Merge branch 'sc/bundle-uri-use-all-refs-in-bundle' into seen

Bundle-URI feature did not use refs recorded in the bundle other
than normal branches as anchoring points to optimize the follow-up
fetch during "git clone"; now it is told to utilize all.

Ready?

* sc/bundle-uri-use-all-refs-in-bundle:
  bundle-uri: add test for bundle-uri clones with tags
  bundle-uri: copy all bundle references ino the refs/bundle space
Junio C Hamano 2025-05-01 14:07:28 -07:00
commit 6de06a65ea
3 changed files with 124 additions and 94 deletions

View File

@ -232,13 +232,13 @@ will interact with bundle URIs according to the following flow:
are present in the client repository. If some are missing, then the are present in the client repository. If some are missing, then the
client delays unbundling until other bundles have been unbundled, client delays unbundling until other bundles have been unbundled,
making those OIDs present. When all required OIDs are present, the making those OIDs present. When all required OIDs are present, the
client unbundles that data using a refspec. The default refspec is client unbundles that data using a refspec. The refspec used is
`+refs/heads/*:refs/bundles/*`, but this can be configured. These refs `+refs/*:refs/bundles/*`. These refs are stored so that later
are stored so that later `git fetch` negotiations can communicate each `git fetch` negotiations can communicate each bundled ref as a `have`,
bundled ref as a `have`, reducing the size of the fetch over the Git reducing the size of the fetch over the Git protocol. To allow pruning
protocol. To allow pruning refs from this ref namespace, Git may refs from this ref namespace, Git may introduce a numbered namespace
introduce a numbered namespace (such as `refs/bundles/<i>/*`) such that (such as `refs/bundles/<i>/*`) such that stale bundle refs can be
stale bundle refs can be deleted. deleted.


3. If the file is instead a bundle list, then the client inspects the 3. If the file is instead a bundle list, then the client inspects the
`bundle.mode` to see if the list is of the `all` or `any` form. `bundle.mode` to see if the list is of the `all` or `any` form.

View File

@ -403,7 +403,7 @@ static int unbundle_from_file(struct repository *r, const char *file)
const char *branch_name; const char *branch_name;
int has_old; int has_old;


if (!skip_prefix(refname->string, "refs/heads/", &branch_name)) if (!skip_prefix(refname->string, "refs/", &branch_name))
continue; continue;


strbuf_setlen(&bundle_ref, bundle_prefix_len); strbuf_setlen(&bundle_ref, bundle_prefix_len);

View File

@ -58,7 +58,7 @@ test_expect_success 'create bundle' '
test_expect_success 'clone with path bundle' ' test_expect_success 'clone with path bundle' '
git clone --bundle-uri="clone-from/B.bundle" \ git clone --bundle-uri="clone-from/B.bundle" \
clone-from clone-path && clone-from clone-path &&
git -C clone-path rev-parse refs/bundles/topic >actual && git -C clone-path rev-parse refs/bundles/heads/topic >actual &&
git -C clone-from rev-parse topic >expect && git -C clone-from rev-parse topic >expect &&
test_cmp expect actual test_cmp expect actual
' '
@ -68,9 +68,9 @@ test_expect_success 'clone with bundle that has bad header' '
git clone --bundle-uri="clone-from/bad-header.bundle" \ git clone --bundle-uri="clone-from/bad-header.bundle" \
clone-from clone-bad-header 2>err && clone-from clone-bad-header 2>err &&
commit_b=$(git -C clone-from rev-parse B) && commit_b=$(git -C clone-from rev-parse B) &&
test_grep "trying to write ref '\''refs/bundles/topic'\'' with nonexistent object $commit_b" err && test_grep "trying to write ref '\''refs/bundles/heads/topic'\'' with nonexistent object $commit_b" err &&
git -C clone-bad-header for-each-ref --format="%(refname)" >refs && git -C clone-bad-header for-each-ref --format="%(refname)" >refs &&
test_grep ! "refs/bundles/" refs test_grep ! "refs/bundles/heads/" refs
' '


