3 # Copyright (c) 2006 Junio C Hamano
6 test_description
='git checkout tests.
8 Creates main, forks renamer and side branches from it.
9 Test switching across them.
11 ! [main] Initial A one, A two
12 * [renamer] Renamer R one->uno, M two
13 ! [side] Side M one, D two, A three
14 ! [simple] Simple D one, M two
16 + [simple] Simple D one, M two
17 + [side] Side M one, D two, A three
18 * [renamer] Renamer R one->uno, M two
19 +*++ [main] Initial A one, A two
23 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
=main
24 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
26 TEST_PASSES_SANITIZE_LEAK
=true
39 test_expect_success setup
'
41 fill 1 2 3 4 5 6 7 8 >one &&
42 fill a b c d e >two &&
43 git add same one two &&
44 git commit -m "Initial A one, A two" &&
46 git checkout -b renamer &&
48 fill 1 3 4 5 6 7 8 >uno &&
50 fill a b c d e f >two &&
51 git commit -a -m "Renamer R one->uno, M two" &&
53 git checkout -b side main &&
54 fill 1 2 3 4 5 6 7 >one &&
55 fill A B C D E >three &&
57 git update-index --add --remove one two three &&
58 git commit -m "Side M one, D two, A three" &&
60 git checkout -b simple main &&
63 git commit -a -m "Simple D one, M two" &&
68 test_expect_success
'checkout from non-existing branch' '
69 git checkout -b delete-me main &&
70 git update-ref -d --no-deref refs/heads/delete-me &&
71 test refs/heads/delete-me = "$(git symbolic-ref HEAD)" &&
73 test refs/heads/main = "$(git symbolic-ref HEAD)"
76 test_expect_success
'checkout with dirty tree without -m' '
77 fill 0 1 2 3 4 5 6 7 8 >one &&
83 echo "happy - failed correctly"
87 test_expect_success
'checkout with unrelated dirty tree without -m' '
88 git checkout -f main &&
89 fill 0 1 2 3 4 5 6 7 8 >same &&
91 git checkout side >messages &&
93 printf "M\t%s\n" same >messages.expect &&
94 test_cmp messages.expect messages
97 test_expect_success
'checkout -m with dirty tree' '
98 git checkout -f main &&
101 fill 0 1 2 3 4 5 6 7 8 >one &&
102 git checkout -m side >messages &&
104 test "$(git symbolic-ref HEAD)" = "refs/heads/side" &&
106 printf "M\t%s\n" one >expect.messages &&
107 test_cmp expect.messages messages &&
109 fill "M one" "A three" "D two" >expect.main &&
110 git diff --name-status main >current.main &&
111 test_cmp expect.main current.main &&
113 fill "M one" >expect.side &&
114 git diff --name-status side >current.side &&
115 test_cmp expect.side current.side &&
117 git diff --cached >current.index &&
118 test_must_be_empty current.index
121 test_expect_success
'checkout -m with dirty tree, renamed' '
122 git checkout -f main && git clean -f &&
124 fill 1 2 3 4 5 7 8 >one &&
125 if git checkout renamer
130 echo "happy - failed correctly"
133 git checkout -m renamer &&
134 fill 1 3 4 5 7 8 >expect &&
135 test_cmp expect uno &&
137 git diff --cached >current &&
138 test_must_be_empty current
141 test_expect_success
'checkout -m with merge conflict' '
142 git checkout -f main && git clean -f &&
144 fill 1 T 3 4 5 6 S 8 >one &&
145 if git checkout renamer
150 echo "happy - failed correctly"
153 git checkout -m renamer &&
155 git diff main:one :3:uno |
156 sed -e "1,/^@@/d" -e "/^ /d" -e "s/^-/d/" -e "s/^+/a/" >current &&
157 fill d2 aT d7 aS >expect &&
158 test_cmp expect current &&
159 git diff --cached two >current &&
160 test_must_be_empty current
163 test_expect_success
'format of merge conflict from checkout -m' '
164 git checkout -f main &&
168 git checkout -m simple &&
170 git ls-files >current &&
171 fill same two two two >expect &&
172 test_cmp expect current &&
174 cat <<-EOF >expect &&
187 test_expect_success
'checkout --merge --conflict=diff3 <branch>' '
188 git checkout -f main &&
193 git checkout --merge --conflict=diff3 simple &&
195 cat <<-EOF >expect &&
214 test_expect_success
'switch to another branch while carrying a deletion' '
215 git checkout -f main &&
220 test_must_fail git checkout simple 2>errs &&
221 test_grep overwritten errs &&
223 test_must_fail git read-tree --quiet -m -u HEAD simple 2>errs &&
224 test_must_be_empty errs
227 test_expect_success
'checkout to detach HEAD (with advice declined)' '
228 git config advice.detachedHead false &&
229 rev=$(git rev-parse --short renamer^) &&
230 git checkout -f renamer &&
232 git checkout renamer^ 2>messages &&
233 test_grep "HEAD is now at $rev" messages &&
234 test_line_count = 1 messages &&
235 H=$(git rev-parse --verify HEAD) &&
236 M=$(git show-ref -s --verify refs/heads/main) &&
237 test "z$H" = "z$M" &&
238 if git symbolic-ref HEAD >/dev/null 2>&1
240 echo "OOPS, HEAD is still symbolic???"
247 test_expect_success
'checkout to detach HEAD' '
248 git config advice.detachedHead true &&
249 rev=$(git rev-parse --short renamer^) &&
250 git checkout -f renamer &&
252 git checkout renamer^ 2>messages &&
253 grep "HEAD is now at $rev" messages &&
254 test_line_count -gt 1 messages &&
255 H=$(git rev-parse --verify HEAD) &&
256 M=$(git show-ref -s --verify refs/heads/main) &&
257 test "z$H" = "z$M" &&
258 if git symbolic-ref HEAD >/dev/null 2>&1
260 echo "OOPS, HEAD is still symbolic???"
267 test_expect_success
'checkout to detach HEAD with branchname^' '
268 git checkout -f main &&
270 git checkout renamer^ &&
271 H=$(git rev-parse --verify HEAD) &&
272 M=$(git show-ref -s --verify refs/heads/main) &&
273 test "z$H" = "z$M" &&
274 if git symbolic-ref HEAD >/dev/null 2>&1
276 echo "OOPS, HEAD is still symbolic???"
283 test_expect_success
'checkout to detach HEAD with :/message' '
284 git checkout -f main &&
286 git checkout ":/Initial" &&
287 H=$(git rev-parse --verify HEAD) &&
288 M=$(git show-ref -s --verify refs/heads/main) &&
289 test "z$H" = "z$M" &&
290 if git symbolic-ref HEAD >/dev/null 2>&1
292 echo "OOPS, HEAD is still symbolic???"
299 test_expect_success
'checkout to detach HEAD with HEAD^0' '
300 git checkout -f main &&
302 git checkout HEAD^0 &&
303 H=$(git rev-parse --verify HEAD) &&
304 M=$(git show-ref -s --verify refs/heads/main) &&
305 test "z$H" = "z$M" &&
306 if git symbolic-ref HEAD >/dev/null 2>&1
308 echo "OOPS, HEAD is still symbolic???"
315 test_expect_success
'checkout with ambiguous tag/branch names' '
317 git branch both main &&
322 H=$(git rev-parse --verify HEAD) &&
323 M=$(git show-ref -s --verify refs/heads/main) &&
324 test "z$H" = "z$M" &&
325 name=$(git symbolic-ref HEAD 2>/dev/null) &&
326 test "z$name" = zrefs/heads/both
329 test_expect_success
'checkout with ambiguous tag/branch names' '
333 git tag frotz side &&
334 git branch frotz main &&
338 git checkout tags/frotz &&
339 H=$(git rev-parse --verify HEAD) &&
340 S=$(git show-ref -s --verify refs/heads/side) &&
341 test "z$H" = "z$S" &&
342 if name=$(git symbolic-ref HEAD 2>/dev/null)
344 echo "Bad -- should have detached"
351 test_expect_success
'switch branches while in subdirectory' '
356 git -C subs checkout side &&
357 ! test -f subs/one &&
361 test_expect_success
'checkout specific path while in subdirectory' '
367 git commit -m "add subs/bero" &&
371 git -C subs checkout side -- bero &&
375 test_expect_success
'checkout w/--track sets up tracking' '
376 git config branch.autosetupmerge false &&
378 git checkout --track -b track1 &&
379 test "$(git config branch.track1.remote)" &&
380 test "$(git config branch.track1.merge)"
383 test_expect_success
'checkout w/autosetupmerge=always sets up tracking' '
384 test_when_finished git config branch.autosetupmerge false &&
385 git config branch.autosetupmerge always &&
387 git checkout -b track2 &&
388 test "$(git config branch.track2.remote)" &&
389 test "$(git config branch.track2.merge)"
392 test_expect_success
'checkout w/--track from non-branch HEAD fails' '
393 git checkout main^0 &&
394 test_must_fail git symbolic-ref HEAD &&
395 test_must_fail git checkout --track -b track &&
396 test_must_fail git rev-parse --verify track &&
397 test_must_fail git symbolic-ref HEAD &&
398 test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)"
401 test_expect_success
'checkout w/--track from tag fails' '
402 git checkout main^0 &&
403 test_must_fail git symbolic-ref HEAD &&
404 test_must_fail git checkout --track -b track frotz &&
405 test_must_fail git rev-parse --verify track &&
406 test_must_fail git symbolic-ref HEAD &&
407 test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)"
410 test_expect_success
'detach a symbolic link HEAD' '
412 git config --bool core.prefersymlinkrefs yes &&
415 it=$(git symbolic-ref HEAD) &&
416 test "z$it" = zrefs/heads/main &&
417 here=$(git rev-parse --verify refs/heads/main) &&
418 git checkout side^ &&
419 test "z$(git rev-parse --verify refs/heads/main)" = "z$here"
422 test_expect_success
'checkout with --track fakes a sensible -b <name>' '
423 git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" &&
424 git update-ref refs/remotes/origin/koala/bear renamer &&
426 git checkout --track origin/koala/bear &&
427 test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
428 test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
430 git checkout main && git branch -D koala/bear &&
432 git checkout --track refs/remotes/origin/koala/bear &&
433 test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
434 test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
436 git checkout main && git branch -D koala/bear &&
438 git checkout --track remotes/origin/koala/bear &&
439 test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
440 test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
443 test_expect_success
'checkout with --track, but without -b, fails with too short tracked name' '
444 test_must_fail git checkout --track renamer
447 setup_conflicting_index
() {
449 O
=$
(echo original | git hash-object
-w --stdin) &&
450 A
=$
(echo ourside | git hash-object
-w --stdin) &&
451 B
=$
(echo theirside | git hash-object
-w --stdin) &&
453 echo "100644 $A 0 fild" &&
454 echo "100644 $O 1 file" &&
455 echo "100644 $A 2 file" &&
456 echo "100644 $B 3 file" &&
457 echo "100644 $A 0 filf"
458 ) | git update-index
--index-info
461 test_expect_success
'checkout an unmerged path should fail' '
462 setup_conflicting_index &&
463 echo "none of the above" >sample &&
467 test_must_fail git checkout fild file filf &&
468 test_cmp sample fild &&
469 test_cmp sample filf &&
473 test_expect_success
'checkout with an unmerged path can be ignored' '
474 setup_conflicting_index &&
475 echo "none of the above" >sample &&
476 echo ourside >expect &&
480 git checkout -f fild file filf &&
481 test_cmp expect fild &&
482 test_cmp expect filf &&
486 test_expect_success
'checkout unmerged stage' '
487 setup_conflicting_index &&
488 echo "none of the above" >sample &&
489 echo ourside >expect &&
493 git checkout --ours . &&
494 test_cmp expect fild &&
495 test_cmp expect filf &&
496 test_cmp expect file &&
497 git checkout --theirs file &&
498 test ztheirside = "z$(cat file)"
501 test_expect_success
'checkout --ours is incompatible with switching' '
502 test_must_fail git checkout --ours 2>error &&
503 test_grep "needs the paths to check out" error &&
505 test_must_fail git checkout --ours HEAD 2>error &&
506 test_grep "cannot be used with switching" error &&
508 test_must_fail git checkout --ours main 2>error &&
509 test_grep "cannot be used with switching" error &&
511 git checkout --ours file
514 test_expect_success
'checkout path with --merge from tree-ish is a no-no' '
515 setup_conflicting_index &&
516 test_must_fail git checkout -m HEAD -- file
519 test_expect_success
'checkout with --merge' '
520 setup_conflicting_index &&
521 echo "none of the above" >sample &&
522 echo ourside >expect &&
526 git checkout -m -- fild file filf &&
528 echo "<<<<<<< ours" &&
532 echo ">>>>>>> theirs"
534 test_cmp expect fild &&
535 test_cmp expect filf &&
539 test_expect_success
'checkout -m works after (mistaken) resolution' '
540 setup_conflicting_index &&
541 echo "none of the above" >sample &&
545 # resolve to something
547 git checkout --merge -- fild file filf &&
549 echo "<<<<<<< ours" &&
553 echo ">>>>>>> theirs"
555 test_cmp expect fild &&
556 test_cmp expect filf &&
560 test_expect_success
'checkout -m works after (mistaken) resolution to remove' '
561 setup_conflicting_index &&
562 echo "none of the above" >sample &&
568 git checkout --merge -- fild file filf &&
570 echo "<<<<<<< ours" &&
574 echo ">>>>>>> theirs"
576 test_cmp expect fild &&
577 test_cmp expect filf &&
581 test_expect_success
'checkout with --merge, in diff3 -m style' '
582 git config merge.conflictstyle diff3 &&
583 setup_conflicting_index &&
584 echo "none of the above" >sample &&
585 echo ourside >expect &&
589 git checkout -m -- fild file filf &&
591 echo "<<<<<<< ours" &&
593 echo "||||||| base" &&
597 echo ">>>>>>> theirs"
599 test_cmp expect fild &&
600 test_cmp expect filf &&
604 test_expect_success
'checkout --conflict=merge, overriding config' '
605 git config merge.conflictstyle diff3 &&
606 setup_conflicting_index &&
607 echo "none of the above" >sample &&
608 echo ourside >expect &&
612 git checkout --conflict=merge -- fild file filf &&
614 echo "<<<<<<< ours" &&
618 echo ">>>>>>> theirs"
620 test_cmp expect fild &&
621 test_cmp expect filf &&
625 test_expect_success
'checkout --conflict=diff3' '
626 test_unconfig merge.conflictstyle &&
627 setup_conflicting_index &&
628 echo "none of the above" >sample &&
629 echo ourside >expect &&
633 git checkout --conflict=diff3 -- fild file filf &&
635 echo "<<<<<<< ours" &&
637 echo "||||||| base" &&
641 echo ">>>>>>> theirs"
643 test_cmp expect fild &&
644 test_cmp expect filf &&
648 test_expect_success
'checkout --conflict=diff3 --no-conflict does not merge' '
649 setup_conflicting_index &&
650 echo "none of the above" >expect &&
653 test_must_fail git checkout --conflict=diff3 --no-conflict -- fild file 2>err &&
654 test_cmp expect file &&
655 test_cmp expect fild &&
656 echo "error: path ${SQ}file${SQ} is unmerged" >expect &&
660 test_expect_success
'checkout --conflict=diff3 --no-merge does not merge' '
661 setup_conflicting_index &&
662 echo "none of the above" >expect &&
665 test_must_fail git checkout --conflict=diff3 --no-merge -- fild file 2>err &&
666 test_cmp expect file &&
667 test_cmp expect fild &&
668 echo "error: path ${SQ}file${SQ} is unmerged" >expect &&
672 test_expect_success
'checkout --no-merge --conflict=diff3 does merge' '
673 setup_conflicting_index &&
674 echo "none of the above" >fild &&
675 echo "none of the above" >file &&
676 git checkout --no-merge --conflict=diff3 -- fild file &&
677 echo "ourside" >expect &&
678 test_cmp expect fild &&
679 cat >expect <<-\EOF &&
691 test_expect_success
'checkout --merge --conflict=diff3 --no-conflict does merge' '
692 setup_conflicting_index &&
693 echo "none of the above" >fild &&
694 echo "none of the above" >file &&
695 git checkout --merge --conflict=diff3 --no-conflict -- fild file &&
696 echo "ourside" >expect &&
697 test_cmp expect fild &&
698 cat >expect <<-\EOF &&
708 test_expect_success
'checkout with invalid conflict style' '
709 test_must_fail git checkout --conflict=bad 2>actual -- file &&
710 echo "error: unknown conflict style ${SQ}bad${SQ}" >expect &&
711 test_cmp expect actual
714 test_expect_success
'failing checkout -b should not break working tree' '
715 git clean -fd && # Remove untracked files in the way
716 git reset --hard main &&
717 git symbolic-ref HEAD refs/heads/main &&
718 test_must_fail git checkout -b renamer side^ &&
719 test $(git symbolic-ref HEAD) = refs/heads/main &&
720 git diff --exit-code &&
721 git diff --cached --exit-code
724 test_expect_success
'switch out of non-branch' '
725 git reset --hard main &&
726 git checkout main^0 &&
727 echo modified >one &&
728 test_must_fail git checkout renamer 2>error.log &&
729 ! grep "^Previous HEAD" error.log
738 echo '<<<<<<< filfre-theirs'
740 echo '||||||| filfre-common
'
744 echo '>>>>>>> filfre-ours
'
751 test_expect_success 'custom merge driver with checkout
-m' '
754 git config merge.filfre.driver
"./filfre.sh %O %A %B" &&
755 git config merge.filfre.name
"Feel-free merge driver" &&
756 git config merge.filfre.recursive binary
&&
757 echo "arm merge=filfre" >.gitattributes
&&
759 git checkout
-b left
&&
761 git add arm .gitattributes
&&
763 git commit
-m neutral
&&
768 git commit
-a -m left
&&
769 git checkout right
&&
773 git commit
-a -m right
&&
775 test_must_fail git merge left
&&
777 for t
in filfre-common left right
779 grep $t arm ||
exit 1
784 git checkout
-m arm
&&
788 test_expect_success 'tracking info copied with autoSetupMerge
=inherit
' '
789 git
reset --hard main
&&
790 # default config does not copy tracking info
791 git checkout
-b foo-no-inherit koala
/bear
&&
792 test_cmp_config
"" --default "" branch.foo-no-inherit.remote
&&
793 test_cmp_config
"" --default "" branch.foo-no-inherit.merge
&&
794 # with autoSetupMerge=inherit, we copy tracking info from koala/bear
795 test_config branch.autoSetupMerge inherit
&&
796 git checkout
-b foo koala
/bear
&&
797 test_cmp_config origin branch.foo.remote
&&
798 test_cmp_config refs
/heads
/koala
/bear branch.foo.merge
&&
799 # no tracking info to inherit from main
800 git checkout
-b main2 main
&&
801 test_cmp_config
"" --default "" branch.main2.remote
&&
802 test_cmp_config
"" --default "" branch.main2.merge