From patchwork Wed Jul 24 14:49:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Toon Claes X-Patchwork-Id: 13741056 Received: from out-174.mta0.migadu.com (out-174.mta0.migadu.com [91.218.175.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5053B15B98E for ; Wed, 24 Jul 2024 14:50:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721832644; cv=none; b=qpX41GR6IfeHv1PsX2NITym3AVBM3g0coPmW57Gl195ES2xT1teyyVfffLGkri9OxTNhDlLqYa7+OAN4oSDzRBSfrSwQFk4dPOA7slyY594xdNSoE5cgxBmXl5/Gh2L17QRQrzPFF+vQ9oZ8Rnve+My5yVQH9S1yhWt+b+ZaeoU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721832644; c=relaxed/simple; bh=EIJ4VJ/DET5fUrXx9pArfLB/ubqxqHlZM/EKHzizfKM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VARj5rHA7FE98T4tMd3mbDQSex0PXYLO8kmHjnhwtMIG6v1qvdtGOroht75VvwVsg3R42VOECM7Hl2XHVncG0WrYiFlfFeBOY96xjY3YqBH5r/3lMy0H/xrvgFW7hWSo2x2CPW4qO+STFIF0MiGvXg9rMgs4gJ77D3FRNdA9qQ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=iotcl.com; spf=fail smtp.mailfrom=iotcl.com; dkim=pass (1024-bit key) header.d=iotcl.com header.i=@iotcl.com header.b=wfq5ZLLJ; arc=none smtp.client-ip=91.218.175.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=iotcl.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=iotcl.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iotcl.com header.i=@iotcl.com header.b="wfq5ZLLJ" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iotcl.com; s=key1; t=1721832639; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=J8a7/4lFL09MDGArufZsv3GfVpnMXCl8SjrOVi5tGmE=; b=wfq5ZLLJGwKVoIUPRl+Mp1SZap+G2Zrwnz2kZYF44EpiYHpsssQTjh67JOujz6Q8ztmlG4 EcExwcwxCsCkao4F8i5QvY/qK36TGpi5WM871nRrq0AYonnuTkh/+nyDYgQJ5cRbHdDUIy lLPU2/hxzIcqR9prDIFcys27ZxwTMpg= From: Toon Claes To: git@vger.kernel.org Cc: gitster@pobox.com, Toon Claes Subject: [PATCH v2 1/3] clone: remove double bundle list clear code Date: Wed, 24 Jul 2024 16:49:55 +0200 Message-ID: <20240724144957.3033840-2-toon@iotcl.com> In-Reply-To: <20240724144957.3033840-1-toon@iotcl.com> References: <20240722080705.2614195-1-toon@iotcl.com> <20240724144957.3033840-1-toon@iotcl.com> Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT The bundle list transport->bundles is filled by transport_get_remote_bundle_uri(). Only when the list is not used, it is cleared right away by calling clear_bundle_list(). This looks like we leak memory allocated for the list when transport->bundles *is* used. But in fact, transport->bundles is cleaned up in transport_disconnect() near the end of cmd_clone(). Remove the double clean up of transport->bundles, and depend solely on transport_disconnect() to take care of it. Also add a test case that hits this code, but due to other leaks we cannot mark it as leak-free. Signed-off-by: Toon Claes --- builtin/clone.c | 3 --- t/t5558-clone-bundle-uri.sh | 28 +++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) -- 2.45.2 diff --git a/builtin/clone.c b/builtin/clone.c index af6017d41a..aa507395a0 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -1419,9 +1419,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) else if (fetch_bundle_list(the_repository, transport->bundles)) warning(_("failed to fetch advertised bundles")); - } else { - clear_bundle_list(transport->bundles); - FREE_AND_NULL(transport->bundles); } } diff --git a/t/t5558-clone-bundle-uri.sh b/t/t5558-clone-bundle-uri.sh index cd05321e17..2d6e690fbe 100755 --- a/t/t5558-clone-bundle-uri.sh +++ b/t/t5558-clone-bundle-uri.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='test fetching bundles with --bundle-uri' +test_description='test clone with use of bundle-uri' . ./test-lib.sh . "$TEST_DIRECTORY"/lib-bundle.sh @@ -438,6 +438,32 @@ test_expect_success 'negotiation: bundle list with all wanted commits' ' test_grep ! "clone> want " trace-packet.txt ' +test_expect_success 'bundles advertised by the server' ' + test_when_finished rm -f trace*.txt && + git clone clone-from clone-advertiser && + git -C clone-advertiser config uploadpack.advertiseBundleURIs true && + git -C clone-advertiser config bundle.version 1 && + git -C clone-advertiser config bundle.mode all && + git -C clone-advertiser config bundle.bundle-1.uri "file://$(pwd)/clone-from/bundle-1.bundle" && + git -C clone-advertiser config bundle.bundle-2.uri "file://$(pwd)/clone-from/bundle-2.bundle" && + git -C clone-advertiser config bundle.bundle-3.uri "file://$(pwd)/clone-from/bundle-3.bundle" && + git -C clone-advertiser config bundle.bundle-4.uri "file://$(pwd)/clone-from/bundle-4.bundle" && + + GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \ + git -c transfer.bundleURI=true clone clone-advertiser clone-advertised && + git -C clone-advertised for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/merge + refs/bundles/right + EOF + test_cmp expect actual && + # We already have all needed commits so no "want" needed. + test_grep ! "clone> want " trace-packet.txt +' + ######################################################################### # HTTP tests begin here From patchwork Wed Jul 24 14:49:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Toon Claes X-Patchwork-Id: 13741057 Received: from out-176.mta0.migadu.com (out-176.mta0.migadu.com [91.218.175.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EFFC915B12F for ; Wed, 24 Jul 2024 14:50:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721832647; cv=none; b=Z2buKQhMQKCAFc3K4qI+nAfH0YpIdz8QtmmH0XfQ//Mfq5cwMsLxbw2fzH4vKT5qdu186ouH+Y7Rnsc3Z3w1V5gya6FyNSKe5Knv0l8OwdFwbKtqd4F5EW3IHNQkq0DwUxsIO8w13TKvfY1ahC544xyakhtNVWnUMNCzwBwtwF0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721832647; c=relaxed/simple; bh=ipt8rPlsSdaXCRB3krCoIDVVDRvnLvHLuZyH9uw1QLk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=reqmLc35+RO8TkG37v68XKqFDU7Ixl13Ned5IX1yQzpgTpi2FIod5X6wLoUtbYo+ZqOQAtWgcJPDgtYWp6144aRbhBkIurLcTcfQpNHtKvH3+CPqHbjBwojxpghn35y8I/V1vK/gfrz8ap0uhrPHVfOUmHv6DJjdb7WB8hLOq9o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=iotcl.com; spf=fail smtp.mailfrom=iotcl.com; dkim=pass (1024-bit key) header.d=iotcl.com header.i=@iotcl.com header.b=13slI0ed; arc=none smtp.client-ip=91.218.175.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=iotcl.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=iotcl.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iotcl.com header.i=@iotcl.com header.b="13slI0ed" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iotcl.com; s=key1; t=1721832641; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=o5WUUG3jZDsdwKDIV+xT96cK4AKsQ4tkPPYDeVAkeQY=; b=13slI0ed4O8jqgFlSnZZqMhTbKWL43x51pCJ4wYssoT5aFji+rhNi4xI3lf+Imvt1ankMR UbzpTkhSNfOv2lIKTJpAurDbUUxjk5+5pyvE9t0nUncPeZk5f8kivDBYx2P9TkPDJIas7n CMCT3AHHZkpm+kMzI0y8iizISMMczSQ= From: Toon Claes To: git@vger.kernel.org Cc: gitster@pobox.com, Toon Claes Subject: [PATCH v2 2/3] transport: introduce transport_has_remote_bundle_uri() Date: Wed, 24 Jul 2024 16:49:56 +0200 Message-ID: <20240724144957.3033840-3-toon@iotcl.com> In-Reply-To: <20240724144957.3033840-1-toon@iotcl.com> References: <20240722080705.2614195-1-toon@iotcl.com> <20240724144957.3033840-1-toon@iotcl.com> Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT The public function transport_get_remote_bundle_uri() exists to fetch the bundle URI(s) from the remote. This function is only called from builtin/clone.c (not taking test-tool into account). There it ignores the return value, because it doesn't matter whether the server didn't return any bundles or if it failed trying to fetch them, clone can continue without bundle URIs. After calling it, it checks if anything is collected in the bundle list and starts fetching them. Add public function transport_has_remote_bundle_uri() instead. This calls the (now made private) transport_get_remote_bundle_uri() function and returns whether any bundle URI is received. This makes reuse of the code easier and avoids code duplication when we add bundle URI support to git-fetch(1). Signed-off-by: Toon Claes --- builtin/clone.c | 23 +++++++---------------- t/helper/test-bundle-uri.c | 2 +- transport.c | 14 +++++++++++++- transport.h | 7 ++++--- 4 files changed, 25 insertions(+), 21 deletions(-) -- 2.45.2 diff --git a/builtin/clone.c b/builtin/clone.c index aa507395a0..25535c1814 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -1404,22 +1404,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix) bundle_uri); else if (has_heuristic) git_config_set_gently("fetch.bundleuri", bundle_uri); - } else { - /* - * Populate transport->got_remote_bundle_uri and - * transport->bundle_uri. We might get nothing. - */ - transport_get_remote_bundle_uri(transport); - - if (transport->bundles && - hashmap_get_size(&transport->bundles->bundles)) { - /* At this point, we need the_repository to match the cloned repo. */ - if (repo_init(the_repository, git_dir, work_tree)) - warning(_("failed to initialize the repo, skipping bundle URI")); - else if (fetch_bundle_list(the_repository, - transport->bundles)) - warning(_("failed to fetch advertised bundles")); - } + } else if (transport_has_remote_bundle_uri(transport)) { + /* At this point, we need the_repository to match the cloned repo. */ + if (repo_init(the_repository, git_dir, work_tree)) + warning(_("failed to initialize the repo, skipping bundle URI")); + else if (fetch_bundle_list(the_repository, + transport->bundles)) + warning(_("failed to fetch advertised bundles")); } if (refs) diff --git a/t/helper/test-bundle-uri.c b/t/helper/test-bundle-uri.c index 0c5fa723d8..bd558d5e57 100644 --- a/t/helper/test-bundle-uri.c +++ b/t/helper/test-bundle-uri.c @@ -90,7 +90,7 @@ static int cmd_ls_remote(int argc, const char **argv) } transport = transport_get(remote, NULL); - if (transport_get_remote_bundle_uri(transport) < 0) { + if (!transport_has_remote_bundle_uri(transport)) { error(_("could not get the bundle-uri list")); status = 1; goto cleanup; diff --git a/transport.c b/transport.c index 12cc5b4d96..1a7d86fa40 100644 --- a/transport.c +++ b/transport.c @@ -1536,7 +1536,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs) return rc; } -int transport_get_remote_bundle_uri(struct transport *transport) +static int transport_get_remote_bundle_uri(struct transport *transport) { int value = 0; const struct transport_vtable *vtable = transport->vtable; @@ -1561,6 +1561,18 @@ int transport_get_remote_bundle_uri(struct transport *transport) if (vtable->get_bundle_uri(transport) < 0) return error(_("could not retrieve server-advertised bundle-uri list")); + + return 0; +} + +int transport_has_remote_bundle_uri(struct transport *transport) +{ + transport_get_remote_bundle_uri(transport); + + if (transport->bundles && + hashmap_get_size(&transport->bundles->bundles)) + return 1; + return 0; } diff --git a/transport.h b/transport.h index 6393cd9823..5ea9641558 100644 --- a/transport.h +++ b/transport.h @@ -294,10 +294,11 @@ const struct ref *transport_get_remote_refs(struct transport *transport, struct transport_ls_refs_options *transport_options); /** - * Retrieve bundle URI(s) from a remote. Populates "struct - * transport"'s "bundle_uri" and "got_remote_bundle_uri". + * Try fetch bundle URI(s) from a remote and returns 1 if one or more + * bundle URI(s) are received from the server. + * Populates "struct transport"'s "bundles" and "got_remote_bundle_uri". */ -int transport_get_remote_bundle_uri(struct transport *transport); +int transport_has_remote_bundle_uri(struct transport *transport); /* * Fetch the hash algorithm used by a remote. From patchwork Wed Jul 24 14:49:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Toon Claes X-Patchwork-Id: 13741058 Received: from out-183.mta1.migadu.com (out-183.mta1.migadu.com [95.215.58.183]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ABCFE15B12F for ; Wed, 24 Jul 2024 14:50:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.183 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721832651; cv=none; b=j9tcBgby1edDK9HB+OxKsaSPgOgB6PFYj2oaZxkPdsYrkC6nMcjbiFgKQyBA3DhRTj8uHUFDQP/kNLXCHYxhIDFbaFxXaUOUI9QCfj9u8eme7Mhcs4KRZNBk+hYIi8+q+ztZlDnoJHgUVDDKPmlQQ1vHSsiWUFPHMAS6jr3SpvY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721832651; c=relaxed/simple; bh=tdBsTN7i54G9a6SiEnvB5+ywIWM8xEY7VASxc09pkFk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=raQAmPfTHT9sKxVVdFaN0jl6LAdos19it4UB3XoGnvsFMUH4+VVwKjZnUtIBwgHmCNZfGLqdst3RLpHpDX+0iF+roXEJeQ7zOlEZh/kjkNM6VgEGaAC+/9QAwXhuCR5OfnWGb4Qj3a9Yntz+lHRT2JM0hqaD9Z1jkyZCeCcFeH8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=iotcl.com; spf=fail smtp.mailfrom=iotcl.com; dkim=pass (1024-bit key) header.d=iotcl.com header.i=@iotcl.com header.b=TldMvP6C; arc=none smtp.client-ip=95.215.58.183 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=iotcl.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=iotcl.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iotcl.com header.i=@iotcl.com header.b="TldMvP6C" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iotcl.com; s=key1; t=1721832646; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SR6ogoa6u3+CSbxCjfLnfb24Z0gXdjdULcZEMelfFmU=; b=TldMvP6C+xw3+uS1EhmB35Tb/8eCIpsFWuFb9DYz4RpyZPWZ/yKdAhqxU0GQMnqjPQgTzd J928+jjpGDZB26xuByI/Qmf/MKlaQinBvTZhhbA78kHSMZ0oIy83OOY5OcAH2A6fsYsMLw 7UC9iiptItypQQXA6SUFuomS/HK/cVM= From: Toon Claes To: git@vger.kernel.org Cc: gitster@pobox.com, Toon Claes Subject: [PATCH v2 3/3] fetch: use bundle URIs when having creationToken heuristic Date: Wed, 24 Jul 2024 16:49:57 +0200 Message-ID: <20240724144957.3033840-4-toon@iotcl.com> In-Reply-To: <20240724144957.3033840-1-toon@iotcl.com> References: <20240722080705.2614195-1-toon@iotcl.com> <20240724144957.3033840-1-toon@iotcl.com> Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT At the moment, bundle URIs are only used by git-clone(1). For a clone the use of bundle URI is trivial, because the repository is empty so downloading bundles will never result in downloading objects that are in the repository already. For git-fetch(1), this more complicated to use bundle URI. We want to avoid downloading bundles that only contains objects that are in the local repository already. One way to achieve this is possible when the "creationToken" heuristic is used for bundle URIs. We attempt to download and unbundle the minimum number of bundles by creationToken in decreasing order. If we fail to unbundle (after a successful download) then move to the next non-downloaded bundle and attempt downloading. Once we succeed in applying a bundle, move to the previous unapplied bundle and attempt to unbundle it again. At the end the highest applied creationToken is written to `fetch.bundleCreationToken` in the git-config. The next time bundles are advertised by the server, bundles with a lower creationToken value are ignored. This was already implemented by 7903efb717 (bundle-uri: download in creationToken order, 2023-01-31) in fetch_bundles_by_token(). Using the creationToken heuristic is optional, but without it the client has no idea which bundles are new, how to sort them, and which only have objects the client already has. With this knowledge, make git-fetch(1) use bundle URIs from the server, but only when the creationToken heuristic is used. Signed-off-by: Toon Claes --- builtin/fetch.c | 13 ++++++++++ t/t5584-fetch-bundle-uri.sh | 49 +++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100755 t/t5584-fetch-bundle-uri.sh -- 2.45.2 diff --git a/builtin/fetch.c b/builtin/fetch.c index 693f02b958..98e811f438 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1694,6 +1694,19 @@ static int do_fetch(struct transport *transport, retcode = 1; } + if (transport_has_remote_bundle_uri(transport)) { + /* + * Only use bundle-URIs when they use the creationToken + * heuristic, this allows us to ensure not downloading bundles + * we don't need. You can read the comments in + * fetch_bundles_by_token() to understand how this works. + */ + if (transport->bundles->heuristic == BUNDLE_HEURISTIC_CREATIONTOKEN) { + if (fetch_bundle_list(the_repository, transport->bundles)) + warning(_("failed to fetch advertised bundles")); + } + } + if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map, &fetch_head, config)) { retcode = 1; diff --git a/t/t5584-fetch-bundle-uri.sh b/t/t5584-fetch-bundle-uri.sh new file mode 100755 index 0000000000..6c2383646e --- /dev/null +++ b/t/t5584-fetch-bundle-uri.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +test_description='test use of bundle URI in "git fetch"' + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +test_expect_success 'set up repos and bundles' ' + git init source && + test_commit -C source A && + git clone --no-local source go-A-to-C && + test_commit -C source B && + git clone --no-local source go-B-to-C && + git clone --no-local source go-B-to-D && + git -C source bundle create B.bundle main && + test_commit -C source C && + git -C source bundle create B-to-C.bundle B..main && + git -C source config uploadpack.advertiseBundleURIs true && + git -C source config bundle.version 1 && + git -C source config bundle.mode all && + git -C source config bundle.heuristic creationToken && + git -C source config bundle.bundle-B.uri "file://$(pwd)/source/B.bundle" && + git -C source config bundle.bundle-B.creationToken 1 && + git -C source config bundle.bundle-B-to-C.uri "file://$(pwd)/source/B-to-C.bundle" && + git -C source config bundle.bundle-B-to-C.creationToken 2 +' + +test_expect_success 'fetches one bundle URI to get up-to-date' ' + git -C go-B-to-C -c transfer.bundleURI=true fetch origin && + test 1 = $(ls go-B-to-C/.git/objects/bundles | wc -l) && + test 2 = $(git -C go-B-to-C config fetch.bundleCreationToken) +' + +test_expect_success 'fetches two bundle URIs to get up-to-date' ' + git -C go-A-to-C -c transfer.bundleURI=true fetch origin && + test 2 = $(ls go-A-to-C/.git/objects/bundles | wc -l) && + test 2 = $(git -C go-A-to-C config fetch.bundleCreationToken) +' + +test_expect_success 'fetches one bundle URI and objects from remote' ' + test_commit -C source D && + git -C go-B-to-D -c transfer.bundleURI=true fetch origin && + test 1 = $(ls go-B-to-D/.git/objects/bundles | wc -l) && + test 2 = $(git -C go-B-to-D config fetch.bundleCreationToken) +' + +test_done