test_expect_success 'clone with bundle that has bad object' ' test_expect_success 'clone with bundle that has bad object' '
@ -78,8 +78,8 @@ test_expect_success 'clone with bundle that has bad object' '
git clone --bundle-uri="clone-from/bad-object.bundle" \ git clone --bundle-uri="clone-from/bad-object.bundle" \
clone-from clone-bad-object-no-fsck && clone-from clone-bad-object-no-fsck &&
git -C clone-bad-object-no-fsck for-each-ref --format="%(refname)" >refs && git -C clone-bad-object-no-fsck for-each-ref --format="%(refname)" >refs &&
grep "refs/bundles/" refs >actual && grep "refs/bundles/heads/" refs >actual &&
test_write_lines refs/bundles/bad >expect && test_write_lines refs/bundles/heads/bad >expect &&
test_cmp expect actual && test_cmp expect actual &&


# Unbundle fails with fsckObjects set true, but clone can still proceed. # Unbundle fails with fsckObjects set true, but clone can still proceed.
@ -87,14 +87,14 @@ test_expect_success 'clone with bundle that has bad object' '
clone-from clone-bad-object-fsck 2>err && clone-from clone-bad-object-fsck 2>err &&
test_grep "missingEmail" err && test_grep "missingEmail" err &&
git -C clone-bad-object-fsck for-each-ref --format="%(refname)" >refs && git -C clone-bad-object-fsck for-each-ref --format="%(refname)" >refs &&
test_grep ! "refs/bundles/" refs test_grep ! "refs/bundles/heads/" refs
' '


test_expect_success 'clone with path bundle and non-default hash' ' test_expect_success 'clone with path bundle and non-default hash' '
test_when_finished "rm -rf clone-path-non-default-hash" && test_when_finished "rm -rf clone-path-non-default-hash" &&
GIT_DEFAULT_HASH=sha256 git clone --bundle-uri="clone-from/B.bundle" \ GIT_DEFAULT_HASH=sha256 git clone --bundle-uri="clone-from/B.bundle" \
clone-from clone-path-non-default-hash && clone-from clone-path-non-default-hash &&
git -C clone-path-non-default-hash rev-parse refs/bundles/topic >actual && git -C clone-path-non-default-hash rev-parse refs/bundles/heads/topic >actual &&
git -C clone-from rev-parse topic >expect && git -C clone-from rev-parse topic >expect &&
test_cmp expect actual test_cmp expect actual
' '
@ -102,11 +102,41 @@ test_expect_success 'clone with path bundle and non-default hash' '
test_expect_success 'clone with file:// bundle' ' test_expect_success 'clone with file:// bundle' '
git clone --bundle-uri="file://$(pwd)/clone-from/B.bundle" \ git clone --bundle-uri="file://$(pwd)/clone-from/B.bundle" \
clone-from clone-file && clone-from clone-file &&
git -C clone-file rev-parse refs/bundles/topic >actual && git -C clone-file rev-parse refs/bundles/heads/topic >actual &&
git -C clone-from rev-parse topic >expect && git -C clone-from rev-parse topic >expect &&
test_cmp expect actual test_cmp expect actual
' '


test_expect_success 'create bundle with tags' '
git init clone-from-tags &&
(
cd clone-from-tags &&
git checkout -b base &&
git checkout -b topic &&

test_commit A &&
git tag tag-A &&
git checkout -b base &&
git branch -d topic &&
test_commit B &&

git bundle create ALL.bundle --all &&
git bundle verify ALL.bundle
)
'

test_expect_success 'clone with tags bundle' '
git clone --bundle-uri="clone-from-tags/ALL.bundle" \
clone-from-tags clone-tags-path &&

git -C clone-from-tags for-each-ref --format="%(refname:lstrip=1)" \
>expect &&
git -C clone-tags-path for-each-ref --format="%(refname:lstrip=2)" \
refs/bundles >actual &&

test_cmp expect actual
'

