From patchwork Fri Apr 9 01:09:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Tan X-Patchwork-Id: 12192699 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DE888C433ED for ; Fri, 9 Apr 2021 01:10:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B5C23610C7 for ; Fri, 9 Apr 2021 01:10:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232996AbhDIBKW (ORCPT ); Thu, 8 Apr 2021 21:10:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51020 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232426AbhDIBKW (ORCPT ); Thu, 8 Apr 2021 21:10:22 -0400 Received: from mail-pl1-x64a.google.com (mail-pl1-x64a.google.com [IPv6:2607:f8b0:4864:20::64a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 544BDC061760 for ; Thu, 8 Apr 2021 18:10:10 -0700 (PDT) Received: by mail-pl1-x64a.google.com with SMTP id p12so1562460plw.0 for ; Thu, 08 Apr 2021 18:10:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=9rG1RVlYLpWnmmm7A7tHfxBU24I6z4/saTdGC4Vl0EM=; b=J3RzSEBFY4qOnsbKLR6UWt7pQMqYKTZzL+Lww7uyd5HeXGzjLE9xZMpEcjHsh2LvmU b1GJ9T+InT2iWZsHOiycy6AYGkDi0MsYAB1lSEkJPV3bYb7YKEkD0DUbSsQ8kSZsOpGb hLBBUJ+v8Ad54HNHg4wwWgJ9xVl765N03sVjo77idkAEsDCdZfOUkPOwoeIQ7hIzEdtX NDrxc5FjrvIZwkYrMN17QuQR2O/dPPhNMVzKOZL5lF7CZcuk4gRoSAxp7XaHGIGcdHsA 8t1TjAoSqayRBqV+XncawkpTC2UXvAqPByqHHQjMScCEozVv6s9h0Terz4emYPY3V6V1 YRrg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=9rG1RVlYLpWnmmm7A7tHfxBU24I6z4/saTdGC4Vl0EM=; b=PSoPe2xZAvvtXQ5T95HmRfy97jYgPFYhLIizqN/QuYcIGw8Qs8ii4L8eAA0BLXkbq0 fqq3JfJxs6EPdPIQwEts3eA8ZNS2XoAR9fd+GDZn6vmSeF3Sq+fYSKV01Bzn74SvYDzE AqszMLMKd5L83rEPsy6onyFEDj71cH26Mjs/K452nXSTkMfAomPDJkufcMptvJPxcclj 8zOzxwKikdc0OqiWDwmlqnx/PVpS5aVAKMCQsjfYTBx8LhRET1eSZchehbBKjkN93w8U oGShj7HcySWw9Ph3yytUtffbagM0cMFHjMhD2py5zdPiLSsFdjO4hmMnxlfWJWnVsxM2 chig== X-Gm-Message-State: AOAM530k8ndxgCeKT22Bz6VlXU4P6cJPG8M1RAm737aLGAUwK0lDPwP0 9qHJvWIkyB5rc4Igxn8BNOpqb+W05OcUJoWKnD1kzgQ3oz8os0EycaS+a0G9MHkP2kWjNlgqurE yF/MgkSFh04KjHSbnrzINswGV5G5bc+XlKiMdkJ/am0RNwDFVq5ky8ZAzPuuHQsEk4WZ2GqlA0/ NS X-Google-Smtp-Source: ABdhPJxl02FoaUR/as8YA+58cNf6//+9zeVpApeSBO1xa9rwAAxKnfGt7P2Udm8FZ0FlPKK3rP8alfWE9MaTSMipwkJi X-Received: from twelve4.c.googlers.com ([fda3:e722:ac3:10:24:72f4:c0a8:437a]) (user=jonathantanmy job=sendgmr) by 2002:a17:903:185:b029:e9:9253:5328 with SMTP id z5-20020a1709030185b02900e992535328mr5418243plg.58.1617930609697; Thu, 08 Apr 2021 18:10:09 -0700 (PDT) Date: Thu, 8 Apr 2021 18:09:58 -0700 In-Reply-To: Message-Id: <86e4ce0e8d9665b1c5a2b30173be4afffe0a0abd.1617929278.git.jonathantanmy@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH 1/6] fetch-pack: buffer object-format with other args From: Jonathan Tan To: git@vger.kernel.org Cc: Jonathan Tan Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org In send_fetch_request(), "object-format" is written directly to the file descriptor, as opposed to the other arguments, which are buffered. Buffer "object-format" as well. "object-format" must be buffered; in particular, it must appear after "command=fetch" in the request. This divergence was introduced in 4b831208bb ("fetch-pack: parse and advertise the object-format capability", 2020-05-27), perhaps as an oversight (the surrounding code at the point of this commit has already been using a request buffer.) Signed-off-by: Jonathan Tan --- fetch-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fetch-pack.c b/fetch-pack.c index 6e68276aa3..2318ebe680 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1251,7 +1251,7 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, if (hash_algo_by_ptr(the_hash_algo) != hash_algo) die(_("mismatched algorithms: client %s; server %s"), the_hash_algo->name, hash_name); - packet_write_fmt(fd_out, "object-format=%s", the_hash_algo->name); + packet_buf_write(&req_buf, "object-format=%s", the_hash_algo->name); } else if (hash_algo_by_ptr(the_hash_algo) != GIT_HASH_SHA1) { die(_("the server does not support algorithm '%s'"), the_hash_algo->name); From patchwork Fri Apr 9 01:09:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Tan X-Patchwork-Id: 12192701 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0E742C433B4 for ; Fri, 9 Apr 2021 01:10:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DDE7F610C7 for ; Fri, 9 Apr 2021 01:10:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233108AbhDIBKZ (ORCPT ); Thu, 8 Apr 2021 21:10:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51034 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232426AbhDIBKY (ORCPT ); Thu, 8 Apr 2021 21:10:24 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 238C8C061760 for ; Thu, 8 Apr 2021 18:10:12 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id g5-20020a17090a7085b02900c0e864bc61so323311pjk.5 for ; Thu, 08 Apr 2021 18:10:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=0p4XllSE8aBFa4fQc7spcXOxtBkighnOA4rj0nIkUxI=; b=HV67n9IhGfXgxC+8kv1tHU704lyESp63uqY/RVP/x/0C1VL8C4Uce7RifA40jQEhuE NOQzaTyk0Kn9v/kTF/ejX38YFp2oVvFH23mu5tNcIjiwv4eE/i6PM5LHFZ9scW9k3H2l 7ugXjyLNYRvrt7UeM+R0TlLq1KkAxuxOXtXX5tzA2UU6dKwiwr2ITvMvg/EQD/3X6UPq V7KVKQ0kLv6Oh9pLDQXBhM7QtuXxSMSd2Eg4gpplpaZeQ31/+0RRJBde1vwB/EhKUj9i 5iWWcW7I4Xhcx8Dzu0mrpXiwUJvnCcL4Qgx0YMn0pDK6gUDXRws1kdHDEp5006yVi8cf DnXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=0p4XllSE8aBFa4fQc7spcXOxtBkighnOA4rj0nIkUxI=; b=JQr+yWUEZR5MnXESiI4YyF5E2qIfjljJDlb2FrTMZA5FqXrgo3+h8WCHpAqAI+Lfex 3GJKCoNaqI7wERatXlXQ0SXSY7GgMTmDo4cqFaQ8JNhNEifWO2a/91+A2i+gmeJ3M67P T+ZICFOjYnGStEQzJOgEfXtY6zfJufuP44h+tEh6/qAl5RZDACtQjWRFCCYNHH395Nw4 EtZJ1Ur6WAe7DqMV8NBkJTSs75CyOC8Rdq0aJtm09RJrncJqateNSAQJqpumc9cUDrxy 7o953mEF58cJ331koYX39wNd9nuV8ZXstJRmUsqzH/weazcMd++iAitaf0sNG9br7TBN iZLw== X-Gm-Message-State: AOAM532rmHZW7IFJW7tRiU9Ev1Yj8imaUW1JEOlxmf9XlqWPoiFJO+DM Etg086C8B2e4ay5UYqbmO8LXA7HhG/mJYnb14+XMQuKftJf6Cg3XcD107c29dYL2wIFvaTt3qKA Gl5YIEtY22WFFdEHm9VyZoqwubuOoGoe3+ex8HCzRUdTLESvFytshQyxybm6XCDSxjfikZ94o+w HL X-Google-Smtp-Source: ABdhPJwmniyFzJCqejmPAEE7zUGWFIQ7DsWbo3NoV4FE3XZX6UWjnGcvaHN80WXtwa4nFkB0RK9/egJLCl22mHMvKJAZ X-Received: from twelve4.c.googlers.com ([fda3:e722:ac3:10:24:72f4:c0a8:437a]) (user=jonathantanmy job=sendgmr) by 2002:a17:902:361:b029:e9:8392:7abd with SMTP id 88-20020a1709020361b02900e983927abdmr7098751pld.8.1617930611586; Thu, 08 Apr 2021 18:10:11 -0700 (PDT) Date: Thu, 8 Apr 2021 18:09:59 -0700 In-Reply-To: Message-Id: <6a9f78df1a3513df04ac3275cd1feccfb6cf87b1.1617929278.git.jonathantanmy@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH 2/6] fetch-pack: refactor process_acks() From: Jonathan Tan To: git@vger.kernel.org Cc: Jonathan Tan Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org A subsequent commit will need part, but not all, of the functionality in process_acks(), so move some of its functionality to its sole caller do_fetch_pack_v2(). As a side effect, the resulting code is also shorter. Signed-off-by: Jonathan Tan --- fetch-pack.c | 70 +++++++++++++++++----------------------------------- 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/fetch-pack.c b/fetch-pack.c index 2318ebe680..9f3901cdba 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1351,35 +1351,11 @@ static int process_section_header(struct packet_reader *reader, return ret; } -enum common_found { - /* - * No commit was found to be possessed by both the client and the - * server, and "ready" was not received. - */ - NO_COMMON_FOUND, - - /* - * At least one commit was found to be possessed by both the client and - * the server, and "ready" was not received. - */ - COMMON_FOUND, - - /* - * "ready" was received, indicating that the server is ready to send - * the packfile without any further negotiation. - */ - READY -}; - -static enum common_found process_acks(struct fetch_negotiator *negotiator, - struct packet_reader *reader, - struct oidset *common) +static int process_ack(struct fetch_negotiator *negotiator, + struct packet_reader *reader, + struct object_id *common_oid, + int *received_ready) { - /* received */ - int received_ready = 0; - int received_ack = 0; - - process_section_header(reader, "acknowledgments", 0); while (packet_reader_read(reader) == PACKET_READ_NORMAL) { const char *arg; @@ -1387,20 +1363,17 @@ static enum common_found process_acks(struct fetch_negotiator *negotiator, continue; if (skip_prefix(reader->line, "ACK ", &arg)) { - struct object_id oid; - received_ack = 1; - if (!get_oid_hex(arg, &oid)) { + if (!get_oid_hex(arg, common_oid)) { struct commit *commit; - oidset_insert(common, &oid); - commit = lookup_commit(the_repository, &oid); + commit = lookup_commit(the_repository, common_oid); if (negotiator) negotiator->ack(negotiator, commit); } - continue; + return 1; } if (!strcmp(reader->line, "ready")) { - received_ready = 1; + *received_ready = 1; continue; } @@ -1418,13 +1391,12 @@ static enum common_found process_acks(struct fetch_negotiator *negotiator, * sent. Therefore, a DELIM is expected if "ready" is sent, and a FLUSH * otherwise. */ - if (received_ready && reader->status != PACKET_READ_DELIM) + if (*received_ready && reader->status != PACKET_READ_DELIM) die(_("expected packfile to be sent after 'ready'")); - if (!received_ready && reader->status != PACKET_READ_FLUSH) + if (!*received_ready && reader->status != PACKET_READ_FLUSH) die(_("expected no other sections to be sent after no 'ready'")); - return received_ready ? READY : - (received_ack ? COMMON_FOUND : NO_COMMON_FOUND); + return 0; } static void receive_shallow_info(struct fetch_pack_args *args, @@ -1573,6 +1545,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, struct fetch_negotiator negotiator_alloc; struct fetch_negotiator *negotiator; int seen_ack = 0; + struct object_id common_oid; + int received_ready = 0; struct string_list packfile_uris = STRING_LIST_INIT_DUP; int i; struct strvec index_pack_args = STRVEC_INIT; @@ -1631,22 +1605,22 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, break; case FETCH_PROCESS_ACKS: /* Process ACKs/NAKs */ - switch (process_acks(negotiator, &reader, &common)) { - case READY: + process_section_header(&reader, "acknowledgments", 0); + while (process_ack(negotiator, &reader, &common_oid, + &received_ready)) { + in_vain = 0; + seen_ack = 1; + oidset_insert(&common, &common_oid); + } + if (received_ready) { /* * Don't check for response delimiter; get_pack() will * read the rest of this response. */ state = FETCH_GET_PACK; - break; - case COMMON_FOUND: - in_vain = 0; - seen_ack = 1; - /* fallthrough */ - case NO_COMMON_FOUND: + } else { do_check_stateless_delimiter(args, &reader); state = FETCH_SEND_REQUEST; - break; } break; case FETCH_GET_PACK: From patchwork Fri Apr 9 01:10:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Tan X-Patchwork-Id: 12192703 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 50CCDC433ED for ; Fri, 9 Apr 2021 01:10:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 09B5B610A7 for ; Fri, 9 Apr 2021 01:10:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233122AbhDIBK1 (ORCPT ); Thu, 8 Apr 2021 21:10:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51048 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232426AbhDIBK0 (ORCPT ); Thu, 8 Apr 2021 21:10:26 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 25B0DC061760 for ; Thu, 8 Apr 2021 18:10:14 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id n13so3739266ybp.14 for ; Thu, 08 Apr 2021 18:10:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=22FfvI2Ld4mCHPq5rjNg63Mu3JTg5FX2CkL3tUrVSbo=; b=nhIGN5Z7CXBMnmeSvPZp+Km3wVv7K6TEOzaoyrL3t1pySgq0HlQiGYdKO0ued5EGQG NRf98a3imqNkQYlc/Ks8KxZ5a/2ZyfWIMn8vLA2vpfQbPO62hyqzosfYXJdH6Dopu0HA cK2MHRtkfeU8W1I9b27p3TrVKQG4fDnMms0xRRiGmjqZ8PG+pv9UMLib9RzLPZ3LgA1O YcY+dhdf59kfoOdZkNkz6DzEQ+SsR8nf0Iqfqx2s5Sx0pQLWwTRbvL1uZroUmwtWrIX2 Yf/vEbSSz0l7npHgYS+2a2xUUwGlE2WYKDRNdpy86JLKCsO1Hk5VSVITKJhHgCwdY+4K C/Dw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=22FfvI2Ld4mCHPq5rjNg63Mu3JTg5FX2CkL3tUrVSbo=; b=KnRhuqKs6Ihcj/XxNeEhmijG4JAFoB+QqYr/HBJiMrCRYA3m9bjvfkEhCjRUXdrTuS LW06uyHKH2e4X1Mjd79HDlKy4bk3CRXNfhQ662QGQs3lPV+Gr7npFR8pYLdVCH3fH2O6 CAmpc1LUAHo5F32PCDQX8YWhaA8j2KhZLRTzk4pxD+OzP6ehBtV+NjcqSfMcBT7rhPr0 +GFiAI5T/AaV15WzMII6XK74vMi5gF8k0DN8NrHnJSUsI8Z6jVzNeYQYvrLuasS1PHl0 3gnTkJG3yHDdlwa3z8B5ZjIL85CRqgFPBnzEoN2SNLtNpyFim8X6BWTLRYvgsu9z7JMK GEcg== X-Gm-Message-State: AOAM532+wBRNtuYWt/TJSoZSjabqlG6nnYv7J3biNYfx4LY+2YA1SR01 dQWfSl6YjhZnA52y6YOdNC7z9LCF4i4KQzCr1P4z4b/GLZbqqZbvwWzg+KmegYwoOWTkmiaEBNU q3KY0GbNASYrzj6OKzPr2SLAXN9ObHPUlS73KfQNcn+7+PDeTfEd4gRt+RzCD4hU8QlPzt/yOfp EM X-Google-Smtp-Source: ABdhPJz2l9OCWwLWmt6Lh8nEVLpH/Zolg5ArB+i2eO91kZZ8RBUqpBGp61w/cDNIjlgsw1a5yBLYpcTBwCQZxUhE2F/m X-Received: from twelve4.c.googlers.com ([fda3:e722:ac3:10:24:72f4:c0a8:437a]) (user=jonathantanmy job=sendgmr) by 2002:a25:9108:: with SMTP id v8mr14839292ybl.460.1617930613225; Thu, 08 Apr 2021 18:10:13 -0700 (PDT) Date: Thu, 8 Apr 2021 18:10:00 -0700 In-Reply-To: Message-Id: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH 3/6] fetch-pack: refactor add_haves() From: Jonathan Tan To: git@vger.kernel.org Cc: Jonathan Tan Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org A subsequent commit will need part, but not all, of the functionality in add_haves(), so move some of its functionality to its sole caller send_fetch_request(). Signed-off-by: Jonathan Tan --- fetch-pack.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/fetch-pack.c b/fetch-pack.c index 9f3901cdba..128ad47d2a 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1195,11 +1195,9 @@ static void add_common(struct strbuf *req_buf, struct oidset *common) } static int add_haves(struct fetch_negotiator *negotiator, - int seen_ack, struct strbuf *req_buf, - int *haves_to_send, int *in_vain) + int *haves_to_send) { - int ret = 0; int haves_added = 0; const struct object_id *oid; @@ -1209,17 +1207,10 @@ static int add_haves(struct fetch_negotiator *negotiator, break; } - *in_vain += haves_added; - if (!haves_added || (seen_ack && *in_vain >= MAX_IN_VAIN)) { - /* Send Done */ - packet_buf_write(req_buf, "done\n"); - ret = 1; - } - /* Increase haves to send on next round */ *haves_to_send = next_flush(1, *haves_to_send); - return ret; + return haves_added; } static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, @@ -1228,7 +1219,8 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, int *haves_to_send, int *in_vain, int sideband_all, int seen_ack) { - int ret = 0; + int haves_added; + int done_sent = 0; const char *hash_name; struct strbuf req_buf = STRBUF_INIT; @@ -1312,9 +1304,13 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, /* Add all of the common commits we've found in previous rounds */ add_common(&req_buf, common); - /* Add initial haves */ - ret = add_haves(negotiator, seen_ack, &req_buf, - haves_to_send, in_vain); + haves_added = add_haves(negotiator, &req_buf, haves_to_send); + *in_vain += haves_added; + if (!haves_added || (seen_ack && *in_vain >= MAX_IN_VAIN)) { + /* Send Done */ + packet_buf_write(&req_buf, "done\n"); + done_sent = 1; + } /* Send request */ packet_buf_flush(&req_buf); @@ -1322,7 +1318,7 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, die_errno(_("unable to write request to remote")); strbuf_release(&req_buf); - return ret; + return done_sent; } /* From patchwork Fri Apr 9 01:10:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Tan X-Patchwork-Id: 12192705 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4944AC433ED for ; Fri, 9 Apr 2021 01:10:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 19F04610C7 for ; Fri, 9 Apr 2021 01:10:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233142AbhDIBK3 (ORCPT ); Thu, 8 Apr 2021 21:10:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51052 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233115AbhDIBK1 (ORCPT ); Thu, 8 Apr 2021 21:10:27 -0400 Received: from mail-qk1-x749.google.com (mail-qk1-x749.google.com [IPv6:2607:f8b0:4864:20::749]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA685C061760 for ; Thu, 8 Apr 2021 18:10:15 -0700 (PDT) Received: by mail-qk1-x749.google.com with SMTP id y22so2384326qkb.23 for ; Thu, 08 Apr 2021 18:10:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=AmiAFUWmc3T1ej5C6alEbnc8klyjc/DyvsLEQJhI0vk=; b=LG3tLN/zNmIypQNQ2wiKg/ZzUEVQJe4cqK0bjnh+seYRGFagKJwGxkVWUlJQM59D69 HPLVurCrutRMRknRGP/eX/eRQM2kPMOYAR1G3V2jKF0d1Ixv3d01HK3DJVLa2023Mk5f poBE3mMadTdthfMa+rMgg61IWlUhD/h7TYaqc8PI0SfYmFPDsNh4Ar00wHdkTzwDhg+b 4GMllCyfMbu4haMEyLNSJxcUaEOgWK8XGqPRjENn8Pxfxrc85FcVQE4KXb/GjX5uSY7Q 9JIeOWOadweUIOJwDaoAwBSGKWRa/DYSQ8zKch2iiIFRXl2voro0/tPrXWbeJnqXqHPa JToQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=AmiAFUWmc3T1ej5C6alEbnc8klyjc/DyvsLEQJhI0vk=; b=cQ74mfcb2gZA61+vQd12xPGFIiGhKSyj/eg1+fJAivTTE4DpxlCNPdFDfRTGAqTncu 51vx7E3fgRvwxutl7U+JaKxQuRyaC/YI/cK1VuQcxyYFodPmDvGsNw2mODjXn7PAJlcV 08BcvoBKKDB5twQ/U9PZ865FiKItI/bfdEhgUkYFAd06m8mMxQkdErybvE6K7WuYj6PU Steg+BzXH+L3t6nEnaFRSrIONL1u0dl+ueEKZeA1AZ7wFAM24DTGQml4mOfdBv1UWHSN pvapiQfdHiRFD9PDGQC27oVTW6925UQ2zW2FD2TuDtU0OWsXIPAt8Vi9hUck5/3D16WZ AIdw== X-Gm-Message-State: AOAM532AjfvSDHPK7JejXmTk5zgafAtlGMlRbbRCtR5iKO82bKiFYibc HRPRohRhydN+UdDmR+qBtEJg+2p8Q/YfnQHuziGa1PaTiI+m6H44wR1TTBXslsSZuf6cynY8oP3 mZw2bAKiwOPK45twtcWADgXT9WsogfnxfcyVJTCH8pWNGufTTEcJ7/VhjAcwPozcnI0nOuhtTFG SR X-Google-Smtp-Source: ABdhPJw87ltKJ3pRidfKZVohk7Lf0LaIHc31bmp1bJVaDM2m5vhmK5rXcjiYb3kY/mVjevcWxgpWkKmDB2fEKmj4KyWF X-Received: from twelve4.c.googlers.com ([fda3:e722:ac3:10:24:72f4:c0a8:437a]) (user=jonathantanmy job=sendgmr) by 2002:a0c:f74d:: with SMTP id e13mr12186703qvo.8.1617930614919; Thu, 08 Apr 2021 18:10:14 -0700 (PDT) Date: Thu, 8 Apr 2021 18:10:01 -0700 In-Reply-To: Message-Id: <7988c106873332ac6e5c2f9dd143cfa1f50e067c.1617929278.git.jonathantanmy@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH 4/6] fetch-pack: refactor command and capability write From: Jonathan Tan To: git@vger.kernel.org Cc: Jonathan Tan Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org A subsequent commit will need this functionality independent of the rest of send_fetch_request(), so put this into its own function. Signed-off-by: Jonathan Tan --- fetch-pack.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/fetch-pack.c b/fetch-pack.c index 128ad47d2a..512fe5450d 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1213,29 +1213,23 @@ static int add_haves(struct fetch_negotiator *negotiator, return haves_added; } -static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, - struct fetch_pack_args *args, - const struct ref *wants, struct oidset *common, - int *haves_to_send, int *in_vain, - int sideband_all, int seen_ack) +static void write_fetch_command_and_capabilities(struct strbuf *req_buf, + const struct string_list *server_options) { - int haves_added; - int done_sent = 0; const char *hash_name; - struct strbuf req_buf = STRBUF_INIT; if (server_supports_v2("fetch", 1)) - packet_buf_write(&req_buf, "command=fetch"); + packet_buf_write(req_buf, "command=fetch"); if (server_supports_v2("agent", 0)) - packet_buf_write(&req_buf, "agent=%s", git_user_agent_sanitized()); + packet_buf_write(req_buf, "agent=%s", git_user_agent_sanitized()); if (advertise_sid && server_supports_v2("session-id", 0)) - packet_buf_write(&req_buf, "session-id=%s", trace2_session_id()); - if (args->server_options && args->server_options->nr && + packet_buf_write(req_buf, "session-id=%s", trace2_session_id()); + if (server_options && server_options->nr && server_supports_v2("server-option", 1)) { int i; - for (i = 0; i < args->server_options->nr; i++) - packet_buf_write(&req_buf, "server-option=%s", - args->server_options->items[i].string); + for (i = 0; i < server_options->nr; i++) + packet_buf_write(req_buf, "server-option=%s", + server_options->items[i].string); } if (server_feature_v2("object-format", &hash_name)) { @@ -1243,13 +1237,26 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, if (hash_algo_by_ptr(the_hash_algo) != hash_algo) die(_("mismatched algorithms: client %s; server %s"), the_hash_algo->name, hash_name); - packet_buf_write(&req_buf, "object-format=%s", the_hash_algo->name); + packet_buf_write(req_buf, "object-format=%s", the_hash_algo->name); } else if (hash_algo_by_ptr(the_hash_algo) != GIT_HASH_SHA1) { die(_("the server does not support algorithm '%s'"), the_hash_algo->name); } + packet_buf_delim(req_buf); +} + +static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, + struct fetch_pack_args *args, + const struct ref *wants, struct oidset *common, + int *haves_to_send, int *in_vain, + int sideband_all, int seen_ack) +{ + int haves_added; + int done_sent = 0; + struct strbuf req_buf = STRBUF_INIT; + + write_fetch_command_and_capabilities(&req_buf, args->server_options); - packet_buf_delim(&req_buf); if (args->use_thin_pack) packet_buf_write(&req_buf, "thin-pack"); if (args->no_progress) From patchwork Fri Apr 9 01:10:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Tan X-Patchwork-Id: 12192707 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.2 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F0510C433ED for ; Fri, 9 Apr 2021 01:10:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C1513610F7 for ; Fri, 9 Apr 2021 01:10:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233153AbhDIBKa (ORCPT ); Thu, 8 Apr 2021 21:10:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51062 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233127AbhDIBK3 (ORCPT ); Thu, 8 Apr 2021 21:10:29 -0400 Received: from mail-pg1-x54a.google.com (mail-pg1-x54a.google.com [IPv6:2607:f8b0:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 545DEC061762 for ; Thu, 8 Apr 2021 18:10:17 -0700 (PDT) Received: by mail-pg1-x54a.google.com with SMTP id j4so2232653pgs.18 for ; Thu, 08 Apr 2021 18:10:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=wmmcB5N9lkvFJV/RgGhqGEH3esfGYwNpq0vOrZg0npU=; b=g9mIe96Mg8sikoekEwgCG8rJR4T7pvHSD0iKGrXHFyaN9yDUkKy58887jo37apPhhn Mx7RqpbGPMx0n3GCz+3KqYDS9V6Qlf3rSt196727uzesAHRRMlNTPFjEDkezNlO7gzqo n/RlQYGY/f2wW9SRgI+9005H5zAbDPtjea1QlXmGiBV0Q6uYuOwB3A/oYtXKm/SWU6mU yo1PTwhbbYH8ZUw5CkO4dkgM09qDZS3BLtF/0sv6FlhFvpBOqqgz8IWZ11OqIs+aj2nE epfLTVnR7zrLbwMdjznkQugCDOrMyPKcHTv9J74sOSuCHghnwRvJuJdVx+UgOwzGvCyc jXhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=wmmcB5N9lkvFJV/RgGhqGEH3esfGYwNpq0vOrZg0npU=; b=rQqH7OFiImMXN7imWPyWMjTgDrriv0OesXFciotwbPYuCfNDjNlxoT/jZtFliTz061 mmIbPIrTjr0yIMb7T93sa+dsZBPJ2RRx2otJVSF58WYEcFzVPH+5xQ60+p/Lg77Er6ln ZGYH5azUHjqik/SVqZk6QpN1CNq0KFqAfZJKD8OyRf1BfArzF/nuRGr7mxAkrRaUIE1q gX8l2dxpvNjcjgY6Zdc2DS+ZGr/2NLoTcWMinxePtEhzwwAqZH20rRe54Gl07pLjZuja EmFRguLA+lhi+mdO0XekwT7rz5yttYWdk+P+8BTA+tDdrKNXonU733VMMvbo0mtuVt+5 54Iw== X-Gm-Message-State: AOAM531rX1Ao8mqrMNx57Vp2AU59ONDIb0MwSHOrIuZHcEhBRZAFhcnh UlW8etlXKgvPONuz8UcNQmiqRTlTov0MNlBmEZzstL8RPut1j6FxYbchHoejcu4vdH/P1C3OoET Bi8msH+g9/0kL9r21RX4Cl1RgYRbKeWqw654lDrtYHwUE7f8k9PSaVSj6qKYVareIwqApZsCipH qh X-Google-Smtp-Source: ABdhPJz8jmLrOVLWjW1Ui2PqQFVtuIP0XekrPWQx/2UMteC7Iv98Yhr0p3IKsNYKYV9ihKfEZ6FNYw4sNrQDhEtooQuz X-Received: from twelve4.c.googlers.com ([fda3:e722:ac3:10:24:72f4:c0a8:437a]) (user=jonathantanmy job=sendgmr) by 2002:a62:7ac8:0:b029:246:e38c:58ac with SMTP id v191-20020a627ac80000b0290246e38c58acmr580026pfc.10.1617930616759; Thu, 08 Apr 2021 18:10:16 -0700 (PDT) Date: Thu, 8 Apr 2021 18:10:02 -0700 In-Reply-To: Message-Id: <4696c8e901808853d17af10d5a6d95cd4711c6d5.1617929278.git.jonathantanmy@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH 5/6] fetch: teach independent negotiation (no packfile) From: Jonathan Tan To: git@vger.kernel.org Cc: Jonathan Tan Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Currently, the packfile negotiation step within a Git fetch cannot be done independent of sending the packfile, even though there is at least one application wherein this is useful. Therefore, make it possible for this negotiation step to be done independently. A subsequent commit will use this for one such application - push negotiation. This feature is for protocol v2 only. (An implementation for protocol v0 would require a separate implementation in the fetch, transport, and transport helper code.) In the protocol, the main hindrance towards independent negotiation is that the server can unilaterally decide to send the packfile. This is solved by a "wait-for-done" argument: the server will then wait for the client to say "done". In practice, the client will never say it; instead it will cease requests once it is satisfied. In the client, the main change lies in the transport and transport helper code. fetch_refs_via_pack() performs everything needed - protocol version and capability checks, and the negotiation itself. There are 2 code paths that do not go through fetch_refs_via_pack() that needed to be individually excluded: the bundle transport (excluded through requiring smart_options, which the bundle transport doesn't support) and transport helpers that do not support takeover. Fortunately, none of these support protocol v2. Signed-off-by: Jonathan Tan --- Documentation/technical/protocol-v2.txt | 8 +++ builtin/fetch.c | 27 +++++++- fetch-pack.c | 89 +++++++++++++++++++++++-- fetch-pack.h | 11 +++ object.h | 2 +- t/t5701-git-serve.sh | 2 +- t/t5702-protocol-v2.sh | 89 +++++++++++++++++++++++++ transport-helper.c | 10 +++ transport.c | 30 +++++++-- transport.h | 6 ++ upload-pack.c | 18 +++-- 11 files changed, 275 insertions(+), 17 deletions(-) diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt index a7c806a73e..0b371d8de4 100644 --- a/Documentation/technical/protocol-v2.txt +++ b/Documentation/technical/protocol-v2.txt @@ -346,6 +346,14 @@ explained below. client should download from all given URIs. Currently, the protocols supported are "http" and "https". +If the 'wait-for-done' feature is advertised, the following argument +can be included in the client's request. + + wait-for-done + Indicates to the server that it should never send "ready", but + should wait for the client to say "done" before sending the + packfile. + The response of `fetch` is broken into a number of sections separated by delimiter packets (0001), with each section beginning with its section header. Most sections are sent only when the packfile is sent. diff --git a/builtin/fetch.c b/builtin/fetch.c index 0b90de87c7..597973848a 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -82,6 +82,7 @@ static struct string_list server_options = STRING_LIST_INIT_DUP; static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP; static int fetch_write_commit_graph = -1; static int stdin_refspecs = 0; +static int negotiate_only; static int git_fetch_config(const char *k, const char *v, void *cb) { @@ -202,6 +203,8 @@ static struct option builtin_fetch_options[] = { TRANSPORT_FAMILY_IPV6), OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"), N_("report that we have only objects reachable from this object")), + OPT_BOOL(0, "negotiate-only", &negotiate_only, + N_("do not fetch a packfile; instead, print ancestors of negotiation tips")), OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options), OPT_BOOL(0, "auto-maintenance", &enable_auto_gc, N_("run 'maintenance --auto' after fetching")), @@ -1986,7 +1989,29 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) } } - if (remote) { + if (negotiate_only) { + struct oidset acked_commits = OIDSET_INIT; + struct oidset_iter iter; + const struct object_id *oid; + + if (!remote) + die(_("Must supply remote when using --negotiate-only")); + gtransport = prepare_transport(remote, 1); + if (gtransport->smart_options) { + gtransport->smart_options->acked_commits = &acked_commits; + } else { + warning(_("Protocol does not support --negotiate-only, exiting.")); + return 1; + } + if (server_options.nr) + gtransport->server_options = &server_options; + result = transport_fetch_refs(gtransport, NULL); + + oidset_iter_init(&acked_commits, &iter); + while ((oid = oidset_iter_next(&iter))) + printf("%s\n", oid_to_hex(oid)); + oidset_clear(&acked_commits); + } else if (remote) { if (filter_options.choice || has_promisor_remote()) fetch_one_setup_partial(remote); result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs); diff --git a/fetch-pack.c b/fetch-pack.c index 512fe5450d..63054e2fc8 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -23,6 +23,7 @@ #include "fetch-negotiator.h" #include "fsck.h" #include "shallow.h" +#include "commit-reach.h" static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; @@ -45,6 +46,8 @@ static struct string_list uri_protocols = STRING_LIST_INIT_DUP; /* Remember to update object flag allocation in object.h */ #define COMPLETE (1U << 0) #define ALTERNATE (1U << 1) +#define COMMON (1U << 6) +#define REACH_SCRATCH (1U << 7) /* * After sending this many "have"s if we do not get any new ACK , we @@ -1523,10 +1526,10 @@ enum fetch_state { FETCH_DONE, }; -static void do_check_stateless_delimiter(const struct fetch_pack_args *args, +static void do_check_stateless_delimiter(int stateless_rpc, struct packet_reader *reader) { - check_stateless_delimiter(args->stateless_rpc, reader, + check_stateless_delimiter(stateless_rpc, reader, _("git fetch-pack: expected response end packet")); } @@ -1622,7 +1625,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, */ state = FETCH_GET_PACK; } else { - do_check_stateless_delimiter(args, &reader); + do_check_stateless_delimiter(args->stateless_rpc, &reader); state = FETCH_SEND_REQUEST; } break; @@ -1645,7 +1648,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, packfile_uris.nr ? &index_pack_args : NULL, sought, nr_sought, &fsck_options.gitmodules_found)) die(_("git fetch-pack: fetch failed.")); - do_check_stateless_delimiter(args, &reader); + do_check_stateless_delimiter(args->stateless_rpc, &reader); state = FETCH_DONE; break; @@ -1962,6 +1965,84 @@ struct ref *fetch_pack(struct fetch_pack_args *args, return ref_cpy; } +static int add_to_object_array(const struct object_id *oid, void *data) +{ + struct object_array *a = data; + + add_object_array(parse_object(the_repository, oid), "", a); + return 0; +} + +void negotiate_using_fetch(const struct oid_array *negotiation_tips, + const struct string_list *server_options, + int stateless_rpc, + int fd[], + struct oidset *acked_commits) +{ + struct fetch_negotiator negotiator; + struct packet_reader reader; + struct object_array nt_object_array = OBJECT_ARRAY_INIT; + struct strbuf req_buf = STRBUF_INIT; + int haves_to_send = INITIAL_FLUSH; + int in_vain = 0; + int seen_ack = 0; + int last_iteration = 0; + + fetch_negotiator_init(the_repository, &negotiator); + mark_tips(&negotiator, negotiation_tips); + + packet_reader_init(&reader, fd[0], NULL, 0, + PACKET_READ_CHOMP_NEWLINE | + PACKET_READ_DIE_ON_ERR_PACKET); + + oid_array_for_each((struct oid_array *) negotiation_tips, + add_to_object_array, + &nt_object_array); + + while (!last_iteration) { + int haves_added; + struct object_id common_oid; + int received_ready = 0; + + strbuf_reset(&req_buf); + write_fetch_command_and_capabilities(&req_buf, server_options); + + packet_buf_write(&req_buf, "wait-for-done"); + + haves_added = add_haves(&negotiator, &req_buf, &haves_to_send); + in_vain += haves_added; + if (!haves_added || (seen_ack && in_vain >= MAX_IN_VAIN)) + last_iteration = 1; + + /* Send request */ + packet_buf_flush(&req_buf); + if (write_in_full(fd[1], req_buf.buf, req_buf.len) < 0) + die_errno(_("unable to write request to remote")); + + /* Process ACKs/NAKs */ + process_section_header(&reader, "acknowledgments", 0); + while (process_ack(&negotiator, &reader, &common_oid, + &received_ready)) { + struct commit *commit = lookup_commit(the_repository, + &common_oid); + if (commit) + commit->object.flags |= COMMON; + in_vain = 0; + seen_ack = 1; + oidset_insert(acked_commits, &common_oid); + } + if (received_ready) + die(_("unexpected 'ready' from remote")); + else + do_check_stateless_delimiter(stateless_rpc, &reader); + if (can_all_from_reach_with_flag(&nt_object_array, COMMON, + REACH_SCRATCH, 0, + GENERATION_NUMBER_ZERO)) + last_iteration = 1; + } + strbuf_release(&req_buf); +} + int report_unmatched_refs(struct ref **sought, int nr_sought) { int i, ret = 0; diff --git a/fetch-pack.h b/fetch-pack.h index f114d72775..7c8f49aca7 100644 --- a/fetch-pack.h +++ b/fetch-pack.h @@ -5,6 +5,7 @@ #include "run-command.h" #include "protocol.h" #include "list-objects-filter-options.h" +#include "oidset.h" struct oid_array; @@ -81,6 +82,16 @@ struct ref *fetch_pack(struct fetch_pack_args *args, struct string_list *pack_lockfiles, enum protocol_version version); +/* + * Execute the --negotiate-only mode of "git fetch", adding all known common + * commits to acked_commits. + */ +void negotiate_using_fetch(const struct oid_array *negotiation_tips, + const struct string_list *server_options, + int stateless_rpc, + int fd[], + struct oidset *acked_commits); + /* * Print an appropriate error message for each sought ref that wasn't * matched. Return 0 if all sought refs were matched, otherwise 1. diff --git a/object.h b/object.h index 59daadce21..4806fa8e66 100644 --- a/object.h +++ b/object.h @@ -60,7 +60,7 @@ struct object_array { /* * object flag allocation: * revision.h: 0---------10 15 23------26 - * fetch-pack.c: 01 + * fetch-pack.c: 01 67 * negotiator/default.c: 2--5 * walker.c: 0-2 * upload-pack.c: 4 11-----14 16-----19 diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh index 509f379d49..f03bb04803 100755 --- a/t/t5701-git-serve.sh +++ b/t/t5701-git-serve.sh @@ -16,7 +16,7 @@ test_expect_success 'test capability advertisement' ' version 2 agent=git/$(git version | cut -d" " -f3) ls-refs=unborn - fetch=shallow + fetch=shallow wait-for-done server-option object-format=$(test_oid algo) 0000 diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh index 2e1243ca40..5d91f067d0 100755 --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@ -585,6 +585,49 @@ test_expect_success 'deepen-relative' ' test_cmp expected actual ' +setup_negotiate_only () { + SERVER="$1" + URI="$2" + + rm -rf "$SERVER" client + + git init "$SERVER" + test_commit -C "$SERVER" one + test_commit -C "$SERVER" two + + git clone "$URI" client + test_commit -C client three +} + +test_expect_success 'file:// --negotiate-only' ' + SERVER="server" && + URI="file://$(pwd)/server" && + + setup_negotiate_only "$SERVER" "$URI" && + + git -C client fetch \ + --no-tags \ + --negotiate-only \ + --negotiation-tip=$(git -C client rev-parse HEAD) \ + origin >out && + COMMON=$(git -C "$SERVER" rev-parse two) && + grep "$COMMON" out +' + +test_expect_success 'file:// --negotiate-only with protocol v0' ' + SERVER="server" && + URI="file://$(pwd)/server" && + + setup_negotiate_only "$SERVER" "$URI" && + + test_must_fail git -c protocol.version=0 -C client fetch \ + --no-tags \ + --negotiate-only \ + --negotiation-tip=$(git -C client rev-parse HEAD) \ + origin 2>err && + test_i18ngrep "negotiate-only requires protocol v2" err +' + # Test protocol v2 with 'http://' transport # . "$TEST_DIRECTORY"/lib-httpd.sh @@ -1035,6 +1078,52 @@ test_expect_success 'packfile-uri with transfer.fsckobjects fails when .gitmodul test_i18ngrep "disallowed submodule name" err ' +test_expect_success 'http:// --negotiate-only' ' + SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" && + URI="$HTTPD_URL/smart/server" && + + setup_negotiate_only "$SERVER" "$URI" && + + git -C client fetch \ + --no-tags \ + --negotiate-only \ + --negotiation-tip=$(git -C client rev-parse HEAD) \ + origin >out && + COMMON=$(git -C "$SERVER" rev-parse two) && + grep "$COMMON" out +' + +test_expect_success 'http:// --negotiate-only without wait-for-done support' ' + SERVER="server" && + URI="$HTTPD_URL/one_time_perl/server" && + + setup_negotiate_only "$SERVER" "$URI" && + + echo "s/ wait-for-done/ xxxx-xxx-xxxx/" \ + >"$HTTPD_ROOT_PATH/one-time-perl" && + + test_must_fail git -C client fetch \ + --no-tags \ + --negotiate-only \ + --negotiation-tip=$(git -C client rev-parse HEAD) \ + origin 2>err && + test_i18ngrep "server does not support wait-for-done" err +' + +test_expect_success 'http:// --negotiate-only with protocol v0' ' + SERVER="$HTTPD_DOCUMENT_ROOT_PATH/server" && + URI="$HTTPD_URL/smart/server" && + + setup_negotiate_only "$SERVER" "$URI" && + + test_must_fail git -c protocol.version=0 -C client fetch \ + --no-tags \ + --negotiate-only \ + --negotiation-tip=$(git -C client rev-parse HEAD) \ + origin 2>err && + test_i18ngrep "negotiate-only requires protocol v2" err +' + # DO NOT add non-httpd-specific tests here, because the last part of this # test script is only executed when httpd is available and enabled. diff --git a/transport-helper.c b/transport-helper.c index 4cd76366fa..4be035edb8 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -684,6 +684,16 @@ static int fetch(struct transport *transport, return transport->vtable->fetch(transport, nr_heads, to_fetch); } + /* + * If we reach here, then the server, the client, and/or the transport + * helper does not support protocol v2. --negotiate-only requires + * protocol v2. + */ + if (data->transport_options.acked_commits) { + warning(_("--negotiate-only requires protocol v2")); + return -1; + } + if (!data->get_refs_list_called) get_refs_list_using_list(transport, 0); diff --git a/transport.c b/transport.c index ef66e73090..80caeaa72f 100644 --- a/transport.c +++ b/transport.c @@ -392,16 +392,29 @@ static int fetch_refs_via_pack(struct transport *transport, else if (data->version <= protocol_v1) die_if_server_options(transport); + if (data->options.acked_commits) { + if (data->version < protocol_v2) { + warning(_("--negotiate-only requires protocol v2")); + ret = -1; + } else if (!server_supports_feature("fetch", "wait-for-done", 0)) { + warning(_("server does not support wait-for-done")); + ret = -1; + } else { + negotiate_using_fetch(data->options.negotiation_tips, + transport->server_options, + transport->stateless_rpc, + data->fd, + data->options.acked_commits); + ret = 0; + } + goto cleanup; + } + refs = fetch_pack(&args, data->fd, refs_tmp ? refs_tmp : transport->remote_refs, to_fetch, nr_heads, &data->shallow, &transport->pack_lockfiles, data->version); - close(data->fd[0]); - close(data->fd[1]); - if (finish_connect(data->conn)) - ret = -1; - data->conn = NULL; data->got_remote_heads = 0; data->options.self_contained_and_connected = args.self_contained_and_connected; @@ -412,6 +425,13 @@ static int fetch_refs_via_pack(struct transport *transport, if (report_unmatched_refs(to_fetch, nr_heads)) ret = -1; +cleanup: + close(data->fd[0]); + close(data->fd[1]); + if (finish_connect(data->conn)) + ret = -1; + data->conn = NULL; + free_refs(refs_tmp); free_refs(refs); return ret; diff --git a/transport.h b/transport.h index 4d5db0a7f2..b8b3d42e62 100644 --- a/transport.h +++ b/transport.h @@ -47,6 +47,12 @@ struct git_transport_options { * transport_set_option(). */ struct oid_array *negotiation_tips; + + /* + * If set, whenever transport_fetch_refs() is called, add known common + * commits to this oidset instead of fetching any packfiles. + */ + struct oidset *acked_commits; }; enum transport_family { diff --git a/upload-pack.c b/upload-pack.c index e19583ae0f..b432ef0119 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -103,6 +103,7 @@ struct upload_pack_data { unsigned use_ofs_delta : 1; unsigned no_progress : 1; unsigned use_include_tag : 1; + unsigned wait_for_done : 1; unsigned allow_filter : 1; unsigned allow_filter_fallback : 1; unsigned long tree_filter_max_depth; @@ -1496,6 +1497,10 @@ static void process_args(struct packet_reader *request, data->done = 1; continue; } + if (!strcmp(arg, "wait-for-done")) { + data->wait_for_done = 1; + continue; + } /* Shallow related arguments */ if (process_shallow(arg, &data->shallows)) @@ -1578,7 +1583,7 @@ static int send_acks(struct upload_pack_data *data, struct oid_array *acks) oid_to_hex(&acks->oid[i])); } - if (ok_to_give_up(data)) { + if (!data->wait_for_done && ok_to_give_up(data)) { /* Send Ready */ packet_writer_write(&data->writer, "ready\n"); return 1; @@ -1668,10 +1673,13 @@ int upload_pack_v2(struct repository *r, struct strvec *keys, case FETCH_PROCESS_ARGS: process_args(request, &data); - if (!data.want_obj.nr) { + if (!data.want_obj.nr && !data.wait_for_done) { /* - * Request didn't contain any 'want' lines, - * guess they didn't want anything. + * Request didn't contain any 'want' lines (and + * the request does not contain + * "wait-for-done", in which it is reasonable + * to just send 'have's without 'want's); guess + * they didn't want anything. */ state = FETCH_DONE; } else if (data.haves.nr) { @@ -1723,7 +1731,7 @@ int upload_pack_advertise(struct repository *r, int allow_sideband_all_value; char *str = NULL; - strbuf_addstr(value, "shallow"); + strbuf_addstr(value, "shallow wait-for-done"); if (!repo_config_get_bool(the_repository, "uploadpack.allowfilter", From patchwork Fri Apr 9 01:10:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Tan X-Patchwork-Id: 12192709 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-26.2 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 65788C433B4 for ; Fri, 9 Apr 2021 01:10:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4364D610A7 for ; Fri, 9 Apr 2021 01:10:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233158AbhDIBKd (ORCPT ); Thu, 8 Apr 2021 21:10:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51072 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233149AbhDIBKb (ORCPT ); Thu, 8 Apr 2021 21:10:31 -0400 Received: from mail-pl1-x64a.google.com (mail-pl1-x64a.google.com [IPv6:2607:f8b0:4864:20::64a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3D581C061760 for ; Thu, 8 Apr 2021 18:10:19 -0700 (PDT) Received: by mail-pl1-x64a.google.com with SMTP id t18so1554207plr.15 for ; Thu, 08 Apr 2021 18:10:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=lzoAv2PYg1zFTeOc2VKgtiK7aJuItGE4oFKiAPWaFSE=; b=BTE2J/Z9I85ODfTt9gU1wV+YPZa3JbdN8iEdoEe5P9PKHmOKl57/GRl6vjWU6synVW wLIPIg4JpxPmJyGBYh/Ses9E8RjUSp7YKXE8b03nYoaqjWuHkqsh4oaf2aWfoVLde+tC 42iHHMOReJ0ZBct3NYBq5yHBBzOVH9iDGq+FmGBo7/+E0cVleZ7lcEpXYf1GCFMPsUxb 1wewCw2ZkV36OlX/KQoyRcIEu+3idEjtTSFQTVnew5t62ubv/bsHgLFxuX6seHtdLCfW DiiHaecSyLWHgaYegJQtjZYhYZLZurxv4ZnyWPuaJse8my4xH5BZC6VpI2AqmndBUqU+ 7jgQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=lzoAv2PYg1zFTeOc2VKgtiK7aJuItGE4oFKiAPWaFSE=; b=SC1QTysxxki94RZO3OwNzwdG+VEY4RYi8EZ2ih9mj5aPbR7R9k/PN8XE4/7u3uinQb Jx+lnFebmqW0sU+eMBTXjKyFszMY+7xhSzwQwRxtXzE8p/PkaJxNbKiVSUoEuLny/U/n nHvNCVJPADK+dh7utobFZgDSnJ4v/DXuvFFXxgtvLdANwKXAXQPQDRo4786NzFx6pLtr 2/1eISUOwhKaEbMy6Gcg2O3K1voKu1GiHb4LPtM41ezQ+tr2IY57ECLD1sKMZQNkuZ9j XM/1ZnvQ7oRWKOounKRy08m3elg+8WQI/169eMSksOKamt0qQFc/i2LwFnCJ6DC6Aw9A EyOg== X-Gm-Message-State: AOAM533Tnt4N8872wk4QOdVf0JcxofncK4FH/Rt/2rGNGTPdTIAw3AZK TvHJbejSmCxHU3MOtIUE3BG4fNkZbKWZZ8Wn0ckqUoh9t0qK2BVjzyd8D/3FA7sGspAZeYyEwMP FyQA7XLuFH1oxHjumaaghhU4j8TCNEQTaakyxIXg7DhOZLQ4NC8mCsVp2eENUGBj0D21WoFjYXL d0 X-Google-Smtp-Source: ABdhPJyZ79x656Xx04ahZzRkYGP4CqMPkU4Lup8e0I2IboN1b7k1jTzqaoLyAaims1gKUo3lX/9v1i7Qh//FrB8ud5kD X-Received: from twelve4.c.googlers.com ([fda3:e722:ac3:10:24:72f4:c0a8:437a]) (user=jonathantanmy job=sendgmr) by 2002:a17:90a:e00c:: with SMTP id u12mr11187520pjy.133.1617930618578; Thu, 08 Apr 2021 18:10:18 -0700 (PDT) Date: Thu, 8 Apr 2021 18:10:03 -0700 In-Reply-To: Message-Id: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH 6/6] send-pack: support push negotiation From: Jonathan Tan To: git@vger.kernel.org Cc: Jonathan Tan Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Teach Git the push.negotiate config variable. Signed-off-by: Jonathan Tan --- Documentation/config/push.txt | 7 ++++ send-pack.c | 61 ++++++++++++++++++++++++++++++++--- t/t5516-fetch-push.sh | 35 ++++++++++++++++++++ 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/Documentation/config/push.txt b/Documentation/config/push.txt index 21b256e0a4..f2667b2689 100644 --- a/Documentation/config/push.txt +++ b/Documentation/config/push.txt @@ -120,3 +120,10 @@ push.useForceIfIncludes:: `--force-if-includes` as an option to linkgit:git-push[1] in the command line. Adding `--no-force-if-includes` at the time of push overrides this configuration setting. + +push.negotiate:: + If set to "true", attempt to reduce the size of the packfile + sent by rounds of negotiation in which the client and the + server attempt to find commits in common. If "false", Git will + rely solely on the server's ref advertisement to find commits + in common. diff --git a/send-pack.c b/send-pack.c index 5f215b13c7..9cb9f71650 100644 --- a/send-pack.c +++ b/send-pack.c @@ -56,7 +56,9 @@ static void feed_object(const struct object_id *oid, FILE *fh, int negative) /* * Make a pack stream and spit it out into file descriptor fd */ -static int pack_objects(int fd, struct ref *refs, struct oid_array *extra, struct send_pack_args *args) +static int pack_objects(int fd, struct ref *refs, struct oid_array *advertised, + struct oid_array *negotiated, + struct send_pack_args *args) { /* * The child becomes pack-objects --revs; we feed @@ -94,8 +96,10 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *extra, struc * parameters by writing to the pipe. */ po_in = xfdopen(po.in, "w"); - for (i = 0; i < extra->nr; i++) - feed_object(&extra->oid[i], po_in, 1); + for (i = 0; i < advertised->nr; i++) + feed_object(&advertised->oid[i], po_in, 1); + for (i = 0; i < negotiated->nr; i++) + feed_object(&negotiated->oid[i], po_in, 1); while (refs) { if (!is_null_oid(&refs->old_oid)) @@ -409,11 +413,55 @@ static void reject_invalid_nonce(const char *nonce, int len) } } +static void get_commons_through_negotiation(const char *url, + const struct ref *remote_refs, + struct oid_array *commons) +{ + struct child_process child = CHILD_PROCESS_INIT; + const struct ref *ref; + int len = the_hash_algo->hexsz + 1; /* hash + NL */ + + child.git_cmd = 1; + child.no_stdin = 1; + child.out = -1; + strvec_pushl(&child.args, "fetch", "--negotiate-only", NULL); + for (ref = remote_refs; ref; ref = ref->next) + strvec_pushf(&child.args, "--negotiation-tip=%s", oid_to_hex(&ref->new_oid)); + strvec_push(&child.args, url); + + if (start_command(&child)) + die(_("send-pack: unable to fork off fetch subprocess")); + + do { + char hex_hash[GIT_MAX_HEXSZ + 1]; + int read_len = read_in_full(child.out, hex_hash, len); + struct object_id oid; + const char *end; + + if (!read_len) + break; + if (read_len != len) + die("invalid length read %d", read_len); + if (parse_oid_hex(hex_hash, &oid, &end) || *end != '\n') + die("invalid hash"); + oid_array_append(commons, &oid); + } while (1); + + if (finish_command(&child)) { + /* + * The information that push negotiation provides is useful but + * not mandatory. + */ + warning(_("push negotiation failed; proceeding anyway with push")); + } +} + int send_pack(struct send_pack_args *args, int fd[], struct child_process *conn, struct ref *remote_refs, struct oid_array *extra_have) { + struct oid_array commons = OID_ARRAY_INIT; int in = fd[0]; int out = fd[1]; struct strbuf req_buf = STRBUF_INIT; @@ -426,6 +474,7 @@ int send_pack(struct send_pack_args *args, int quiet_supported = 0; int agent_supported = 0; int advertise_sid = 0; + int push_negotiate = 0; int use_atomic = 0; int atomic_supported = 0; int use_push_options = 0; @@ -437,6 +486,10 @@ int send_pack(struct send_pack_args *args, const char *push_cert_nonce = NULL; struct packet_reader reader; + git_config_get_bool("push.negotiate", &push_negotiate); + if (push_negotiate) + get_commons_through_negotiation(args->url, remote_refs, &commons); + git_config_get_bool("transfer.advertisesid", &advertise_sid); /* Does the other end support the reporting? */ @@ -625,7 +678,7 @@ int send_pack(struct send_pack_args *args, PACKET_READ_DIE_ON_ERR_PACKET); if (need_pack_data && cmds_sent) { - if (pack_objects(out, remote_refs, extra_have, args) < 0) { + if (pack_objects(out, remote_refs, extra_have, &commons, args) < 0) { if (args->stateless_rpc) close(out); if (git_connection_is_socket(conn)) diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index f11742ed59..62fb9074a2 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -191,6 +191,41 @@ test_expect_success 'fetch with pushInsteadOf (should not rewrite)' ' ) ' +grep_wrote () { + object_count=$1 + file_name=$2 + grep 'write_pack_file/wrote.*"value":"'$1'"' $2 +} + +test_expect_success 'push with negotiation' ' + # Without negotiation + mk_empty testrepo && + git push testrepo $the_first_commit:refs/remotes/origin/first_commit && + git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit && + echo now pushing without negotiation && + GIT_TRACE2_EVENT="$(pwd)/event" git push testrepo refs/heads/main:refs/remotes/origin/main && + grep_wrote 5 event && # 2 commits, 2 trees, 1 blob + + # Same commands, but with negotiation + rm event && + mk_empty testrepo && + git push testrepo $the_first_commit:refs/remotes/origin/first_commit && + git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit && + GIT_TRACE2_EVENT="$(pwd)/event" git -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main && + grep_wrote 2 event # 1 commit, 1 tree +' + +test_expect_success 'push with negotiation proceeds anyway even if negotiation fails' ' + rm event && + mk_empty testrepo && + git push testrepo $the_first_commit:refs/remotes/origin/first_commit && + git -C testrepo config receive.hideRefs refs/remotes/origin/first_commit && + GIT_TRACE_PACKET="$(pwd)/trace" GIT_TEST_PROTOCOL_VERSION=0 GIT_TRACE2_EVENT="$(pwd)/event" \ + git -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err && + grep_wrote 5 event && # 2 commits, 2 trees, 1 blob + test_i18ngrep "push negotiation failed" err +' + test_expect_success 'push without wildcard' ' mk_empty testrepo &&