Raw
1 #!/bin/sh
2
3 test_description='test describe'
4
5 # o---o-----o----o----o-------o----x
6 # \ D,R e /
7 # \---o-------------o-'
8 # \ B /
9 # `-o----o----o-'
10 # A c
11 #
12 # First parent of a merge commit is on the same line, second parent below.
13
14 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
15 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
16
17 . ./test-lib.sh
18
19 check_describe () {
20 indir= &&
21 outcome=success &&
22 while test $# != 0
23 do
24 case "$1" in
25 -C)
26 indir="$2"
27 shift
28 ;;
29 --expect-failure)
30 outcome=failure
31 ;;
32 *)
33 break
34 ;;
35 esac
36 shift
37 done &&
38 indir=${indir:+"$indir"/} &&
39 expect="$1"
40 shift
41 describe_opts="$@"
42 test_expect_${outcome} "describe $describe_opts" '
43 git ${indir:+ -C "$indir"} describe $describe_opts >raw &&
44 sed -e "s/-g[0-9a-f]*\$/-gHASH/" <raw >actual &&
45 echo "$expect" >expect &&
46 test_cmp expect actual
47 '
48 }
49
50 test_expect_success setup '
51 test_commit initial file one &&
52 test_commit second file two &&
53 test_commit third file three &&
54 test_commit --annotate A file A &&
55 test_commit c file c &&
56
57 git reset --hard second &&
58 test_commit --annotate B side B &&
59
60 test_tick &&
61 git merge -m Merged c &&
62 merged=$(git rev-parse HEAD) &&
63
64 git reset --hard second &&
65 test_commit --no-tag D another D &&
66
67 test_tick &&
68 git tag -a -m R R &&
69
70 test_commit e another DD &&
71 test_commit --no-tag "yet another" another DDD &&
72
73 test_tick &&
74 git merge -m Merged $merged &&
75
76 test_commit --no-tag x file
77 '
78
79 check_describe A-8-gHASH HEAD
80 check_describe A-7-gHASH HEAD^
81 check_describe R-2-gHASH HEAD^^
82 check_describe A-3-gHASH HEAD^^2
83 check_describe B HEAD^^2^
84 check_describe R-1-gHASH HEAD^^^
85 check_describe R-1-gHASH R-1-g$(git rev-parse --short HEAD^^)~1
86
87 check_describe c-7-gHASH --tags HEAD
88 check_describe c-6-gHASH --tags HEAD^
89 check_describe e-1-gHASH --tags HEAD^^
90 check_describe c-2-gHASH --tags HEAD^^2
91 check_describe c-2-gHASH --tags c-2-g$(git rev-parse --short HEAD^^2)^0
92 check_describe B --tags HEAD^^2^
93 check_describe e --tags HEAD^^^
94 check_describe e --tags --exact-match HEAD^^^
95
96 check_describe heads/main --all HEAD
97 check_describe tags/c-6-gHASH --all HEAD^
98 check_describe tags/e --all HEAD^^^
99
100 check_describe B-0-gHASH --long HEAD^^2^
101 check_describe A-3-gHASH --long HEAD^^2
102
103 check_describe c-7-gHASH --tags
104 check_describe e-3-gHASH --first-parent --tags
105
106 check_describe c-7-gHASH --tags --no-exact-match HEAD
107 check_describe e-3-gHASH --first-parent --tags --no-exact-match HEAD
108
109 test_expect_success '--exact-match failure' '
110 test_must_fail git describe --exact-match HEAD 2>err
111 '
112
113 test_expect_success 'describe --contains defaults to HEAD without commit-ish' '
114 echo "A^0" >expect &&
115 git checkout A &&
116 test_when_finished "git checkout -" &&
117 git describe --contains >actual &&
118 test_cmp expect actual
119 '
120
121 check_describe tags/A --all A^0
122
123 test_expect_success 'renaming tag A to Q locally produces a warning' "
124 git update-ref refs/tags/Q $(git rev-parse refs/tags/A) &&
125 git update-ref -d refs/tags/A &&
126 git describe HEAD 2>err >out &&
127 cat >expected <<-\EOF &&
128 warning: tag 'Q' is externally known as 'A'
129 EOF
130 test_cmp expected err &&
131 test_grep -E '^A-8-g[0-9a-f]+$' out
132 "
133
134 test_expect_success 'misnamed annotated tag forces long output' '
135 description=$(git describe --no-long Q^0) &&
136 expr "$description" : "A-0-g[0-9a-f]*$" &&
137 git rev-parse --verify "$description" >actual &&
138 git rev-parse --verify Q^0 >expect &&
139 test_cmp expect actual
140 '
141
142 test_expect_success 'abbrev=0 will not break misplaced tag (1)' '
143 description=$(git describe --abbrev=0 Q^0) &&
144 expr "$description" : "A-0-g[0-9a-f]*$"
145 '
146
147 test_expect_success 'abbrev=0 will not break misplaced tag (2)' '
148 description=$(git describe --abbrev=0 c^0) &&
149 expr "$description" : "A-1-g[0-9a-f]*$"
150 '
151
152 test_expect_success 'rename tag Q back to A' '
153 git update-ref refs/tags/A $(git rev-parse refs/tags/Q) &&
154 git update-ref -d refs/tags/Q
155 '
156
157 test_expect_success 'pack tag refs' 'git pack-refs'
158 check_describe A-8-gHASH HEAD
159
160 test_expect_success 'describe works from outside repo using --git-dir' '
161 git clone --bare "$TRASH_DIRECTORY" "$TRASH_DIRECTORY/bare" &&
162 git --git-dir "$TRASH_DIRECTORY/bare" describe >out &&
163 test_grep -E "^A-8-g[0-9a-f]+$" out
164 '
165
166 check_describe "A-8-gHASH" --dirty
167
168 test_expect_success 'describe --dirty with --work-tree' '
169 (
170 cd "$TEST_DIRECTORY" &&
171 git --git-dir "$TRASH_DIRECTORY/.git" --work-tree "$TRASH_DIRECTORY" describe --dirty >"$TRASH_DIRECTORY/out"
172 ) &&
173 test_grep -E "^A-8-g[0-9a-f]+$" out
174 '
175
176 test_expect_success 'set-up dirty work tree' '
177 echo >>file
178 '
179
180 test_expect_success 'describe --dirty with --work-tree (dirty)' '
181 git describe --dirty >expected &&
182 (
183 cd "$TEST_DIRECTORY" &&
184 git --git-dir "$TRASH_DIRECTORY/.git" --work-tree "$TRASH_DIRECTORY" describe --dirty >"$TRASH_DIRECTORY/out"
185 ) &&
186 test_grep -E "^A-8-g[0-9a-f]+-dirty$" out &&
187 test_cmp expected out
188 '
189
190 test_expect_success 'describe --dirty=.mod with --work-tree (dirty)' '
191 git describe --dirty=.mod >expected &&
192 (
193 cd "$TEST_DIRECTORY" &&
194 git --git-dir "$TRASH_DIRECTORY/.git" --work-tree "$TRASH_DIRECTORY" describe --dirty=.mod >"$TRASH_DIRECTORY/out"
195 ) &&
196 test_grep -E "^A-8-g[0-9a-f]+.mod$" out &&
197 test_cmp expected out
198 '
199
200 test_expect_success 'describe --dirty HEAD' '
201 test_must_fail git describe --dirty HEAD
202 '
203
204 test_expect_success 'set-up matching pattern tests' '
205 git tag -a -m test-annotated test-annotated &&
206 echo >>file &&
207 test_tick &&
208 git commit -a -m "one more" &&
209 git tag test1-lightweight &&
210 echo >>file &&
211 test_tick &&
212 git commit -a -m "yet another" &&
213 git tag test2-lightweight &&
214 echo >>file &&
215 test_tick &&
216 git commit -a -m "even more"
217
218 '
219
220 check_describe "test-annotated-3-gHASH" --match="test-*"
221
222 check_describe "test1-lightweight-2-gHASH" --tags --match="test1-*"
223
224 check_describe "test2-lightweight-1-gHASH" --tags --match="test2-*"
225
226 check_describe "test2-lightweight-0-gHASH" --long --tags --match="test2-*" HEAD^
227
228 check_describe "test2-lightweight-0-gHASH" --long --tags --match="test1-*" --match="test2-*" HEAD^
229
230 check_describe "test2-lightweight-0-gHASH" --long --tags --match="test1-*" --no-match --match="test2-*" HEAD^
231
232 check_describe "test1-lightweight-2-gHASH" --long --tags --match="test1-*" --match="test3-*" HEAD
233
234 check_describe "test1-lightweight-2-gHASH" --long --tags --match="test3-*" --match="test1-*" HEAD
235
236 test_expect_success 'set-up branches' '
237 git branch branch_A A &&
238 git branch branch_C c &&
239 git update-ref refs/remotes/origin/remote_branch_A "A^{commit}" &&
240 git update-ref refs/remotes/origin/remote_branch_C "c^{commit}" &&
241 git update-ref refs/original/original_branch_A test-annotated~2
242 '
243
244 check_describe "heads/branch_A-11-gHASH" --all --match="branch_*" --exclude="branch_C" HEAD
245
246 check_describe "remotes/origin/remote_branch_A-11-gHASH" --all --match="origin/remote_branch_*" --exclude="origin/remote_branch_C" HEAD
247
248 check_describe "original/original_branch_A-6-gHASH" --all test-annotated~1
249
250 test_expect_success '--match does not work for other types' '
251 test_must_fail git describe --all --match="*original_branch_*" test-annotated~1
252 '
253
254 test_expect_success '--exclude does not work for other types' '
255 R=$(git describe --all --exclude="any_pattern_even_not_matching" test-annotated~1) &&
256 case "$R" in
257 *original_branch_A*) echo "fail: Found unknown reference $R with --exclude"
258 false;;
259 *) echo ok: Found some known type;;
260 esac
261 '
262
263 test_expect_success 'name-rev with exact tags' '
264 echo A >expect &&
265 tag_object=$(git rev-parse refs/tags/A) &&
266 git name-rev --tags --name-only $tag_object >actual &&
267 test_cmp expect actual &&
268
269 echo "A^0" >expect &&
270 tagged_commit=$(git rev-parse "refs/tags/A^0") &&
271 git name-rev --tags --name-only $tagged_commit >actual &&
272 test_cmp expect actual
273 '
274
275 test_expect_success 'name-rev --all' '
276 >expect.unsorted &&
277 for rev in $(git rev-list --all)
278 do
279 git name-rev $rev >>expect.unsorted || return 1
280 done &&
281 sort <expect.unsorted >expect &&
282 git name-rev --all >actual.unsorted &&
283 sort <actual.unsorted >actual &&
284 test_cmp expect actual
285 '
286
287 test_expect_success 'name-rev --annotate-stdin' '
288 >expect.unsorted &&
289 for rev in $(git rev-list --all)
290 do
291 name=$(git name-rev --name-only $rev) &&
292 echo "$rev ($name)" >>expect.unsorted || return 1
293 done &&
294 sort <expect.unsorted >expect &&
295 git rev-list --all >list &&
296 git name-rev --annotate-stdin <list >actual.unsorted &&
297 sort <actual.unsorted >actual &&
298 test_cmp expect actual
299 '
300
301 test_expect_success 'name-rev --annotate-stdin --name-only' '
302 >expect.unsorted &&
303 for rev in $(git rev-list --all)
304 do
305 name=$(git name-rev --name-only $rev) &&
306 echo "$name" >>expect.unsorted || return 1
307 done &&
308 sort <expect.unsorted >expect &&
309 git name-rev --annotate-stdin --name-only \
310 <list >actual.unsorted &&
311 sort <actual.unsorted >actual &&
312 test_cmp expect actual
313 '
314
315 test_expect_success 'name-rev --stdin deprecated' '
316 git rev-list --all >list &&
317 if ! test_have_prereq WITH_BREAKING_CHANGES
318 then
319 git name-rev --stdin <list 2>actual &&
320 test_grep "warning: --stdin is deprecated" actual
321 else
322 test_must_fail git name-rev --stdin <list 2>actual &&
323 test_grep "unknown option .stdin." actual
324 fi
325 '
326
327 test_expect_success 'describe --contains with the exact tags' '
328 echo "A^0" >expect &&
329 tag_object=$(git rev-parse refs/tags/A) &&
330 git describe --contains $tag_object >actual &&
331 test_cmp expect actual &&
332
333 echo "A^0" >expect &&
334 tagged_commit=$(git rev-parse "refs/tags/A^0") &&
335 git describe --contains $tagged_commit >actual &&
336 test_cmp expect actual
337 '
338
339 test_expect_success 'describe --contains and --match' '
340 echo "A^0" >expect &&
341 tagged_commit=$(git rev-parse "refs/tags/A^0") &&
342 test_must_fail git describe --contains --match="B" $tagged_commit &&
343 git describe --contains --match="B" --match="A" $tagged_commit >actual &&
344 test_cmp expect actual
345 '
346
347 test_expect_success 'describe --exclude' '
348 echo "c~1" >expect &&
349 tagged_commit=$(git rev-parse "refs/tags/A^0") &&
350 test_must_fail git describe --contains --match="B" $tagged_commit &&
351 git describe --contains --match="?" --exclude="A" $tagged_commit >actual &&
352 test_cmp expect actual
353 '
354
355 test_expect_success 'describe --contains and --no-match' '
356 echo "A^0" >expect &&
357 tagged_commit=$(git rev-parse "refs/tags/A^0") &&
358 git describe --contains --match="B" --no-match $tagged_commit >actual &&
359 test_cmp expect actual
360 '
361
362 test_expect_success 'describe --contains --all --match no matching commit' '
363 echo "tags/A^0" >expect &&
364 tagged_commit=$(git rev-parse "refs/tags/A^0") &&
365 test_must_fail git describe --contains --all --match="B" $tagged_commit
366 '
367
368 check_describe "tags/A^0" --contains --all --match="A" $(git rev-parse "refs/tags/A^0")
369
370 check_describe "branch_A" --contains --all --match="branch*" $(git rev-parse "refs/tags/A^0")
371
372 check_describe "branch_C~1" --contains --all --match="branch*" --exclude="branch_A" $(git rev-parse "refs/tags/A^0")
373
374 check_describe "branch_A" --contains --all \
375 --exclude="A" --exclude="c" --exclude="test*" --exclude="origin/remote_branch_A" \
376 $(git rev-parse "refs/tags/A^0")
377
378 check_describe "remotes/origin/remote_branch_A" --contains --all --match="origin/remote*" $(git rev-parse "refs/tags/A^0")
379
380 check_describe "remotes/origin/remote_branch_C~1" --contains --all \
381 --match="origin/remote*" --exclude="origin/remote_branch_A" \
382 $(git rev-parse "refs/tags/A^0")
383
384 test_expect_success 'setup and absorb a submodule' '
385 test_create_repo sub1 &&
386 test_commit -C sub1 initial &&
387 git submodule add ./sub1 &&
388 git submodule absorbgitdirs &&
389 git commit -a -m "add submodule" &&
390 git describe --dirty >expect &&
391 git describe --broken >out &&
392 test_cmp expect out
393 '
394
395 test_expect_success 'describe chokes on severely broken submodules' '
396 mv .git/modules/sub1/ .git/modules/sub_moved &&
397 test_must_fail git describe --dirty
398 '
399
400 test_expect_success 'describe ignoring a broken submodule' '
401 git describe --broken >out &&
402 test_grep broken out
403 '
404
405 test_expect_success 'describe with --work-tree ignoring a broken submodule' '
406 (
407 cd "$TEST_DIRECTORY" &&
408 git --git-dir "$TRASH_DIRECTORY/.git" --work-tree "$TRASH_DIRECTORY" describe --broken >"$TRASH_DIRECTORY/out"
409 ) &&
410 test_when_finished "mv .git/modules/sub_moved .git/modules/sub1" &&
411 test_grep broken out
412 '
413
414 test_expect_success 'describe a blob at a directly tagged commit' '
415 echo "make it a unique blob" >file &&
416 git add file && git commit -m "content in file" &&
417 git tag -a -m "latest annotated tag" unique-file &&
418 git describe HEAD:file >actual &&
419 echo "unique-file:file" >expect &&
420 test_cmp expect actual
421 '
422
423 test_expect_success 'describe a blob with its first introduction' '
424 git commit --allow-empty -m "empty commit" &&
425 git rm file &&
426 git commit -m "delete blob" &&
427 git revert HEAD &&
428 git commit --allow-empty -m "empty commit" &&
429 git describe HEAD:file >actual &&
430 echo "unique-file:file" >expect &&
431 test_cmp expect actual
432 '
433
434 test_expect_success 'describe directly tagged blob' '
435 git tag test-blob unique-file:file &&
436 git describe test-blob >actual &&
437 echo "unique-file:file" >expect &&
438 # suboptimal: we rather want to see "test-blob"
439 test_cmp expect actual
440 '
441
442 test_expect_success 'describe tag object' '
443 git tag test-blob-1 -a -m msg unique-file:file &&
444 test_must_fail git describe test-blob-1 2>actual &&
445 test_grep "fatal: test-blob-1 is neither a commit nor blob" actual
446 '
447
448 test_expect_success 'describe an unreachable blob' '
449 blob=$(echo not-found-anywhere | git hash-object -w --stdin) &&
450 test_must_fail git describe $blob 2>actual &&
451 test_grep "blob .$blob. not reachable from HEAD" actual
452 '
453
454 test_expect_success 'describe blob on an unborn branch' '
455 oldbranch=$(git symbolic-ref HEAD) &&
456 test_when_finished "git symbolic-ref HEAD $oldbranch" &&
457 git symbolic-ref HEAD refs/heads/does-not-exist &&
458 test_must_fail git describe test-blob 2>actual &&
459 test_grep "cannot search .* on an unborn branch" actual
460 '
461
462 # This test creates a repository state that we generally try to disallow: HEAD
463 # is pointing to an object that is not a commit. The ref update code forbids
464 # non-commit writes directly to HEAD or to any branch in refs/heads/. But we
465 # can use the loophole of pointing HEAD to another non-branch ref (something we
466 # should forbid, but don't for historical reasons).
467 #
468 # Do not take this test as an endorsement of the loophole! If we ever tighten
469 # it, it is reasonable to just drop this test entirely.
470 test_expect_success 'describe blob on a non-commit HEAD' '
471 oldbranch=$(git symbolic-ref HEAD) &&
472 test_when_finished "git symbolic-ref HEAD $oldbranch" &&
473 git symbolic-ref HEAD refs/tags/test-blob &&
474 test_must_fail git describe test-blob 2>actual &&
475 test_grep "blob .* not reachable from HEAD" actual
476 '
477
478 test_expect_success ULIMIT_STACK_SIZE 'name-rev works in a deep repo' '
479 i=1 &&
480 while test $i -lt 8000
481 do
482 echo "commit refs/heads/main
483 committer A U Thor <author@example.com> $((1000000000 + $i * 100)) +0200
484 data <<EOF
485 commit #$i
486 EOF" &&
487 if test $i = 1
488 then
489 echo "from refs/heads/main^0"
490 fi &&
491 i=$(($i + 1)) || return 1
492 done | git fast-import &&
493 git checkout main &&
494 git tag far-far-away HEAD^ &&
495 echo "HEAD~4000 tags/far-far-away~3999" >expect &&
496 git name-rev HEAD~4000 >actual &&
497 test_cmp expect actual &&
498 run_with_limited_stack git name-rev HEAD~4000 >actual &&
499 test_cmp expect actual
500 '
501
502 test_expect_success ULIMIT_STACK_SIZE 'describe works in a deep repo' '
503 git tag -f far-far-away HEAD~7999 &&
504 echo "far-far-away" >expect &&
505 git describe --tags --abbrev=0 HEAD~4000 >actual &&
506 test_cmp expect actual &&
507 run_with_limited_stack git describe --tags --abbrev=0 HEAD~4000 >actual &&
508 test_cmp expect actual
509 '
510
511 check_describe tags/A --all A
512 check_describe tags/c --all c
513 check_describe heads/branch_A --all --match='branch_*' branch_A
514
515 test_expect_success 'describe complains about tree object' '
516 test_must_fail git describe HEAD^{tree}
517 '
518
519 test_expect_success 'describe complains about missing object' '
520 test_must_fail git describe $ZERO_OID
521 '
522
523 test_expect_success 'name-rev a rev shortly after epoch' '
524 test_when_finished "git checkout main" &&
525
526 git checkout --orphan no-timestamp-underflow &&
527 # Any date closer to epoch than the CUTOFF_DATE_SLOP constant
528 # in builtin/name-rev.c.
529 GIT_COMMITTER_DATE="@1234 +0000" \
530 git commit -m "committer date shortly after epoch" &&
531 old_commit_oid=$(git rev-parse HEAD) &&
532
533 echo "$old_commit_oid no-timestamp-underflow" >expect &&
534 git name-rev $old_commit_oid >actual &&
535 test_cmp expect actual
536 '
537
538 # A--------------main
539 # \ /
540 # \----------M2
541 # \ /
542 # \---M1-C
543 # \ /
544 # B
545 test_expect_success 'name-rev covers all conditions while looking at parents' '
546 git init repo &&
547 (
548 cd repo &&
549
550 echo A >file &&
551 git add file &&
552 git commit -m A &&
553 A=$(git rev-parse HEAD) &&
554
555 git checkout --detach &&
556 echo B >file &&
557 git commit -m B file &&
558 B=$(git rev-parse HEAD) &&
559
560 git checkout $A &&
561 git merge --no-ff $B && # M1
562
563 echo C >file &&
564 git commit -m C file &&
565
566 git checkout $A &&
567 git merge --no-ff HEAD@{1} && # M2
568
569 git checkout main &&
570 git merge --no-ff HEAD@{1} &&
571
572 echo "$B main^2^2~1^2" >expect &&
573 git name-rev $B >actual &&
574
575 test_cmp expect actual
576 )
577 '
578
579 # A-B-C-D-E-main
580 #
581 # Where C has a non-monotonically increasing commit timestamp w.r.t. other
582 # commits
583 test_expect_success 'non-monotonic commit dates setup' '
584 UNIX_EPOCH_ZERO="@0 +0000" &&
585 git init non-monotonic &&
586 test_commit -C non-monotonic A &&
587 test_commit -C non-monotonic --no-tag B &&
588 test_commit -C non-monotonic --no-tag --date "$UNIX_EPOCH_ZERO" C &&
589 test_commit -C non-monotonic D &&
590 test_commit -C non-monotonic E
591 '
592
593 test_expect_success 'name-rev with commitGraph handles non-monotonic timestamps' '
594 test_config -C non-monotonic core.commitGraph true &&
595 (
596 cd non-monotonic &&
597
598 git commit-graph write --reachable &&
599
600 echo "main~3 tags/D~2" >expect &&
601 git name-rev --tags main~3 >actual &&
602
603 test_cmp expect actual
604 )
605 '
606
607 test_expect_success 'name-rev --all works with non-monotonic timestamps' '
608 test_config -C non-monotonic core.commitGraph false &&
609 (
610 cd non-monotonic &&
611
612 rm -rf .git/info/commit-graph* &&
613
614 cat >tags <<-\EOF &&
615 tags/E
616 tags/D
617 tags/D~1
618 tags/D~2
619 tags/A
620 EOF
621
622 git log --pretty=%H >revs &&
623
624 paste -d" " revs tags | sort >expect &&
625
626 git name-rev --tags --all | sort >actual &&
627 test_cmp expect actual
628 )
629 '
630
631 test_expect_success 'name-rev --annotate-stdin works with non-monotonic timestamps' '
632 test_config -C non-monotonic core.commitGraph false &&
633 (
634 cd non-monotonic &&
635
636 rm -rf .git/info/commit-graph* &&
637
638 cat >expect <<-\EOF &&
639 E
640 D
641 D~1
642 D~2
643 A
644 EOF
645
646 git log --pretty=%H >revs &&
647 git name-rev --tags --annotate-stdin --name-only <revs >actual &&
648 test_cmp expect actual
649 )
650 '
651
652 test_expect_success 'name-rev --all works with commitGraph' '
653 test_config -C non-monotonic core.commitGraph true &&
654 (
655 cd non-monotonic &&
656
657 git commit-graph write --reachable &&
658
659 cat >tags <<-\EOF &&
660 tags/E
661 tags/D
662 tags/D~1
663 tags/D~2
664 tags/A
665 EOF
666
667 git log --pretty=%H >revs &&
668
669 paste -d" " revs tags | sort >expect &&
670
671 git name-rev --tags --all | sort >actual &&
672 test_cmp expect actual
673 )
674 '
675
676 test_expect_success 'name-rev --annotate-stdin works with commitGraph' '
677 test_config -C non-monotonic core.commitGraph true &&
678 (
679 cd non-monotonic &&
680
681 git commit-graph write --reachable &&
682
683 cat >expect <<-\EOF &&
684 E
685 D
686 D~1
687 D~2
688 A
689 EOF
690
691 git log --pretty=%H >revs &&
692 git name-rev --tags --annotate-stdin --name-only <revs >actual &&
693 test_cmp expect actual
694 )
695 '
696
697 # B
698 # o
699 # H \
700 # o-----o---o----x
701 # A
702 #
703 test_expect_success 'setup: describe commits with disjoint bases' '
704 git init disjoint1 &&
705 (
706 cd disjoint1 &&
707
708 echo o >> file && git add file && git commit -m o &&
709 git tag H -a -m H &&
710 echo A >> file && git add file && git commit -m A &&
711 git tag A -a -m A &&
712 echo o >> file && git add file && git commit -m o &&
713
714 git checkout --orphan branch && rm file &&
715 echo B > file2 && git add file2 && git commit -m B &&
716 git tag B -a -m B &&
717 git merge --no-ff --allow-unrelated-histories main -m x
718 )
719 '
720
721 check_describe -C disjoint1 "A-3-gHASH" HEAD
722 check_describe -C disjoint1 --expect-failure "A-3-gHASH" --candidates=2 HEAD
723
724 # H B
725 # o---o---o------------.
726 # \
727 # o---o---x
728 # A
729 #
730 test_expect_success 'setup: describe commits with disjoint bases 2' '
731 git init disjoint2 &&
732 (
733 cd disjoint2 &&
734
735 echo A >> file && git add file && GIT_COMMITTER_DATE="2020-01-01 18:00" git commit -m A &&
736 git tag A -a -m A &&
737 echo o >> file && git add file && GIT_COMMITTER_DATE="2020-01-01 18:01" git commit -m o &&
738
739 git checkout --orphan branch &&
740 echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:00" git commit -m o &&
741 echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:01" git commit -m o &&
742 git tag H -a -m H &&
743 echo B >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:02" git commit -m B &&
744 git tag B -a -m B &&
745 git merge --no-ff --allow-unrelated-histories main -m x
746 )
747 '
748
749 check_describe -C disjoint2 "B-3-gHASH" HEAD
750 check_describe -C disjoint2 --expect-failure "B-3-gHASH" --candidates=2 HEAD
751
752 test_expect_success 'setup misleading taggerdates' '
753 GIT_COMMITTER_DATE="2006-12-12 12:31" git tag -a -m "another tag" newer-tag-older-commit unique-file~1
754 '
755
756 check_describe newer-tag-older-commit~1 --contains unique-file~2
757
758 test_expect_success 'describe --dirty with a file with changed stat' '
759 test_when_finished "rm -fr stat-dirty" &&
760 git init stat-dirty &&
761 (
762 cd stat-dirty &&
763
764 echo A >file &&
765 git add file &&
766 git commit -m A &&
767 git tag A -a -m A &&
768 echo "A" >expect &&
769
770 test-tool chmtime -10 file &&
771 git describe --dirty >actual &&
772 test_cmp expect actual
773 )
774 '
775
776 test_expect_success 'describe --broken --dirty with a file with changed stat' '
777 test_when_finished "rm -fr stat-dirty" &&
778 git init stat-dirty &&
779 (
780 cd stat-dirty &&
781
782 echo A >file &&
783 git add file &&
784 git commit -m A &&
785 git tag A -a -m A &&
786 echo "A" >expect &&
787
788 test-tool chmtime -10 file &&
789 git describe --dirty --broken >actual &&
790 test_cmp expect actual
791 )
792 '
793
794 test_expect_success '--always with no refs falls back to commit hash' '
795 git rev-parse HEAD >expect &&
796 git describe --no-abbrev --always --match=no-such-tag >actual &&
797 test_cmp expect actual
798 '
799
800 test_expect_success '--exact-match does not show --always fallback' '
801 test_must_fail git describe --exact-match --always
802 '
803
804 test_expect_success 'avoid being fooled by describe-like filename' '
805 test_when_finished rm out &&
806
807 git rev-parse --short HEAD >out &&
808 FILENAME=filename-g$(cat out) &&
809 touch $FILENAME &&
810 git add $FILENAME &&
811 git commit -m "Add $FILENAME" &&
812
813 git cat-file -t HEAD:$FILENAME >actual &&
814
815 echo blob >expect &&
816 test_cmp expect actual
817 '
818
819 test_expect_success 'do not be fooled by invalid describe format ' '
820 test_when_finished rm out &&
821
822 git rev-parse --short HEAD >out &&
823 test_must_fail git cat-file -t "refs/tags/super-invalid/./../...../ ~^:/?*[////\\\\\\&}/busted.lock-42-g"$(cat out)
824 '
825
826 test_expect_success 'setup: format-rev' '
827 mkdir repo-format &&
828 git -C repo-format init &&
829 test_commit -C repo-format first &&
830 test_commit -C repo-format second &&
831 test_commit -C repo-format third &&
832 test_commit -C repo-format fourth &&
833 test_commit -C repo-format fifth &&
834 test_commit -C repo-format sixth &&
835 test_commit -C repo-format seventh &&
836 test_commit -C repo-format eighth
837 '
838
839 test_expect_success 'format-rev --stdin-mode=revs' '
840 cat >expect <<-\EOF &&
841 eighth
842 seventh
843 fifth
844 EOF
845 git -C repo-format format-rev --stdin-mode=revs \
846 --format=%s >actual <<-\EOF &&
847 HEAD
848 HEAD~
849 HEAD~3
850 EOF
851 test_cmp expect actual
852 '
853
854 test_expect_success 'format-rev --stdin-mode=text from rev-list same as log' '
855 git -C repo-format log --format=reference >expect &&
856 test_file_not_empty expect &&
857 git -C repo-format rev-list HEAD >list &&
858 git -C repo-format format-rev --stdin-mode=text \
859 --format=reference <list >actual &&
860 test_cmp expect actual
861 '
862
863 test_expect_success 'format-rev --stdin-mode=text with running text and tree oid' '
864 cmit_oid=$(git -C repo-format rev-parse fifth) &&
865 reference=$(git -C repo-format log -n1 --format=reference fifth) &&
866 tree=$(git -C repo-format rev-parse HEAD^{tree}) &&
867 cat >expect <<-EOF &&
868 We thought we fixed this in ${reference}.
869 But look at this tree: ${tree}.
870 EOF
871 git -C repo-format format-rev --stdin-mode=text --format=reference \
872 >actual <<-EOF &&
873 We thought we fixed this in ${cmit_oid}.
874 But look at this tree: ${tree}.
875 EOF
876 test_cmp expect actual
877 '
878
879 test_expect_success 'format-rev with %N (note)' '
880 test_when_finished "git -C repo-format notes remove" &&
881 git -C repo-format notes add -m"Make a note" &&
882 printf "Make a note\n\n\n" >expect &&
883 git -C repo-format format-rev --stdin-mode=revs \
884 --format="tformat:%N" \
885 >actual <<-\EOF &&
886 HEAD
887 HEAD~
888 EOF
889 test_cmp expect actual
890 '
891
892 test_expect_success 'format-rev --notes<ref> (custom notes ref)' '
893 # One custom notes ref
894 test_when_finished "git -C repo-format notes remove" &&
895 test_when_finished "git -C repo-format notes --ref=word remove" &&
896 git -C repo-format notes add -m"default" &&
897 git -C repo-format notes --ref=word add -m"custom" &&
898 printf "custom\n\n" >expect &&
899 git -C repo-format format-rev --stdin-mode=revs \
900 --format="tformat:%N" \
901 --notes=word \
902 >actual <<-\EOF &&
903 HEAD
904 EOF
905 test_cmp expect actual &&
906 # Glob all
907 printf "default\ncustom\n\n" >expect &&
908 git -C repo-format format-rev --stdin-mode=revs \
909 --format="tformat:%N" \
910 --notes=* >actual <<-\EOF &&
911 HEAD
912 EOF
913 test_cmp expect actual
914 '
915
916 test_expect_success 'format-rev --stdin-mode=revs on annotated tag peels to commit' '
917 test_when_finished "git -C repo-format tag -d version" &&
918 git -C repo-format tag -a -m"new version" version &&
919 cat >expect <<-\EOF &&
920 eighth
921 EOF
922 git -C repo-format format-rev --stdin-mode=revs \
923 --format=%s \
924 >actual <<-\EOF &&
925 version
926 EOF
927 test_cmp expect actual
928 '
929
930 test_expect_success 'format-rev --stdin-mode=revs lookup failures' '
931 test_when_finished "git -C repo-format tag -d tag-to-tree" &&
932 invalid_syntax=not-valid &&
933 non_existing_oid=${EMPTY_BLOB} &&
934 tree=$(git -C repo-format rev-parse eighth^{tree}) &&
935 git -C repo-format tag -a -mmessage tag-to-tree "$tree" &&
936 tag_to_tree=$(git -C repo-format rev-parse tag-to-tree) &&
937 cat >expect <<-EOF &&
938 Could not get object name for ${invalid_syntax}. Skipping.
939 Could not get object for ${non_existing_oid}. Skipping.
940 Could not get commit for ${tree}. Skipping.
941 Could not get commit for ${tag_to_tree}. Skipping.
942 EOF
943 git -C repo-format format-rev --stdin-mode=revs \
944 --format=%s \
945 2>actual >out <<-EOF &&
946 ${invalid_syntax}
947 ${non_existing_oid}
948 ${tree}
949 ${tag_to_tree}
950 EOF
951 test_line_count = 0 out &&
952 test_cmp expect actual
953 '
954
955
956 test_expect_success 'format-rev -z --stdin-mode=text with object name lookup failures' '
957 printf "%s\0" "$(git -C repo-format rev-parse HEAD)" >input &&
958 printf "%s\0" "$(git -C repo-format rev-parse HEAD^{tree})" >>input &&
959 printf "%s\0" "$EMPTY_BLOB" >>input &&
960 printf "%s\0" "$(git -C repo-format log --format=%s -1)" >expect &&
961 printf "%s\0" "$(git -C repo-format rev-parse HEAD^{tree})" >>expect &&
962 printf "%s\0" "$EMPTY_BLOB" >>expect &&
963 git -C repo-format format-rev --stdin-mode=text \
964 --format=%s -z <input >actual &&
965 test_cmp expect actual
966 '
967
968 test_expect_success 'setup: format-rev input and output separators' '
969 git -C repo-format rev-list HEAD >input-lf &&
970 git -C repo-format rev-list -z HEAD >input-nul &&
971 git -C repo-format log --format=%s >output-lf &&
972 git -C repo-format log -z --format=%s >output-nul &&
973 echo revs >stdin-modes &&
974 echo text >>stdin-modes
975 '
976
977 while read mode
978 do
979 test_expect_success "format-rev -z --stdin-mode=$mode" '
980 cat output-nul >expect &&
981 git -C repo-format format-rev --stdin-mode="$mode" \
982 --format=%s -z <input-nul >actual &&
983 test_cmp expect actual
984 '
985
986 test_expect_success "format-rev -z --no-null-input --no-null-output --stdin-mode=$mode" '
987 cat output-lf >expect &&
988 git -C repo-format format-rev --stdin-mode="$mode" \
989 --format=%s -z --no-null-input --no-null-output \
990 <input-lf >actual &&
991 test_cmp expect actual
992 '
993
994 test_expect_success "format-rev ---null-input --stdin-mode=$mode" '
995 cat output-lf >expect &&
996 git -C repo-format format-rev --stdin-mode="$mode" \
997 --format=%s --null-input \
998 <input-nul >actual &&
999 test_cmp expect actual
1000 '
1001
1002 test_expect_success "format-rev --null-output --stdin-mode=$mode" '
1003 cat output-nul >expect &&
1004 git -C repo-format format-rev --stdin-mode="$mode" \
1005 --format=%s --null-output \
1006 <input-lf >actual &&
1007 test_cmp expect actual
1008 '
1009
1010 test_expect_success "format-rev -z --stdin-mode=$mode with multi-line output" '
1011 format="%s%n%aI" &&
1012 git -C repo-format log -z --format="$format" \
1013 >expect &&
1014 git -C repo-format format-rev --stdin-mode="$mode" \
1015 --format="$format" -z <input-nul >actual &&
1016 test_cmp expect actual
1017 '
1018 done <stdin-modes
1019
1020 test_done