# To get interesting tests for bundle lists, we need to construct a # To get interesting tests for bundle lists, we need to construct a
# somewhat-interesting commit history. # somewhat-interesting commit history.
# #
@ -173,12 +203,12 @@ test_expect_success 'clone bundle list (file, no heuristic)' '
git -C clone-list-file cat-file --batch-check <oids && git -C clone-list-file cat-file --batch-check <oids &&


git -C clone-list-file for-each-ref --format="%(refname)" >refs && git -C clone-list-file for-each-ref --format="%(refname)" >refs &&
grep "refs/bundles/" refs >actual && grep "refs/bundles/heads/" refs >actual &&
cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
refs/bundles/merge refs/bundles/heads/merge
refs/bundles/right refs/bundles/heads/right
EOF EOF
test_cmp expect actual test_cmp expect actual
' '
@ -220,10 +250,10 @@ test_expect_success 'clone bundle list (file, all mode, some failures)' '
git -C clone-all-some cat-file --batch-check <oids && git -C clone-all-some cat-file --batch-check <oids &&


git -C clone-all-some for-each-ref --format="%(refname)" >refs && git -C clone-all-some for-each-ref --format="%(refname)" >refs &&
grep "refs/bundles/" refs >actual && grep "refs/bundles/heads/" refs >actual &&
cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
EOF EOF
test_cmp expect actual test_cmp expect actual
' '
@ -253,7 +283,7 @@ test_expect_success 'clone bundle list (file, all mode, all failures)' '
git -C clone-all-fail cat-file --batch-check <oids && git -C clone-all-fail cat-file --batch-check <oids &&


git -C clone-all-fail for-each-ref --format="%(refname)" >refs && git -C clone-all-fail for-each-ref --format="%(refname)" >refs &&
! grep "refs/bundles/" refs ! grep "refs/bundles/heads/" refs
' '


test_expect_success 'clone bundle list (file, any mode)' ' test_expect_success 'clone bundle list (file, any mode)' '
@ -282,9 +312,9 @@ test_expect_success 'clone bundle list (file, any mode)' '
git -C clone-any-file cat-file --batch-check <oids && git -C clone-any-file cat-file --batch-check <oids &&


git -C clone-any-file for-each-ref --format="%(refname)" >refs && git -C clone-any-file for-each-ref --format="%(refname)" >refs &&
grep "refs/bundles/" refs >actual && grep "refs/bundles/heads/" refs >actual &&
cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
EOF EOF
test_cmp expect actual test_cmp expect actual
' '
@ -313,7 +343,7 @@ test_expect_success 'clone bundle list (file, any mode, all failures)' '
git -C clone-any-fail cat-file --batch-check <oids && git -C clone-any-fail cat-file --batch-check <oids &&


git -C clone-any-fail for-each-ref --format="%(refname)" >refs && git -C clone-any-fail for-each-ref --format="%(refname)" >refs &&
! grep "refs/bundles/" refs ! grep "refs/bundles/heads/" refs
' '


