The eighth batch
[alt-git.git] / t / t0610-reftable-basics.sh
blobb06c46999d85559e4b26a777aa319937fc10458e
1 #!/bin/sh
3 # Copyright (c) 2020 Google LLC
6 test_description='reftable basics'
8 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
9 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
10 GIT_TEST_DEFAULT_REF_FORMAT=reftable
11 export GIT_TEST_DEFAULT_REF_FORMAT
13 TEST_PASSES_SANITIZE_LEAK=true
14 . ./test-lib.sh
16 INVALID_OID=$(test_oid 001)
18 test_expect_success 'init: creates basic reftable structures' '
19 test_when_finished "rm -rf repo" &&
20 git init repo &&
21 test_path_is_dir repo/.git/reftable &&
22 test_path_is_file repo/.git/reftable/tables.list &&
23 echo reftable >expect &&
24 git -C repo rev-parse --show-ref-format >actual &&
25 test_cmp expect actual
28 test_expect_success 'init: sha256 object format via environment variable' '
29 test_when_finished "rm -rf repo" &&
30 GIT_DEFAULT_HASH=sha256 git init repo &&
31 cat >expect <<-EOF &&
32 sha256
33 reftable
34 EOF
35 git -C repo rev-parse --show-object-format --show-ref-format >actual &&
36 test_cmp expect actual
39 test_expect_success 'init: sha256 object format via option' '
40 test_when_finished "rm -rf repo" &&
41 git init --object-format=sha256 repo &&
42 cat >expect <<-EOF &&
43 sha256
44 reftable
45 EOF
46 git -C repo rev-parse --show-object-format --show-ref-format >actual &&
47 test_cmp expect actual
50 test_expect_success 'init: reinitializing reftable backend succeeds' '
51 test_when_finished "rm -rf repo" &&
52 git init repo &&
53 test_commit -C repo A &&
55 git -C repo for-each-ref >expect &&
56 git init --ref-format=reftable repo &&
57 git -C repo for-each-ref >actual &&
58 test_cmp expect actual
61 test_expect_success 'init: reinitializing files with reftable backend fails' '
62 test_when_finished "rm -rf repo" &&
63 git init --ref-format=files repo &&
64 test_commit -C repo file &&
66 cp repo/.git/HEAD expect &&
67 test_must_fail git init --ref-format=reftable repo &&
68 test_cmp expect repo/.git/HEAD
71 test_expect_success 'init: reinitializing reftable with files backend fails' '
72 test_when_finished "rm -rf repo" &&
73 git init --ref-format=reftable repo &&
74 test_commit -C repo file &&
76 cp repo/.git/HEAD expect &&
77 test_must_fail git init --ref-format=files repo &&
78 test_cmp expect repo/.git/HEAD
81 test_expect_perms () {
82 local perms="$1" &&
83 local file="$2" &&
84 local actual="$(ls -l "$file")" &&
86 case "$actual" in
87 $perms*)
88 : happy
91 echo "$(basename $2) is not $perms but $actual"
92 false
94 esac
97 test_expect_reftable_perms () {
98 local umask="$1"
99 local shared="$2"
100 local expect="$3"
102 test_expect_success POSIXPERM "init: honors --shared=$shared with umask $umask" '
103 test_when_finished "rm -rf repo" &&
105 umask $umask &&
106 git init --shared=$shared repo
107 ) &&
108 test_expect_perms "$expect" repo/.git/reftable/tables.list &&
109 for table in repo/.git/reftable/*.ref
111 test_expect_perms "$expect" "$table" ||
112 return 1
113 done
116 test_expect_success POSIXPERM "pack-refs: honors --shared=$shared with umask $umask" '
117 test_when_finished "rm -rf repo" &&
119 umask $umask &&
120 git init --shared=$shared repo &&
121 test_commit -C repo A &&
122 test_line_count = 2 repo/.git/reftable/tables.list &&
123 git -C repo pack-refs
124 ) &&
125 test_expect_perms "$expect" repo/.git/reftable/tables.list &&
126 for table in repo/.git/reftable/*.ref
128 test_expect_perms "$expect" "$table" ||
129 return 1
130 done
134 test_expect_reftable_perms 002 umask "-rw-rw-r--"
135 test_expect_reftable_perms 022 umask "-rw-r--r--"
136 test_expect_reftable_perms 027 umask "-rw-r-----"
138 test_expect_reftable_perms 002 group "-rw-rw-r--"
139 test_expect_reftable_perms 022 group "-rw-rw-r--"
140 test_expect_reftable_perms 027 group "-rw-rw----"
142 test_expect_reftable_perms 002 world "-rw-rw-r--"
143 test_expect_reftable_perms 022 world "-rw-rw-r--"
144 test_expect_reftable_perms 027 world "-rw-rw-r--"
146 test_expect_success 'clone: can clone reftable repository' '
147 test_when_finished "rm -rf repo clone" &&
148 git init repo &&
149 test_commit -C repo message1 file1 &&
151 git clone repo cloned &&
152 echo reftable >expect &&
153 git -C cloned rev-parse --show-ref-format >actual &&
154 test_cmp expect actual &&
155 test_path_is_file cloned/file1
158 test_expect_success 'clone: can clone reffiles into reftable repository' '
159 test_when_finished "rm -rf reffiles reftable" &&
160 git init --ref-format=files reffiles &&
161 test_commit -C reffiles A &&
162 git clone --ref-format=reftable ./reffiles reftable &&
164 git -C reffiles rev-parse HEAD >expect &&
165 git -C reftable rev-parse HEAD >actual &&
166 test_cmp expect actual &&
168 git -C reftable rev-parse --show-ref-format >actual &&
169 echo reftable >expect &&
170 test_cmp expect actual &&
172 git -C reffiles rev-parse --show-ref-format >actual &&
173 echo files >expect &&
174 test_cmp expect actual
177 test_expect_success 'clone: can clone reftable into reffiles repository' '
178 test_when_finished "rm -rf reffiles reftable" &&
179 git init --ref-format=reftable reftable &&
180 test_commit -C reftable A &&
181 git clone --ref-format=files ./reftable reffiles &&
183 git -C reftable rev-parse HEAD >expect &&
184 git -C reffiles rev-parse HEAD >actual &&
185 test_cmp expect actual &&
187 git -C reftable rev-parse --show-ref-format >actual &&
188 echo reftable >expect &&
189 test_cmp expect actual &&
191 git -C reffiles rev-parse --show-ref-format >actual &&
192 echo files >expect &&
193 test_cmp expect actual
196 test_expect_success 'ref transaction: corrupted tables cause failure' '
197 test_when_finished "rm -rf repo" &&
198 git init repo &&
200 cd repo &&
201 test_commit file1 &&
202 for f in .git/reftable/*.ref
204 : >"$f" || return 1
205 done &&
206 test_must_fail git update-ref refs/heads/main HEAD
210 test_expect_success 'ref transaction: corrupted tables.list cause failure' '
211 test_when_finished "rm -rf repo" &&
212 git init repo &&
214 cd repo &&
215 test_commit file1 &&
216 echo garbage >.git/reftable/tables.list &&
217 test_must_fail git update-ref refs/heads/main HEAD
221 test_expect_success 'ref transaction: refuses to write ref causing F/D conflict' '
222 test_when_finished "rm -rf repo" &&
223 git init repo &&
224 test_commit -C repo file &&
225 test_must_fail git -C repo update-ref refs/heads/main/forbidden
228 test_expect_success 'ref transaction: deleting ref with invalid name fails' '
229 test_when_finished "rm -rf repo" &&
230 git init repo &&
231 test_commit -C repo file &&
232 test_must_fail git -C repo update-ref -d ../../my-private-file
235 test_expect_success 'ref transaction: can skip object ID verification' '
236 test_when_finished "rm -rf repo" &&
237 git init repo &&
238 test_must_fail test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID 0 &&
239 test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION
242 test_expect_success 'ref transaction: updating same ref multiple times fails' '
243 test_when_finished "rm -rf repo" &&
244 git init repo &&
245 test_commit -C repo A &&
246 cat >updates <<-EOF &&
247 update refs/heads/main $A
248 update refs/heads/main $A
250 cat >expect <<-EOF &&
251 fatal: multiple updates for ref ${SQ}refs/heads/main${SQ} not allowed
253 test_must_fail git -C repo update-ref --stdin <updates 2>err &&
254 test_cmp expect err
257 test_expect_success 'ref transaction: can delete symbolic self-reference with git-symbolic-ref(1)' '
258 test_when_finished "rm -rf repo" &&
259 git init repo &&
260 git -C repo symbolic-ref refs/heads/self refs/heads/self &&
261 git -C repo symbolic-ref -d refs/heads/self
264 test_expect_success 'ref transaction: deleting symbolic self-reference without --no-deref fails' '
265 test_when_finished "rm -rf repo" &&
266 git init repo &&
267 git -C repo symbolic-ref refs/heads/self refs/heads/self &&
268 cat >expect <<-EOF &&
269 error: multiple updates for ${SQ}refs/heads/self${SQ} (including one via symref ${SQ}refs/heads/self${SQ}) are not allowed
271 test_must_fail git -C repo update-ref -d refs/heads/self 2>err &&
272 test_cmp expect err
275 test_expect_success 'ref transaction: deleting symbolic self-reference with --no-deref succeeds' '
276 test_when_finished "rm -rf repo" &&
277 git init repo &&
278 git -C repo symbolic-ref refs/heads/self refs/heads/self &&
279 git -C repo update-ref -d --no-deref refs/heads/self
282 test_expect_success 'ref transaction: creating symbolic ref fails with F/D conflict' '
283 test_when_finished "rm -rf repo" &&
284 git init repo &&
285 test_commit -C repo A &&
286 cat >expect <<-EOF &&
287 error: ${SQ}refs/heads/main${SQ} exists; cannot create ${SQ}refs/heads${SQ}
289 test_must_fail git -C repo symbolic-ref refs/heads refs/heads/foo 2>err &&
290 test_cmp expect err
293 test_expect_success 'ref transaction: ref deletion' '
294 test_when_finished "rm -rf repo" &&
295 git init repo &&
297 cd repo &&
298 test_commit file &&
299 HEAD_OID=$(git show-ref -s --verify HEAD) &&
300 cat >expect <<-EOF &&
301 $HEAD_OID refs/heads/main
302 $HEAD_OID refs/tags/file
304 git show-ref >actual &&
305 test_cmp expect actual &&
307 test_must_fail git update-ref -d refs/tags/file $INVALID_OID &&
308 git show-ref >actual &&
309 test_cmp expect actual &&
311 git update-ref -d refs/tags/file $HEAD_OID &&
312 echo "$HEAD_OID refs/heads/main" >expect &&
313 git show-ref >actual &&
314 test_cmp expect actual
318 test_expect_success 'ref transaction: writes cause auto-compaction' '
319 test_when_finished "rm -rf repo" &&
321 git init repo &&
322 test_line_count = 1 repo/.git/reftable/tables.list &&
324 test_commit -C repo --no-tag A &&
325 test_line_count = 1 repo/.git/reftable/tables.list &&
327 test_commit -C repo --no-tag B &&
328 test_line_count = 1 repo/.git/reftable/tables.list
331 test_expect_success 'ref transaction: env var disables compaction' '
332 test_when_finished "rm -rf repo" &&
334 git init repo &&
335 test_commit -C repo A &&
337 start=$(wc -l <repo/.git/reftable/tables.list) &&
338 iterations=5 &&
339 expected=$((start + iterations)) &&
341 for i in $(test_seq $iterations)
343 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
344 git -C repo update-ref branch-$i HEAD || return 1
345 done &&
346 test_line_count = $expected repo/.git/reftable/tables.list &&
348 git -C repo update-ref foo HEAD &&
349 test_line_count -lt $expected repo/.git/reftable/tables.list
352 test_expect_success 'ref transaction: alternating table sizes are compacted' '
353 test_when_finished "rm -rf repo" &&
355 git init repo &&
356 test_commit -C repo A &&
357 for i in $(test_seq 5)
359 git -C repo branch -f foo &&
360 git -C repo branch -d foo || return 1
361 done &&
362 test_line_count = 2 repo/.git/reftable/tables.list
365 check_fsync_events () {
366 local trace="$1" &&
367 shift &&
369 cat >expect &&
370 sed -n \
371 -e '/^{"event":"counter",.*"category":"fsync",/ {
372 s/.*"category":"fsync",//;
373 s/}$//;
375 }' \
376 <"$trace" >actual &&
377 test_cmp expect actual
380 test_expect_success 'ref transaction: writes are synced' '
381 test_when_finished "rm -rf repo" &&
382 git init repo &&
383 test_commit -C repo initial &&
385 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
386 GIT_TEST_FSYNC=true \
387 git -C repo -c core.fsync=reference \
388 -c core.fsyncMethod=fsync update-ref refs/heads/branch HEAD &&
389 check_fsync_events trace2.txt <<-EOF
390 "name":"hardware-flush","count":4
394 test_expect_success 'ref transaction: empty transaction in empty repo' '
395 test_when_finished "rm -rf repo" &&
396 git init repo &&
397 test_commit -C repo --no-tag A &&
398 git -C repo update-ref -d refs/heads/main &&
399 test-tool -C repo ref-store main delete-refs REF_NO_DEREF msg HEAD &&
400 git -C repo update-ref --stdin <<-EOF
401 prepare
402 commit
406 test_expect_success 'ref transaction: fails gracefully when auto compaction fails' '
407 test_when_finished "rm -rf repo" &&
408 git init repo &&
410 cd repo &&
412 test_commit A &&
413 for i in $(test_seq 10)
415 git branch branch-$i &&
416 for table in .git/reftable/*.ref
418 touch "$table.lock" || exit 1
419 done ||
420 exit 1
421 done &&
422 test_line_count = 10 .git/reftable/tables.list
426 test_expect_success 'pack-refs: compacts tables' '
427 test_when_finished "rm -rf repo" &&
428 git init repo &&
430 test_commit -C repo A &&
431 ls -1 repo/.git/reftable >table-files &&
432 test_line_count = 3 table-files &&
433 test_line_count = 2 repo/.git/reftable/tables.list &&
435 git -C repo pack-refs &&
436 ls -1 repo/.git/reftable >table-files &&
437 test_line_count = 2 table-files &&
438 test_line_count = 1 repo/.git/reftable/tables.list
441 test_expect_success 'pack-refs: compaction raises locking errors' '
442 test_when_finished "rm -rf repo" &&
443 git init repo &&
444 test_commit -C repo A &&
445 touch repo/.git/reftable/tables.list.lock &&
446 cat >expect <<-EOF &&
447 error: unable to compact stack: data is locked
449 test_must_fail git -C repo pack-refs 2>err &&
450 test_cmp expect err
453 for command in pack-refs gc "maintenance run --task=pack-refs"
455 test_expect_success "$command: auto compaction" '
456 test_when_finished "rm -rf repo" &&
457 git init repo &&
459 cd repo &&
461 test_commit A &&
463 # We need a bit of setup to ensure that git-gc(1) actually
464 # triggers, and that it does not write anything to the refdb.
465 git config gc.auto 1 &&
466 git config gc.autoDetach 0 &&
467 git config gc.reflogExpire never &&
468 git config gc.reflogExpireUnreachable never &&
469 test_oid blob17_1 | git hash-object -w --stdin &&
471 # The tables should have been auto-compacted, and thus auto
472 # compaction should not have to do anything.
473 ls -1 .git/reftable >tables-expect &&
474 test_line_count = 3 tables-expect &&
475 git $command --auto &&
476 ls -1 .git/reftable >tables-actual &&
477 test_cmp tables-expect tables-actual &&
479 test_oid blob17_2 | git hash-object -w --stdin &&
481 # Lock all tables write some refs. Auto-compaction will be
482 # unable to compact tables and thus fails gracefully, leaving
483 # the stack in a sub-optimal state.
484 ls .git/reftable/*.ref |
485 while read table
487 touch "$table.lock" || exit 1
488 done &&
489 git branch B &&
490 git branch C &&
491 rm .git/reftable/*.lock &&
492 test_line_count = 4 .git/reftable/tables.list &&
494 git $command --auto &&
495 test_line_count = 1 .git/reftable/tables.list
498 done
500 test_expect_success 'pack-refs: prunes stale tables' '
501 test_when_finished "rm -rf repo" &&
502 git init repo &&
503 touch repo/.git/reftable/stale-table.ref &&
504 git -C repo pack-refs &&
505 test_path_is_missing repo/.git/reftable/stable-ref.ref
508 test_expect_success 'pack-refs: does not prune non-table files' '
509 test_when_finished "rm -rf repo" &&
510 git init repo &&
511 touch repo/.git/reftable/garbage &&
512 git -C repo pack-refs &&
513 test_path_is_file repo/.git/reftable/garbage
516 test_expect_success 'packed-refs: writes are synced' '
517 test_when_finished "rm -rf repo" &&
518 git init repo &&
519 test_commit -C repo initial &&
520 test_line_count = 2 table-files &&
522 : >trace2.txt &&
523 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
524 GIT_TEST_FSYNC=true \
525 git -C repo -c core.fsync=reference \
526 -c core.fsyncMethod=fsync pack-refs &&
527 check_fsync_events trace2.txt <<-EOF
528 "name":"hardware-flush","count":2
532 test_expect_success 'ref iterator: bogus names are flagged' '
533 test_when_finished "rm -rf repo" &&
534 git init repo &&
536 cd repo &&
537 test_commit --no-tag file &&
538 test-tool ref-store main update-ref msg "refs/heads/bogus..name" $(git rev-parse HEAD) $ZERO_OID REF_SKIP_REFNAME_VERIFICATION &&
540 cat >expect <<-EOF &&
541 $ZERO_OID refs/heads/bogus..name 0xc
542 $(git rev-parse HEAD) refs/heads/main 0x0
544 test-tool ref-store main for-each-ref "" >actual &&
545 test_cmp expect actual
549 test_expect_success 'ref iterator: missing object IDs are not flagged' '
550 test_when_finished "rm -rf repo" &&
551 git init repo &&
553 cd repo &&
554 test-tool ref-store main update-ref msg "refs/heads/broken-hash" $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION &&
556 cat >expect <<-EOF &&
557 $INVALID_OID refs/heads/broken-hash 0x0
559 test-tool ref-store main for-each-ref "" >actual &&
560 test_cmp expect actual
564 test_expect_success 'basic: commit and list refs' '
565 test_when_finished "rm -rf repo" &&
566 git init repo &&
567 test_commit -C repo file &&
568 test_write_lines refs/heads/main refs/tags/file >expect &&
569 git -C repo for-each-ref --format="%(refname)" >actual &&
570 test_cmp actual expect
573 test_expect_success 'basic: can write large commit message' '
574 test_when_finished "rm -rf repo" &&
575 git init repo &&
576 perl -e "
577 print \"this is a long commit message\" x 50000
578 " >commit-msg &&
579 git -C repo commit --allow-empty --file=../commit-msg
582 test_expect_success 'basic: show-ref fails with empty repository' '
583 test_when_finished "rm -rf repo" &&
584 git init repo &&
585 test_must_fail git -C repo show-ref >actual &&
586 test_must_be_empty actual
589 test_expect_success 'basic: can check out unborn branch' '
590 test_when_finished "rm -rf repo" &&
591 git init repo &&
592 git -C repo checkout -b main
595 test_expect_success 'basic: peeled tags are stored' '
596 test_when_finished "rm -rf repo" &&
597 git init repo &&
598 test_commit -C repo file &&
599 git -C repo tag -m "annotated tag" test_tag HEAD &&
600 for ref in refs/heads/main refs/tags/file refs/tags/test_tag refs/tags/test_tag^{}
602 echo "$(git -C repo rev-parse "$ref") $ref" || return 1
603 done >expect &&
604 git -C repo show-ref -d >actual &&
605 test_cmp expect actual
608 test_expect_success 'basic: for-each-ref can print symrefs' '
609 test_when_finished "rm -rf repo" &&
610 git init repo &&
612 cd repo &&
613 test_commit file &&
614 git branch &&
615 git symbolic-ref refs/heads/sym refs/heads/main &&
616 cat >expected <<-EOF &&
617 refs/heads/main
619 git for-each-ref --format="%(symref)" refs/heads/sym >actual &&
620 test_cmp expected actual
624 test_expect_success 'basic: notes' '
625 test_when_finished "rm -rf repo" &&
626 git init repo &&
628 write_script fake_editor <<-\EOF &&
629 echo "$MSG" >"$1"
630 echo "$MSG" >&2
633 test_commit 1st &&
634 test_commit 2nd &&
635 GIT_EDITOR=./fake_editor MSG=b4 git notes add &&
636 GIT_EDITOR=./fake_editor MSG=b3 git notes edit &&
637 echo b4 >expect &&
638 git notes --ref commits@{1} show >actual &&
639 test_cmp expect actual
643 test_expect_success 'basic: stash' '
644 test_when_finished "rm -rf repo" &&
645 git init repo &&
647 cd repo &&
648 test_commit file &&
649 git stash list >expect &&
650 test_line_count = 0 expect &&
652 echo hoi >>file.t &&
653 git stash push -m stashed &&
654 git stash list >expect &&
655 test_line_count = 1 expect &&
657 git stash clear &&
658 git stash list >expect &&
659 test_line_count = 0 expect
663 test_expect_success 'basic: cherry-pick' '
664 test_when_finished "rm -rf repo" &&
665 git init repo &&
667 cd repo &&
668 test_commit message1 file1 &&
669 test_commit message2 file2 &&
670 git branch source &&
671 git checkout HEAD^ &&
672 test_commit message3 file3 &&
673 git cherry-pick source &&
674 test_path_is_file file2
678 test_expect_success 'basic: rebase' '
679 test_when_finished "rm -rf repo" &&
680 git init repo &&
682 cd repo &&
683 test_commit message1 file1 &&
684 test_commit message2 file2 &&
685 git branch source &&
686 git checkout HEAD^ &&
687 test_commit message3 file3 &&
688 git rebase source &&
689 test_path_is_file file2
693 test_expect_success 'reflog: can delete separate reflog entries' '
694 test_when_finished "rm -rf repo" &&
695 git init repo &&
697 cd repo &&
699 test_commit file &&
700 test_commit file2 &&
701 test_commit file3 &&
702 test_commit file4 &&
703 git reflog >actual &&
704 grep file3 actual &&
706 git reflog delete HEAD@{1} &&
707 git reflog >actual &&
708 ! grep file3 actual
712 test_expect_success 'reflog: can switch to previous branch' '
713 test_when_finished "rm -rf repo" &&
714 git init repo &&
716 cd repo &&
717 test_commit file1 &&
718 git checkout -b branch1 &&
719 test_commit file2 &&
720 git checkout -b branch2 &&
721 git switch - &&
722 git rev-parse --symbolic-full-name HEAD >actual &&
723 echo refs/heads/branch1 >expect &&
724 test_cmp actual expect
728 test_expect_success 'reflog: copying branch writes reflog entry' '
729 test_when_finished "rm -rf repo" &&
730 git init repo &&
732 cd repo &&
733 test_commit file1 &&
734 test_commit file2 &&
735 oid=$(git rev-parse --short HEAD) &&
736 git branch src &&
737 cat >expect <<-EOF &&
738 ${oid} dst@{0}: Branch: copied refs/heads/src to refs/heads/dst
739 ${oid} dst@{1}: branch: Created from main
741 git branch -c src dst &&
742 git reflog dst >actual &&
743 test_cmp expect actual
747 test_expect_success 'reflog: renaming branch writes reflog entry' '
748 test_when_finished "rm -rf repo" &&
749 git init repo &&
751 cd repo &&
752 git symbolic-ref HEAD refs/heads/before &&
753 test_commit file &&
754 git show-ref >expected.refs &&
755 sed s/before/after/g <expected.refs >expected &&
756 git branch -M after &&
757 git show-ref >actual &&
758 test_cmp expected actual &&
759 echo refs/heads/after >expected &&
760 git symbolic-ref HEAD >actual &&
761 test_cmp expected actual
765 test_expect_success 'reflog: can store empty logs' '
766 test_when_finished "rm -rf repo" &&
767 git init repo &&
769 cd repo &&
771 test_must_fail test-tool ref-store main reflog-exists refs/heads/branch &&
772 test-tool ref-store main create-reflog refs/heads/branch &&
773 test-tool ref-store main reflog-exists refs/heads/branch &&
774 test-tool ref-store main for-each-reflog-ent-reverse refs/heads/branch >actual &&
775 test_must_be_empty actual
779 test_expect_success 'reflog: expiry empties reflog' '
780 test_when_finished "rm -rf repo" &&
781 git init repo &&
783 cd repo &&
785 test_commit initial &&
786 git checkout -b branch &&
787 test_commit fileA &&
788 test_commit fileB &&
790 cat >expect <<-EOF &&
791 commit: fileB
792 commit: fileA
793 branch: Created from HEAD
795 git reflog show --format="%gs" refs/heads/branch >actual &&
796 test_cmp expect actual &&
798 git reflog expire branch --expire=all &&
799 git reflog show --format="%gs" refs/heads/branch >actual &&
800 test_must_be_empty actual &&
801 test-tool ref-store main reflog-exists refs/heads/branch
805 test_expect_success 'reflog: can be deleted' '
806 test_when_finished "rm -rf repo" &&
807 git init repo &&
809 cd repo &&
810 test_commit initial &&
811 test-tool ref-store main reflog-exists refs/heads/main &&
812 test-tool ref-store main delete-reflog refs/heads/main &&
813 test_must_fail test-tool ref-store main reflog-exists refs/heads/main
817 test_expect_success 'reflog: garbage collection deletes reflog entries' '
818 test_when_finished "rm -rf repo" &&
819 git init repo &&
821 cd repo &&
823 for count in $(test_seq 1 10)
825 test_commit "number $count" file.t $count number-$count ||
826 return 1
827 done &&
828 git reflog refs/heads/main >actual &&
829 test_line_count = 10 actual &&
830 grep "commit (initial): number 1" actual &&
831 grep "commit: number 10" actual &&
833 git gc &&
834 git reflog refs/heads/main >actual &&
835 test_line_count = 0 actual
839 test_expect_success 'reflog: updates via HEAD update HEAD reflog' '
840 test_when_finished "rm -rf repo" &&
841 git init repo &&
843 cd repo &&
844 test_commit main-one &&
845 git checkout -b new-branch &&
846 test_commit new-one &&
847 test_commit new-two &&
849 echo new-one >expect &&
850 git log -1 --format=%s HEAD@{1} >actual &&
851 test_cmp expect actual
855 test_expect_success 'branch: copying branch with D/F conflict' '
856 test_when_finished "rm -rf repo" &&
857 git init repo &&
859 cd repo &&
860 test_commit A &&
861 git branch branch &&
862 cat >expect <<-EOF &&
863 error: ${SQ}refs/heads/branch${SQ} exists; cannot create ${SQ}refs/heads/branch/moved${SQ}
864 fatal: branch copy failed
866 test_must_fail git branch -c branch branch/moved 2>err &&
867 test_cmp expect err
871 test_expect_success 'branch: moving branch with D/F conflict' '
872 test_when_finished "rm -rf repo" &&
873 git init repo &&
875 cd repo &&
876 test_commit A &&
877 git branch branch &&
878 git branch conflict &&
879 cat >expect <<-EOF &&
880 error: ${SQ}refs/heads/conflict${SQ} exists; cannot create ${SQ}refs/heads/conflict/moved${SQ}
881 fatal: branch rename failed
883 test_must_fail git branch -m branch conflict/moved 2>err &&
884 test_cmp expect err
888 test_expect_success 'worktree: adding worktree creates separate stack' '
889 test_when_finished "rm -rf repo worktree" &&
890 git init repo &&
891 test_commit -C repo A &&
893 git -C repo worktree add ../worktree &&
894 test_path_is_file repo/.git/worktrees/worktree/refs/heads &&
895 echo "ref: refs/heads/.invalid" >expect &&
896 test_cmp expect repo/.git/worktrees/worktree/HEAD &&
897 test_path_is_dir repo/.git/worktrees/worktree/reftable &&
898 test_path_is_file repo/.git/worktrees/worktree/reftable/tables.list
901 test_expect_success 'worktree: pack-refs in main repo packs main refs' '
902 test_when_finished "rm -rf repo worktree" &&
903 git init repo &&
904 test_commit -C repo A &&
906 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
907 git -C repo worktree add ../worktree &&
908 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
909 git -C worktree update-ref refs/worktree/per-worktree HEAD &&
911 test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list &&
912 test_line_count = 3 repo/.git/reftable/tables.list &&
913 git -C repo pack-refs &&
914 test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list &&
915 test_line_count = 1 repo/.git/reftable/tables.list
918 test_expect_success 'worktree: pack-refs in worktree packs worktree refs' '
919 test_when_finished "rm -rf repo worktree" &&
920 git init repo &&
921 test_commit -C repo A &&
923 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
924 git -C repo worktree add ../worktree &&
925 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
926 git -C worktree update-ref refs/worktree/per-worktree HEAD &&
928 test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list &&
929 test_line_count = 3 repo/.git/reftable/tables.list &&
930 git -C worktree pack-refs &&
931 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
932 test_line_count = 3 repo/.git/reftable/tables.list
935 test_expect_success 'worktree: creating shared ref updates main stack' '
936 test_when_finished "rm -rf repo worktree" &&
937 git init repo &&
938 test_commit -C repo A &&
940 git -C repo worktree add ../worktree &&
941 git -C repo pack-refs &&
942 git -C worktree pack-refs &&
943 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
944 test_line_count = 1 repo/.git/reftable/tables.list &&
946 GIT_TEST_REFTABLE_AUTOCOMPACTION=false \
947 git -C worktree update-ref refs/heads/shared HEAD &&
948 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
949 test_line_count = 2 repo/.git/reftable/tables.list
952 test_expect_success 'worktree: creating per-worktree ref updates worktree stack' '
953 test_when_finished "rm -rf repo worktree" &&
954 git init repo &&
955 test_commit -C repo A &&
957 git -C repo worktree add ../worktree &&
958 git -C repo pack-refs &&
959 git -C worktree pack-refs &&
960 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
961 test_line_count = 1 repo/.git/reftable/tables.list &&
963 git -C worktree update-ref refs/bisect/per-worktree HEAD &&
964 test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&
965 test_line_count = 1 repo/.git/reftable/tables.list
968 test_expect_success 'worktree: creating per-worktree ref from main repo' '
969 test_when_finished "rm -rf repo worktree" &&
970 git init repo &&
971 test_commit -C repo A &&
973 git -C repo worktree add ../worktree &&
974 git -C repo pack-refs &&
975 git -C worktree pack-refs &&
976 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
977 test_line_count = 1 repo/.git/reftable/tables.list &&
979 git -C repo update-ref worktrees/worktree/refs/bisect/per-worktree HEAD &&
980 test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&
981 test_line_count = 1 repo/.git/reftable/tables.list
984 test_expect_success 'worktree: creating per-worktree ref from second worktree' '
985 test_when_finished "rm -rf repo wt1 wt2" &&
986 git init repo &&
987 test_commit -C repo A &&
989 git -C repo worktree add ../wt1 &&
990 git -C repo worktree add ../wt2 &&
991 git -C repo pack-refs &&
992 git -C wt1 pack-refs &&
993 git -C wt2 pack-refs &&
994 test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list &&
995 test_line_count = 1 repo/.git/worktrees/wt2/reftable/tables.list &&
996 test_line_count = 1 repo/.git/reftable/tables.list &&
998 git -C wt1 update-ref worktrees/wt2/refs/bisect/per-worktree HEAD &&
999 test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list &&
1000 test_line_count = 2 repo/.git/worktrees/wt2/reftable/tables.list &&
1001 test_line_count = 1 repo/.git/reftable/tables.list
1004 test_expect_success 'worktree: can create shared and per-worktree ref in one transaction' '
1005 test_when_finished "rm -rf repo worktree" &&
1006 git init repo &&
1007 test_commit -C repo A &&
1009 git -C repo worktree add ../worktree &&
1010 git -C repo pack-refs &&
1011 git -C worktree pack-refs &&
1012 test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&
1013 test_line_count = 1 repo/.git/reftable/tables.list &&
1015 cat >stdin <<-EOF &&
1016 create worktrees/worktree/refs/bisect/per-worktree HEAD
1017 create refs/branches/shared HEAD
1019 git -C repo update-ref --stdin <stdin &&
1020 test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&
1021 test_line_count = 2 repo/.git/reftable/tables.list
1024 test_expect_success 'worktree: can access common refs' '
1025 test_when_finished "rm -rf repo worktree" &&
1026 git init repo &&
1027 test_commit -C repo file1 &&
1028 git -C repo branch branch1 &&
1029 git -C repo worktree add ../worktree &&
1031 echo refs/heads/worktree >expect &&
1032 git -C worktree symbolic-ref HEAD >actual &&
1033 test_cmp expect actual &&
1034 git -C worktree checkout branch1
1037 test_expect_success 'worktree: adds worktree with detached HEAD' '
1038 test_when_finished "rm -rf repo worktree" &&
1040 git init repo &&
1041 test_commit -C repo A &&
1042 git -C repo rev-parse main >expect &&
1044 git -C repo worktree add --detach ../worktree main &&
1045 git -C worktree rev-parse HEAD >actual &&
1046 test_cmp expect actual
1049 test_expect_success 'fetch: accessing FETCH_HEAD special ref works' '
1050 test_when_finished "rm -rf repo sub" &&
1052 git init sub &&
1053 test_commit -C sub two &&
1054 git -C sub rev-parse HEAD >expect &&
1056 git init repo &&
1057 test_commit -C repo one &&
1058 git -C repo fetch ../sub &&
1059 git -C repo rev-parse FETCH_HEAD >actual &&
1060 test_cmp expect actual
1063 test_done