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