test_expect_success 'negotiation: bundle with part of wanted commits' ' test_expect_success 'negotiation: bundle with part of wanted commits' '
@ -322,10 +352,10 @@ test_expect_success 'negotiation: bundle with part of wanted commits' '
git clone --no-local --bundle-uri="clone-from/A.bundle" \ git clone --no-local --bundle-uri="clone-from/A.bundle" \
clone-from nego-bundle-part && clone-from nego-bundle-part &&
git -C nego-bundle-part for-each-ref --format="%(refname)" >refs && git -C nego-bundle-part for-each-ref --format="%(refname)" >refs &&
grep "refs/bundles/" refs >actual && grep "refs/bundles/heads/" refs >actual &&
test_write_lines refs/bundles/topic >expect && test_write_lines refs/bundles/heads/topic >expect &&
test_cmp expect actual && test_cmp expect actual &&
# Ensure that refs/bundles/topic are sent as "have". # Ensure that refs/bundles/heads/topic are sent as "have".
tip=$(git -C clone-from rev-parse A) && tip=$(git -C clone-from rev-parse A) &&
test_grep "clone> have $tip" trace-packet.txt test_grep "clone> have $tip" trace-packet.txt
' '
@ -337,8 +367,8 @@ test_expect_success 'negotiation: bundle with all wanted commits' '
--bundle-uri="clone-from/B.bundle" \ --bundle-uri="clone-from/B.bundle" \
clone-from nego-bundle-all && clone-from nego-bundle-all &&
git -C nego-bundle-all for-each-ref --format="%(refname)" >refs && git -C nego-bundle-all for-each-ref --format="%(refname)" >refs &&
grep "refs/bundles/" refs >actual && grep "refs/bundles/heads/" refs >actual &&
test_write_lines refs/bundles/topic >expect && test_write_lines refs/bundles/heads/topic >expect &&
test_cmp expect actual && test_cmp expect actual &&
# We already have all needed commits so no "want" needed. # We already have all needed commits so no "want" needed.
test_grep ! "clone> want " trace-packet.txt test_grep ! "clone> want " trace-packet.txt
@ -363,13 +393,13 @@ test_expect_success 'negotiation: bundle list (no heuristic)' '
clone-from nego-bundle-list-no-heuristic && clone-from nego-bundle-list-no-heuristic &&


git -C nego-bundle-list-no-heuristic for-each-ref --format="%(refname)" >refs && git -C nego-bundle-list-no-heuristic for-each-ref --format="%(refname)" >refs &&
grep "refs/bundles/" refs >actual && grep "refs/bundles/heads/" refs >actual &&
cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
EOF EOF
test_cmp expect actual && test_cmp expect actual &&
tip=$(git -C nego-bundle-list-no-heuristic rev-parse refs/bundles/left) && tip=$(git -C nego-bundle-list-no-heuristic rev-parse refs/bundles/heads/left) &&
test_grep "clone> have $tip" trace-packet.txt test_grep "clone> have $tip" trace-packet.txt
' '


@ -395,13 +425,13 @@ test_expect_success 'negotiation: bundle list (creationToken)' '
clone-from nego-bundle-list-heuristic && clone-from nego-bundle-list-heuristic &&


git -C nego-bundle-list-heuristic for-each-ref --format="%(refname)" >refs && git -C nego-bundle-list-heuristic for-each-ref --format="%(refname)" >refs &&
grep "refs/bundles/" refs >actual && grep "refs/bundles/heads/" refs >actual &&
cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
EOF EOF
test_cmp expect actual && test_cmp expect actual &&
tip=$(git -C nego-bundle-list-heuristic rev-parse refs/bundles/left) && tip=$(git -C nego-bundle-list-heuristic rev-parse refs/bundles/heads/left) &&
test_grep "clone> have $tip" trace-packet.txt test_grep "clone> have $tip" trace-packet.txt
' '


@ -428,10 +458,10 @@ test_expect_success 'negotiation: bundle list with all wanted commits' '
clone-from nego-bundle-list-all && clone-from nego-bundle-list-all &&


git -C nego-bundle-list-all for-each-ref --format="%(refname)" >refs && git -C nego-bundle-list-all for-each-ref --format="%(refname)" >refs &&
grep "refs/bundles/" refs >actual && grep "refs/bundles/heads/" refs >actual &&
cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
EOF EOF
test_cmp expect actual && test_cmp expect actual &&
# We already have all needed commits so no "want" needed. # We already have all needed commits so no "want" needed.
@ -465,7 +495,7 @@ test_expect_success 'clone HTTP bundle' '


git clone --bundle-uri="$HTTPD_URL/B.bundle" \ git clone --bundle-uri="$HTTPD_URL/B.bundle" \
"$HTTPD_URL/smart/fetch.git" clone-http && "$HTTPD_URL/smart/fetch.git" clone-http &&
git -C clone-http rev-parse refs/bundles/topic >actual && git -C clone-http rev-parse refs/bundles/heads/topic >actual &&
git -C clone-from rev-parse topic >expect && git -C clone-from rev-parse topic >expect &&
test_cmp expect actual && test_cmp expect actual &&


