Merge branch 'js/var-git-shell-path'
[git/debian.git] / t / t6020-bundle-misc.sh
blobfe75a06572aed63c2227398de9f82c8006b8e1e7
1 #!/bin/sh
3 # Copyright (c) 2021 Jiang Xin
6 test_description='Test git-bundle'
8 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
9 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
11 TEST_PASSES_SANITIZE_LEAK=true
12 . ./test-lib.sh
13 . "$TEST_DIRECTORY"/lib-bundle.sh
14 . "$TEST_DIRECTORY"/lib-terminal.sh
16 for cmd in create verify list-heads unbundle
18 test_expect_success "usage: git bundle $cmd needs an argument" '
19 test_expect_code 129 git bundle $cmd
21 done
23 # Create a commit or tag and set the variable with the object ID.
24 test_commit_setvar () {
25 notick=
26 signoff=
27 indir=
28 merge=
29 tag=
30 var=
32 while test $# != 0
34 case "$1" in
35 --merge)
36 merge=t
38 --tag)
39 tag=t
41 --notick)
42 notick=t
44 --signoff)
45 signoff="$1"
47 -C)
48 shift
49 indir="$1"
51 -*)
52 echo >&2 "error: unknown option $1"
53 return 1
56 break
58 esac
59 shift
60 done
61 if test $# -lt 2
62 then
63 echo >&2 "error: test_commit_setvar must have at least 2 arguments"
64 return 1
66 var=$1
67 shift
68 indir=${indir:+"$indir"/}
69 if test -z "$notick"
70 then
71 test_tick
72 fi &&
73 if test -n "$merge"
74 then
75 git ${indir:+ -C "$indir"} merge --no-edit --no-ff \
76 ${2:+-m "$2"} "$1" &&
77 oid=$(git ${indir:+ -C "$indir"} rev-parse HEAD)
78 elif test -n "$tag"
79 then
80 git ${indir:+ -C "$indir"} tag -m "$1" "$1" "${2:-HEAD}" &&
81 oid=$(git ${indir:+ -C "$indir"} rev-parse "$1")
82 else
83 file=${2:-"$1.t"} &&
84 echo "${3-$1}" >"$indir$file" &&
85 git ${indir:+ -C "$indir"} add "$file" &&
86 git ${indir:+ -C "$indir"} commit $signoff -m "$1" &&
87 oid=$(git ${indir:+ -C "$indir"} rev-parse HEAD)
88 fi &&
89 eval $var=$oid
92 get_abbrev_oid () {
93 oid=$1 &&
94 suffix=${oid#???????} &&
95 oid=${oid%$suffix} &&
96 if test -n "$oid"
97 then
98 echo "$oid"
99 else
100 echo "undefined-oid"
104 # Format the output of git commands to make a user-friendly and stable
105 # text. We can easily prepare the expect text without having to worry
106 # about future changes of the commit ID.
107 make_user_friendly_and_stable_output () {
108 sed \
109 -e "s/$(get_abbrev_oid $A)[0-9a-f]*/<COMMIT-A>/g" \
110 -e "s/$(get_abbrev_oid $B)[0-9a-f]*/<COMMIT-B>/g" \
111 -e "s/$(get_abbrev_oid $C)[0-9a-f]*/<COMMIT-C>/g" \
112 -e "s/$(get_abbrev_oid $D)[0-9a-f]*/<COMMIT-D>/g" \
113 -e "s/$(get_abbrev_oid $E)[0-9a-f]*/<COMMIT-E>/g" \
114 -e "s/$(get_abbrev_oid $F)[0-9a-f]*/<COMMIT-F>/g" \
115 -e "s/$(get_abbrev_oid $G)[0-9a-f]*/<COMMIT-G>/g" \
116 -e "s/$(get_abbrev_oid $H)[0-9a-f]*/<COMMIT-H>/g" \
117 -e "s/$(get_abbrev_oid $I)[0-9a-f]*/<COMMIT-I>/g" \
118 -e "s/$(get_abbrev_oid $J)[0-9a-f]*/<COMMIT-J>/g" \
119 -e "s/$(get_abbrev_oid $K)[0-9a-f]*/<COMMIT-K>/g" \
120 -e "s/$(get_abbrev_oid $L)[0-9a-f]*/<COMMIT-L>/g" \
121 -e "s/$(get_abbrev_oid $M)[0-9a-f]*/<COMMIT-M>/g" \
122 -e "s/$(get_abbrev_oid $N)[0-9a-f]*/<COMMIT-N>/g" \
123 -e "s/$(get_abbrev_oid $O)[0-9a-f]*/<COMMIT-O>/g" \
124 -e "s/$(get_abbrev_oid $P)[0-9a-f]*/<COMMIT-P>/g" \
125 -e "s/$(get_abbrev_oid $TAG1)[0-9a-f]*/<TAG-1>/g" \
126 -e "s/$(get_abbrev_oid $TAG2)[0-9a-f]*/<TAG-2>/g" \
127 -e "s/$(get_abbrev_oid $TAG3)[0-9a-f]*/<TAG-3>/g"
130 format_and_save_expect () {
131 sed -e 's/Z$//' >expect
134 HASH_MESSAGE="The bundle uses this hash algorithm: $GIT_DEFAULT_HASH"
136 # (C) (D, pull/1/head, topic/1)
137 # o --- o
138 # / \ (L)
139 # / \ o (H, topic/2) (M, tag:v2)
140 # / (F) \ / (N, tag:v3)
141 # / o --------- o (G, pull/2/head) o --- o --- o (release)
142 # / / \ \ / \
143 # o --- o --- o -------- o -- o ------------------ o ------- o --- o (main)
144 # (A) (B) (E, tag:v1) (I) (J) (K) (O) (P)
146 test_expect_success 'setup' '
147 # Try to make a stable fixed width for abbreviated commit ID,
148 # this fixed-width oid will be replaced with "<OID>".
149 git config core.abbrev 7 &&
151 # branch main: commit A & B
152 test_commit_setvar A "Commit A" main.txt &&
153 test_commit_setvar B "Commit B" main.txt &&
155 # branch topic/1: commit C & D, refs/pull/1/head
156 git checkout -b topic/1 &&
157 test_commit_setvar C "Commit C" topic-1.txt &&
158 test_commit_setvar D "Commit D" topic-1.txt &&
159 git update-ref refs/pull/1/head HEAD &&
161 # branch topic/1: commit E, tag v1
162 git checkout main &&
163 test_commit_setvar E "Commit E" main.txt &&
164 test_commit_setvar --tag TAG1 v1 &&
166 # branch topic/2: commit F & G, refs/pull/2/head
167 git checkout -b topic/2 &&
168 test_commit_setvar F "Commit F" topic-2.txt &&
169 test_commit_setvar G "Commit G" topic-2.txt &&
170 git update-ref refs/pull/2/head HEAD &&
171 test_commit_setvar H "Commit H" topic-2.txt &&
173 # branch main: merge commit I & J
174 git checkout main &&
175 test_commit_setvar --merge I topic/1 "Merge commit I" &&
176 test_commit_setvar --merge J refs/pull/2/head "Merge commit J" &&
178 # branch main: commit K
179 git checkout main &&
180 test_commit_setvar K "Commit K" main.txt &&
182 # branch release:
183 git checkout -b release &&
184 test_commit_setvar L "Commit L" release.txt &&
185 test_commit_setvar M "Commit M" release.txt &&
186 test_commit_setvar --tag TAG2 v2 &&
187 test_commit_setvar N "Commit N" release.txt &&
188 test_commit_setvar --tag TAG3 v3 &&
190 # branch main: merge commit O, commit P
191 git checkout main &&
192 test_commit_setvar --merge O tags/v2 "Merge commit O" &&
193 test_commit_setvar P "Commit P" main.txt
196 test_expect_success 'create bundle from special rev: main^!' '
197 git bundle create special-rev.bdl "main^!" &&
199 git bundle list-heads special-rev.bdl |
200 make_user_friendly_and_stable_output >actual &&
201 cat >expect <<-\EOF &&
202 <COMMIT-P> refs/heads/main
204 test_cmp expect actual &&
206 git bundle verify special-rev.bdl |
207 make_user_friendly_and_stable_output >actual &&
208 format_and_save_expect <<-EOF &&
209 The bundle contains this ref:
210 <COMMIT-P> refs/heads/main
211 The bundle requires this ref:
212 <COMMIT-O> Z
213 $HASH_MESSAGE
215 test_cmp expect actual &&
217 test_bundle_object_count special-rev.bdl 3
220 test_expect_success 'create bundle with --max-count option' '
221 git bundle create max-count.bdl --max-count 1 \
222 main \
223 "^release" \
224 refs/tags/v1 \
225 refs/pull/1/head \
226 refs/pull/2/head &&
228 git bundle verify max-count.bdl |
229 make_user_friendly_and_stable_output >actual &&
230 format_and_save_expect <<-EOF &&
231 The bundle contains these 2 refs:
232 <COMMIT-P> refs/heads/main
233 <TAG-1> refs/tags/v1
234 The bundle requires this ref:
235 <COMMIT-O> Z
236 $HASH_MESSAGE
238 test_cmp expect actual &&
240 test_bundle_object_count max-count.bdl 4
243 test_expect_success 'create bundle with --since option' '
244 git log -1 --pretty="%ad" $M >actual &&
245 cat >expect <<-\EOF &&
246 Thu Apr 7 15:26:13 2005 -0700
248 test_cmp expect actual &&
250 git bundle create since.bdl \
251 --since "Thu Apr 7 15:27:00 2005 -0700" \
252 --all &&
254 git bundle verify since.bdl |
255 make_user_friendly_and_stable_output >actual &&
256 format_and_save_expect <<-EOF &&
257 The bundle contains these 5 refs:
258 <COMMIT-P> refs/heads/main
259 <COMMIT-N> refs/heads/release
260 <TAG-2> refs/tags/v2
261 <TAG-3> refs/tags/v3
262 <COMMIT-P> HEAD
263 The bundle requires these 2 refs:
264 <COMMIT-M> Z
265 <COMMIT-K> Z
266 $HASH_MESSAGE
268 test_cmp expect actual &&
270 test_bundle_object_count --thin since.bdl 13
273 test_expect_success 'create bundle 1 - no prerequisites' '
274 # create bundle from args
275 git bundle create 1.bdl topic/1 topic/2 &&
277 # create bundle from stdin
278 cat >input <<-\EOF &&
279 topic/1
280 topic/2
282 git bundle create stdin-1.bdl --stdin <input &&
284 format_and_save_expect <<-EOF &&
285 The bundle contains these 2 refs:
286 <COMMIT-D> refs/heads/topic/1
287 <COMMIT-H> refs/heads/topic/2
288 The bundle records a complete history.
289 $HASH_MESSAGE
292 # verify bundle, which has no prerequisites
293 git bundle verify 1.bdl |
294 make_user_friendly_and_stable_output >actual &&
295 test_cmp expect actual &&
297 git bundle verify stdin-1.bdl |
298 make_user_friendly_and_stable_output >actual &&
299 test_cmp expect actual &&
301 test_bundle_object_count 1.bdl 24 &&
302 test_bundle_object_count stdin-1.bdl 24
305 test_expect_success 'create bundle 2 - has prerequisites' '
306 # create bundle from args
307 git bundle create 2.bdl \
308 --ignore-missing \
309 ^topic/deleted \
310 ^$D \
311 ^topic/2 \
312 release &&
314 # create bundle from stdin
315 # input has a non-exist reference: "topic/deleted"
316 cat >input <<-EOF &&
317 ^topic/deleted
319 ^topic/2
321 git bundle create stdin-2.bdl \
322 --ignore-missing \
323 --stdin \
324 release <input &&
326 format_and_save_expect <<-EOF &&
327 The bundle contains this ref:
328 <COMMIT-N> refs/heads/release
329 The bundle requires these 3 refs:
330 <COMMIT-D> Z
331 <COMMIT-E> Z
332 <COMMIT-G> Z
333 $HASH_MESSAGE
336 git bundle verify 2.bdl |
337 make_user_friendly_and_stable_output >actual &&
338 test_cmp expect actual &&
340 git bundle verify stdin-2.bdl |
341 make_user_friendly_and_stable_output >actual &&
342 test_cmp expect actual &&
344 test_bundle_object_count 2.bdl 16 &&
345 test_bundle_object_count stdin-2.bdl 16
348 test_expect_success 'fail to verify bundle without prerequisites' '
349 git init --bare test1.git &&
351 format_and_save_expect <<-\EOF &&
352 error: Repository lacks these prerequisite commits:
353 error: <COMMIT-D> Z
354 error: <COMMIT-E> Z
355 error: <COMMIT-G> Z
358 test_must_fail git -C test1.git bundle verify ../2.bdl 2>&1 |
359 make_user_friendly_and_stable_output >actual &&
360 test_cmp expect actual &&
362 test_must_fail git -C test1.git bundle verify ../stdin-2.bdl 2>&1 |
363 make_user_friendly_and_stable_output >actual &&
364 test_cmp expect actual
367 test_expect_success 'create bundle 3 - two refs, same object' '
368 # create bundle from args
369 git bundle create --version=3 3.bdl \
370 ^release \
371 ^topic/1 \
372 ^topic/2 \
373 main \
374 HEAD &&
376 # create bundle from stdin
377 cat >input <<-\EOF &&
378 ^release
379 ^topic/1
380 ^topic/2
382 git bundle create --version=3 stdin-3.bdl \
383 --stdin \
384 main HEAD <input &&
386 format_and_save_expect <<-EOF &&
387 The bundle contains these 2 refs:
388 <COMMIT-P> refs/heads/main
389 <COMMIT-P> HEAD
390 The bundle requires these 2 refs:
391 <COMMIT-M> Z
392 <COMMIT-K> Z
393 $HASH_MESSAGE
396 git bundle verify 3.bdl |
397 make_user_friendly_and_stable_output >actual &&
398 test_cmp expect actual &&
400 git bundle verify stdin-3.bdl |
401 make_user_friendly_and_stable_output >actual &&
402 test_cmp expect actual &&
404 test_bundle_object_count 3.bdl 4 &&
405 test_bundle_object_count stdin-3.bdl 4
408 test_expect_success 'create bundle 4 - with tags' '
409 # create bundle from args
410 git bundle create 4.bdl \
411 ^main \
412 ^release \
413 ^topic/1 \
414 ^topic/2 \
415 --all &&
417 # create bundle from stdin
418 cat >input <<-\EOF &&
419 ^main
420 ^release
421 ^topic/1
422 ^topic/2
424 git bundle create stdin-4.bdl \
425 --ignore-missing \
426 --stdin \
427 --all <input &&
429 cat >expect <<-EOF &&
430 The bundle contains these 3 refs:
431 <TAG-1> refs/tags/v1
432 <TAG-2> refs/tags/v2
433 <TAG-3> refs/tags/v3
434 The bundle records a complete history.
435 $HASH_MESSAGE
438 git bundle verify 4.bdl |
439 make_user_friendly_and_stable_output >actual &&
440 test_cmp expect actual &&
442 git bundle verify stdin-4.bdl |
443 make_user_friendly_and_stable_output >actual &&
444 test_cmp expect actual &&
446 test_bundle_object_count 4.bdl 3 &&
447 test_bundle_object_count stdin-4.bdl 3
450 test_expect_success 'clone from bundle' '
451 git clone --mirror 1.bdl mirror.git &&
452 git -C mirror.git show-ref |
453 make_user_friendly_and_stable_output >actual &&
454 cat >expect <<-\EOF &&
455 <COMMIT-D> refs/heads/topic/1
456 <COMMIT-H> refs/heads/topic/2
458 test_cmp expect actual &&
460 git -C mirror.git fetch ../2.bdl "+refs/*:refs/*" &&
461 git -C mirror.git show-ref |
462 make_user_friendly_and_stable_output >actual &&
463 cat >expect <<-\EOF &&
464 <COMMIT-N> refs/heads/release
465 <COMMIT-D> refs/heads/topic/1
466 <COMMIT-H> refs/heads/topic/2
468 test_cmp expect actual &&
470 git -C mirror.git fetch ../3.bdl "+refs/*:refs/*" &&
471 git -C mirror.git show-ref |
472 make_user_friendly_and_stable_output >actual &&
473 cat >expect <<-\EOF &&
474 <COMMIT-P> refs/heads/main
475 <COMMIT-N> refs/heads/release
476 <COMMIT-D> refs/heads/topic/1
477 <COMMIT-H> refs/heads/topic/2
479 test_cmp expect actual &&
481 git -C mirror.git fetch ../4.bdl "+refs/*:refs/*" &&
482 git -C mirror.git show-ref |
483 make_user_friendly_and_stable_output >actual &&
484 cat >expect <<-\EOF &&
485 <COMMIT-P> refs/heads/main
486 <COMMIT-N> refs/heads/release
487 <COMMIT-D> refs/heads/topic/1
488 <COMMIT-H> refs/heads/topic/2
489 <TAG-1> refs/tags/v1
490 <TAG-2> refs/tags/v2
491 <TAG-3> refs/tags/v3
493 test_cmp expect actual
496 test_expect_success 'unfiltered bundle with --objects' '
497 git bundle create all-objects.bdl \
498 --all --objects &&
499 git bundle create all.bdl \
500 --all &&
502 # Compare the headers of these files.
503 sed -n -e "/^$/q" -e "p" all.bdl >expect &&
504 sed -n -e "/^$/q" -e "p" all-objects.bdl >actual &&
505 test_cmp expect actual
508 for filter in "blob:none" "tree:0" "tree:1" "blob:limit=100"
510 test_expect_success "filtered bundle: $filter" '
511 test_when_finished rm -rf .git/objects/pack cloned unbundled &&
512 git bundle create partial.bdl \
513 --all \
514 --filter=$filter &&
516 git bundle verify partial.bdl >unfiltered &&
517 make_user_friendly_and_stable_output <unfiltered >actual &&
519 cat >expect <<-EOF &&
520 The bundle contains these 10 refs:
521 <COMMIT-P> refs/heads/main
522 <COMMIT-N> refs/heads/release
523 <COMMIT-D> refs/heads/topic/1
524 <COMMIT-H> refs/heads/topic/2
525 <COMMIT-D> refs/pull/1/head
526 <COMMIT-G> refs/pull/2/head
527 <TAG-1> refs/tags/v1
528 <TAG-2> refs/tags/v2
529 <TAG-3> refs/tags/v3
530 <COMMIT-P> HEAD
531 The bundle records a complete history.
532 $HASH_MESSAGE
533 The bundle uses this filter: $filter
535 test_cmp expect actual &&
537 test_config uploadpack.allowfilter 1 &&
538 test_config uploadpack.allowanysha1inwant 1 &&
539 git clone --no-local --filter=$filter --bare "file://$(pwd)" cloned &&
541 git init unbundled &&
542 git -C unbundled bundle unbundle ../partial.bdl >ref-list.txt &&
543 ls unbundled/.git/objects/pack/pack-*.promisor >promisor &&
544 test_line_count = 1 promisor &&
546 # Count the same number of reachable objects.
547 reflist=$(git for-each-ref --format="%(objectname)") &&
548 git rev-list --objects --filter=$filter --missing=allow-any \
549 $reflist >expect &&
550 for repo in cloned unbundled
552 git -C $repo rev-list --objects --missing=allow-any \
553 $reflist >actual &&
554 test_cmp expect actual || return 1
555 done
557 done
559 # NEEDSWORK: 'git clone --bare' should be able to clone from a filtered
560 # bundle, but that requires a change to promisor/filter config options.
561 # For now, we fail gracefully with a helpful error. This behavior can be
562 # changed in the future to succeed as much as possible.
563 test_expect_success 'cloning from filtered bundle has useful error' '
564 git bundle create partial.bdl \
565 --all \
566 --filter=blob:none &&
567 test_must_fail git clone --bare partial.bdl partial 2>err &&
568 grep "cannot clone from filtered bundle" err
571 test_expect_success 'verify catches unreachable, broken prerequisites' '
572 test_when_finished rm -rf clone-from clone-to &&
573 git init clone-from &&
575 cd clone-from &&
576 git checkout -b base &&
577 test_commit A &&
578 git checkout -b tip &&
579 git commit --allow-empty -m "will drop by shallow" &&
580 git commit --allow-empty -m "will keep by shallow" &&
581 git commit --allow-empty -m "for bundle, not clone" &&
582 git bundle create tip.bundle tip~1..tip &&
583 git reset --hard HEAD~1 &&
584 git checkout base
585 ) &&
586 BAD_OID=$(git -C clone-from rev-parse tip~1) &&
587 TIP_OID=$(git -C clone-from rev-parse tip) &&
588 git clone --depth=1 --no-single-branch \
589 "file://$(pwd)/clone-from" clone-to &&
591 cd clone-to &&
593 # Set up broken history by removing shallow markers
594 git update-ref -d refs/remotes/origin/tip &&
595 rm .git/shallow &&
597 # Verify should fail
598 test_must_fail git bundle verify \
599 ../clone-from/tip.bundle 2>err &&
600 grep "some prerequisite commits .* are not connected" err &&
601 test_line_count = 1 err &&
603 # Unbundling should fail
604 test_must_fail git bundle unbundle \
605 ../clone-from/tip.bundle 2>err &&
606 grep "some prerequisite commits .* are not connected" err &&
607 test_line_count = 1 err
611 test_expect_success 'bundle progress includes write phase' '
612 GIT_PROGRESS_DELAY=0 \
613 git bundle create --progress out.bundle --all 2>err &&
614 grep 'Writing' err
617 test_expect_success TTY 'create --quiet disables all bundle progress' '
618 test_terminal env GIT_PROGRESS_DELAY=0 \
619 git bundle create --quiet out.bundle --all 2>err &&
620 test_must_be_empty err
623 test_expect_success 'bundle progress with --no-quiet' '
624 GIT_PROGRESS_DELAY=0 \
625 git bundle create --no-quiet out.bundle --all 2>err &&
626 grep "%" err
629 test_expect_success 'read bundle over stdin' '
630 git bundle create some.bundle HEAD &&
632 git bundle verify - <some.bundle 2>err &&
633 grep "<stdin> is okay" err &&
635 git bundle list-heads some.bundle >expect &&
636 git bundle list-heads - <some.bundle >actual &&
637 test_cmp expect actual &&
639 git bundle unbundle some.bundle >expect &&
640 git bundle unbundle - <some.bundle >actual &&
641 test_cmp expect actual
644 test_expect_success 'send a bundle to standard output' '
645 git bundle create - --all HEAD >bundle-one &&
646 mkdir -p down &&
647 git -C down bundle create - --all HEAD >bundle-two &&
648 git bundle verify bundle-one &&
649 git bundle verify bundle-two &&
650 git ls-remote bundle-one >expect &&
651 git ls-remote bundle-two >actual &&
652 test_cmp expect actual
655 test_done