@ -476,7 +506,7 @@ test_expect_success 'clone HTTP bundle with non-default hash' '
test_when_finished "rm -rf clone-http-non-default-hash" && test_when_finished "rm -rf clone-http-non-default-hash" &&
GIT_DEFAULT_HASH=sha256 git clone --bundle-uri="$HTTPD_URL/B.bundle" \ GIT_DEFAULT_HASH=sha256 git clone --bundle-uri="$HTTPD_URL/B.bundle" \
"$HTTPD_URL/smart/fetch.git" clone-http-non-default-hash && "$HTTPD_URL/smart/fetch.git" clone-http-non-default-hash &&
git -C clone-http-non-default-hash rev-parse refs/bundles/topic >actual && git -C clone-http-non-default-hash rev-parse refs/bundles/heads/topic >actual &&
git -C clone-from rev-parse topic >expect && git -C clone-from rev-parse topic >expect &&
test_cmp expect actual test_cmp expect actual
' '
@ -553,12 +583,12 @@ test_expect_success 'clone bundle list (HTTP, any mode)' '
git -C clone-any-http cat-file --batch-check <oids && git -C clone-any-http cat-file --batch-check <oids &&


git -C clone-list-file for-each-ref --format="%(refname)" >refs && git -C clone-list-file for-each-ref --format="%(refname)" >refs &&
grep "refs/bundles/" refs >actual && grep "refs/bundles/heads/" refs >actual &&
cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
refs/bundles/merge refs/bundles/heads/merge
refs/bundles/right refs/bundles/heads/right
EOF EOF
test_cmp expect actual test_cmp expect actual
' '
@ -641,9 +671,9 @@ test_expect_success 'clone incomplete bundle list (http, creationToken)' '
test_cmp expect actual && test_cmp expect actual &&


# We now have only one bundle ref. # We now have only one bundle ref.
git -C clone-token-http for-each-ref --format="%(refname)" "refs/bundles/*" >refs && git -C clone-token-http for-each-ref --format="%(refname)" "refs/bundles/heads/*" >refs &&
cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
EOF EOF
test_cmp expect refs && test_cmp expect refs &&


@ -679,13 +709,13 @@ test_expect_success 'clone incomplete bundle list (http, creationToken)' '
test_cmp expect actual && test_cmp expect actual &&


# We now have all bundle refs. # We now have all bundle refs.
git -C clone-token-http for-each-ref --format="%(refname)" "refs/bundles/*" >refs && git -C clone-token-http for-each-ref --format="%(refname)" "refs/bundles/heads/*" >refs &&


cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
refs/bundles/merge refs/bundles/heads/merge
refs/bundles/right refs/bundles/heads/right
EOF EOF
test_cmp expect refs test_cmp expect refs
' '
@ -721,9 +751,9 @@ test_expect_success 'http clone with bundle.heuristic creates fetch.bundleURI' '
test_cmp expect actual && test_cmp expect actual &&


# only received base ref from bundle-1 # only received base ref from bundle-1
git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/heads/*" >refs &&
cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
EOF EOF
test_cmp expect refs && test_cmp expect refs &&


@ -749,10 +779,10 @@ test_expect_success 'http clone with bundle.heuristic creates fetch.bundleURI' '
test_cmp expect actual && test_cmp expect actual &&


# received left from bundle-2 # received left from bundle-2
git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/heads/*" >refs &&
cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
EOF EOF
test_cmp expect refs && test_cmp expect refs &&


@ -795,12 +825,12 @@ test_expect_success 'http clone with bundle.heuristic creates fetch.bundleURI' '


# received merge ref from bundle-4, but right is missing # received merge ref from bundle-4, but right is missing
# because we did not download bundle-3. # because we did not download bundle-3.
git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/heads/*" >refs &&


cat >expect <<-\EOF && cat >expect <<-\EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
refs/bundles/merge refs/bundles/heads/merge
EOF EOF
test_cmp expect refs && test_cmp expect refs &&


@ -862,7 +892,7 @@ test_expect_success 'creationToken heuristic with failed downloads (clone)' '
test_cmp expect actual && test_cmp expect actual &&


# All bundles failed to unbundle # All bundles failed to unbundle
git -C download-1 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && git -C download-1 for-each-ref --format="%(refname)" "refs/bundles/heads/*" >refs &&
test_must_be_empty refs && test_must_be_empty refs &&


# Case 2: middle bundle does not exist, only two bundles can unbundle # Case 2: middle bundle does not exist, only two bundles can unbundle
@ -909,10 +939,10 @@ test_expect_success 'creationToken heuristic with failed downloads (clone)' '
test_cmp expect actual && test_cmp expect actual &&


# bundle-1 and bundle-3 could unbundle, but bundle-4 could not # bundle-1 and bundle-3 could unbundle, but bundle-4 could not
git -C download-2 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && git -C download-2 for-each-ref --format="%(refname)" "refs/bundles/heads/*" >refs &&
cat >expect <<-EOF && cat >expect <<-EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/right refs/bundles/heads/right
EOF EOF
test_cmp expect refs && test_cmp expect refs &&


@ -961,11 +991,11 @@ test_expect_success 'creationToken heuristic with failed downloads (clone)' '
test_cmp expect actual && test_cmp expect actual &&


# fake.bundle did not unbundle, but the others did. # fake.bundle did not unbundle, but the others did.
git -C download-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && git -C download-3 for-each-ref --format="%(refname)" "refs/bundles/heads/*" >refs &&
cat >expect <<-EOF && cat >expect <<-EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
refs/bundles/right refs/bundles/heads/right
EOF EOF
test_cmp expect refs test_cmp expect refs
' '
@ -1083,15 +1113,15 @@ test_expect_success 'creationToken heuristic with failed downloads (fetch)' '
test_cmp expect actual && test_cmp expect actual &&


# Check which bundles have unbundled by refs # Check which bundles have unbundled by refs
git -C fetch-1 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && git -C fetch-1 for-each-ref --format="%(refname)" "refs/bundles/heads/*" >refs &&
cat >expect <<-EOF && cat >expect <<-EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
refs/bundles/lefter refs/bundles/heads/lefter
refs/bundles/merge refs/bundles/heads/merge
refs/bundles/right refs/bundles/heads/right
refs/bundles/righter refs/bundles/heads/righter
refs/bundles/top refs/bundles/heads/top
EOF EOF
test_cmp expect refs && test_cmp expect refs &&


@ -1144,12 +1174,12 @@ test_expect_success 'creationToken heuristic with failed downloads (fetch)' '
test_cmp expect actual && test_cmp expect actual &&


# Check which bundles have unbundled by refs # Check which bundles have unbundled by refs
git -C fetch-2 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && git -C fetch-2 for-each-ref --format="%(refname)" "refs/bundles/heads/*" >refs &&
cat >expect <<-EOF && cat >expect <<-EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
refs/bundles/merge refs/bundles/heads/merge
refs/bundles/right refs/bundles/heads/right
EOF EOF
test_cmp expect refs && test_cmp expect refs &&


@ -1204,13 +1234,13 @@ test_expect_success 'creationToken heuristic with failed downloads (fetch)' '
test_cmp expect actual && test_cmp expect actual &&


# Check which bundles have unbundled by refs # Check which bundles have unbundled by refs
git -C fetch-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && git -C fetch-3 for-each-ref --format="%(refname)" "refs/bundles/heads/*" >refs &&
cat >expect <<-EOF && cat >expect <<-EOF &&
refs/bundles/base refs/bundles/heads/base
refs/bundles/left refs/bundles/heads/left
refs/bundles/lefter refs/bundles/heads/lefter
refs/bundles/right refs/bundles/heads/right
refs/bundles/righter refs/bundles/heads/righter
EOF EOF
test_cmp expect refs test_cmp expect refs
' '