Raw
1 #!/bin/sh
2 #
3 # Copyright (c) 2006 Junio C Hamano
4 #
5
6 test_description='git checkout tests.
7
8 Creates main, forks renamer and side branches from it.
9 Test switching across them.
10
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
15 ----
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
20
21 '
22
23 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
24 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
25
26 . ./test-lib.sh
27
28 test_tick
29
30 fill () {
31 for i
32 do
33 echo "$i"
34 done
35 }
36
37
38 test_expect_success setup '
39 fill x y z >same &&
40 fill 1 2 3 4 5 6 7 8 >one &&
41 fill a b c d e >two &&
42 git add same one two &&
43 git commit -m "Initial A one, A two" &&
44
45 git checkout -b renamer &&
46 rm -f one &&
47 fill 1 3 4 5 6 7 8 >uno &&
48 git add uno &&
49 fill a b c d e f >two &&
50 git commit -a -m "Renamer R one->uno, M two" &&
51
52 git checkout -b side main &&
53 fill 1 2 3 4 5 6 7 >one &&
54 fill A B C D E >three &&
55 rm -f two &&
56 git update-index --add --remove one two three &&
57 git commit -m "Side M one, D two, A three" &&
58
59 git checkout -b simple main &&
60 rm -f one &&
61 fill a c e >two &&
62 git commit -a -m "Simple D one, M two" &&
63
64 git checkout main
65 '
66
67 test_expect_success 'checkout from non-existing branch' '
68 git checkout -b delete-me main &&
69 git update-ref -d --no-deref refs/heads/delete-me &&
70 test refs/heads/delete-me = "$(git symbolic-ref HEAD)" &&
71 git checkout main &&
72 test refs/heads/main = "$(git symbolic-ref HEAD)"
73 '
74
75 test_expect_success 'checkout with dirty tree without -m' '
76 fill 0 1 2 3 4 5 6 7 8 >one &&
77 if git checkout side
78 then
79 echo Not happy
80 false
81 else
82 echo "happy - failed correctly"
83 fi
84 '
85
86 test_expect_success 'checkout with unrelated dirty tree without -m' '
87 git checkout -f main &&
88 fill 0 1 2 3 4 5 6 7 8 >same &&
89 cp same kept &&
90 git checkout side >messages &&
91 test_cmp same kept &&
92 printf "M\t%s\n" same >messages.expect &&
93 test_cmp messages.expect messages
94 '
95
96 test_expect_success 'checkout -m with dirty tree' '
97 git checkout -f main &&
98 git clean -f &&
99
100 fill 0 1 2 3 4 5 6 7 8 >one &&
101 git checkout -m side >messages &&
102
103 test "$(git symbolic-ref HEAD)" = "refs/heads/side" &&
104
105 cat >expect.messages <<-\EOF &&
106 The following paths have local changes:
107 M one
108 EOF
109 test_cmp expect.messages messages &&
110
111 fill "M one" "A three" "D two" >expect.main &&
112 git diff --name-status main >current.main &&
113 test_cmp expect.main current.main &&
114
115 fill "M one" >expect.side &&
116 git diff --name-status side >current.side &&
117 test_cmp expect.side current.side &&
118
119 git diff --cached >current.index &&
120 test_must_be_empty current.index
121 '
122
123 test_expect_success 'checkout -m with dirty tree, renamed' '
124 git checkout -f main && git clean -f &&
125
126 fill 1 2 3 4 5 7 8 >one &&
127 if git checkout renamer
128 then
129 echo Not happy
130 false
131 else
132 echo "happy - failed correctly"
133 fi &&
134
135 git checkout -m renamer &&
136 fill 1 3 4 5 7 8 >expect &&
137 test_cmp expect uno &&
138 ! test -f one &&
139 git diff --cached >current &&
140 test_must_be_empty current
141 '
142
143 test_expect_success 'checkout -m with merge conflict' '
144 git checkout -f main && git clean -f &&
145
146 fill 1 T 3 4 5 6 S 8 >one &&
147 if git checkout renamer
148 then
149 echo Not happy
150 false
151 else
152 echo "happy - failed correctly"
153 fi &&
154
155 git checkout -m renamer &&
156
157 git diff main:one :3:uno |
158 sed -e "1,/^@@/d" -e "/^ /d" -e "s/^-/d/" -e "s/^+/a/" >current &&
159 fill d2 aT d7 aS >expect &&
160 test_cmp expect current &&
161 git diff --cached two >current &&
162 test_must_be_empty current
163 '
164
165 test_expect_success 'format of merge conflict from checkout -m' '
166 git checkout -f main &&
167 git clean -f &&
168
169 fill b d >two &&
170 git checkout -m simple &&
171
172 git ls-files >current &&
173 fill same two two two >expect &&
174 test_cmp expect current &&
175
176 cat <<-EOF >expect &&
177 <<<<<<< simple
178 a
179 c
180 e
181 =======
182 b
183 d
184 >>>>>>> local
185 EOF
186 test_cmp expect two
187 '
188
189 test_expect_success 'checkout --merge --conflict=diff3 <branch>' '
190 git checkout -f main &&
191 git reset --hard &&
192 git clean -f &&
193
194 fill b d >two &&
195 git checkout --merge --conflict=diff3 simple &&
196
197 cat <<-EOF >expect &&
198 <<<<<<< simple
199 a
200 c
201 e
202 ||||||| main
203 a
204 b
205 c
206 d
207 e
208 =======
209 b
210 d
211 >>>>>>> local
212 EOF
213 test_cmp expect two
214 '
215
216 test_expect_success 'checkout -m with mixed staged and unstaged changes' '
217 git checkout -f main &&
218 git clean -f &&
219
220 fill 0 x y z >same &&
221 git add same &&
222 fill 1 2 3 4 5 6 7 >one &&
223 git checkout -m side >actual 2>&1 &&
224 test_grep "Applied autostash" actual &&
225 fill 0 x y z >expect &&
226 test_cmp expect same &&
227 fill 1 2 3 4 5 6 7 >expect &&
228 test_cmp expect one
229 '
230
231 test_expect_success 'checkout -m creates a recoverable stash on conflict' '
232 git checkout -f main &&
233 git clean -f &&
234
235 fill 1 2 3 4 5 >one &&
236 test_must_fail git checkout side 2>stderr &&
237 test_grep "Your local changes" stderr &&
238 git checkout -m side >actual 2>&1 &&
239 test_grep "resulted in conflicts" actual &&
240 test_grep "git stash drop" actual &&
241 test_grep "git stash pop" actual &&
242 test_grep "The following paths have local changes" actual &&
243 git log -p -1 --format="%gs%n%B" -g --diff-merges=1 refs/stash >actual &&
244 sed /^index/d actual >actual.trimmed &&
245 cat >expect <<-EOF &&
246 autostash while switching to ${SQ}side${SQ}
247 On main: autostash while switching to ${SQ}side${SQ}
248
249 diff --git a/one b/one
250 --- a/one
251 +++ b/one
252 @@ -3,6 +3,3 @@
253 3
254 4
255 5
256 -6
257 -7
258 -8
259 EOF
260 test_cmp expect actual.trimmed &&
261 git stash drop &&
262 git reset --hard
263 '
264
265 test_expect_success 'checkout -m which would overwrite untracked file' '
266 git checkout -f --detach main &&
267 test_commit another-file &&
268 git checkout HEAD^ &&
269 >another-file.t &&
270 fill 1 2 3 4 5 >one &&
271 test_must_fail git checkout -m @{-1} 2>err &&
272 q_to_tab >expect <<-\EOF &&
273 error: The following untracked working tree files would be overwritten by checkout:
274 Qanother-file.t
275 Please move or remove them before you switch branches.
276 Aborting
277 Applied autostash.
278 EOF
279 test_cmp expect err
280 '
281
282 test_expect_success 'switch to another branch while carrying a deletion' '
283 git checkout -f main &&
284 git reset --hard &&
285 git clean -f &&
286 git rm two &&
287
288 test_must_fail git checkout simple 2>errs &&
289 test_grep overwritten errs &&
290
291 test_must_fail git read-tree --quiet -m -u HEAD simple 2>errs &&
292 test_must_be_empty errs
293 '
294
295 test_expect_success 'checkout to detach HEAD (with advice declined)' '
296 git config set advice.detachedHead false &&
297 rev=$(git rev-parse --short renamer^) &&
298 git checkout -f renamer &&
299 git clean -f &&
300 git checkout renamer^ 2>messages &&
301 test_grep "HEAD is now at $rev" messages &&
302 test_line_count = 1 messages &&
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
307 then
308 echo "OOPS, HEAD is still symbolic???"
309 false
310 else
311 : happy
312 fi
313 '
314
315 test_expect_success 'checkout to detach HEAD' '
316 git config set advice.detachedHead true &&
317 rev=$(git rev-parse --short renamer^) &&
318 git checkout -f renamer &&
319 git clean -f &&
320 git checkout renamer^ 2>messages &&
321 test_grep "HEAD is now at $rev" messages &&
322 test_line_count -gt 1 messages &&
323 H=$(git rev-parse --verify HEAD) &&
324 M=$(git show-ref -s --verify refs/heads/main) &&
325 test "z$H" = "z$M" &&
326 if git symbolic-ref HEAD >/dev/null 2>&1
327 then
328 echo "OOPS, HEAD is still symbolic???"
329 false
330 else
331 : happy
332 fi
333 '
334
335 test_expect_success 'checkout to detach HEAD with branchname^' '
336 git checkout -f main &&
337 git clean -f &&
338 git checkout renamer^ &&
339 H=$(git rev-parse --verify HEAD) &&
340 M=$(git show-ref -s --verify refs/heads/main) &&
341 test "z$H" = "z$M" &&
342 if git symbolic-ref HEAD >/dev/null 2>&1
343 then
344 echo "OOPS, HEAD is still symbolic???"
345 false
346 else
347 : happy
348 fi
349 '
350
351 test_expect_success 'checkout to detach HEAD with :/message' '
352 git checkout -f main &&
353 git clean -f &&
354 git checkout ":/Initial" &&
355 H=$(git rev-parse --verify HEAD) &&
356 M=$(git show-ref -s --verify refs/heads/main) &&
357 test "z$H" = "z$M" &&
358 if git symbolic-ref HEAD >/dev/null 2>&1
359 then
360 echo "OOPS, HEAD is still symbolic???"
361 false
362 else
363 : happy
364 fi
365 '
366
367 test_expect_success 'checkout to detach HEAD with HEAD^0' '
368 git checkout -f main &&
369 git clean -f &&
370 git checkout HEAD^0 &&
371 H=$(git rev-parse --verify HEAD) &&
372 M=$(git show-ref -s --verify refs/heads/main) &&
373 test "z$H" = "z$M" &&
374 if git symbolic-ref HEAD >/dev/null 2>&1
375 then
376 echo "OOPS, HEAD is still symbolic???"
377 false
378 else
379 : happy
380 fi
381 '
382
383 test_expect_success 'checkout with ambiguous tag/branch names' '
384 git tag both side &&
385 git branch both main &&
386 git reset --hard &&
387 git checkout main &&
388
389 git checkout both &&
390 H=$(git rev-parse --verify HEAD) &&
391 M=$(git show-ref -s --verify refs/heads/main) &&
392 test "z$H" = "z$M" &&
393 name=$(git symbolic-ref HEAD 2>/dev/null) &&
394 test "z$name" = zrefs/heads/both
395 '
396
397 test_expect_success 'checkout with ambiguous tag/branch names' '
398 git reset --hard &&
399 git checkout main &&
400
401 git tag frotz side &&
402 git branch frotz main &&
403 git reset --hard &&
404 git checkout main &&
405
406 git checkout tags/frotz &&
407 H=$(git rev-parse --verify HEAD) &&
408 S=$(git show-ref -s --verify refs/heads/side) &&
409 test "z$H" = "z$S" &&
410 if name=$(git symbolic-ref HEAD 2>/dev/null)
411 then
412 echo "Bad -- should have detached"
413 false
414 else
415 : happy
416 fi
417 '
418
419 test_expect_success 'switch branches while in subdirectory' '
420 git reset --hard &&
421 git checkout main &&
422
423 mkdir subs &&
424 git -C subs checkout side &&
425 ! test -f subs/one &&
426 rm -fr subs
427 '
428
429 test_expect_success 'checkout specific path while in subdirectory' '
430 git reset --hard &&
431 git checkout side &&
432 mkdir subs &&
433 >subs/bero &&
434 git add subs/bero &&
435 git commit -m "add subs/bero" &&
436
437 git checkout main &&
438 mkdir -p subs &&
439 git -C subs checkout side -- bero &&
440 test -f subs/bero
441 '
442
443 test_expect_success 'checkout w/--track sets up tracking' '
444 git config branch.autosetupmerge false &&
445 git checkout main &&
446 git checkout --track -b track1 &&
447 test "$(git config branch.track1.remote)" &&
448 test "$(git config branch.track1.merge)"
449 '
450
451 test_expect_success 'checkout w/autosetupmerge=always sets up tracking' '
452 test_when_finished git config branch.autosetupmerge false &&
453 git config branch.autosetupmerge always &&
454 git checkout main &&
455 git checkout -b track2 &&
456 test "$(git config branch.track2.remote)" &&
457 test "$(git config branch.track2.merge)"
458 '
459
460 test_expect_success 'checkout w/--track from non-branch HEAD fails' '
461 git checkout main^0 &&
462 test_must_fail git symbolic-ref HEAD &&
463 test_must_fail git checkout --track -b track &&
464 test_must_fail git rev-parse --verify track &&
465 test_must_fail git symbolic-ref HEAD &&
466 test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)"
467 '
468
469 test_expect_success 'checkout w/--track from tag fails' '
470 git checkout main^0 &&
471 test_must_fail git symbolic-ref HEAD &&
472 test_must_fail git checkout --track -b track frotz &&
473 test_must_fail git rev-parse --verify track &&
474 test_must_fail git symbolic-ref HEAD &&
475 test "z$(git rev-parse main^0)" = "z$(git rev-parse HEAD)"
476 '
477
478 test_expect_success 'detach a symbolic link HEAD' '
479 git checkout main &&
480 git config --bool core.prefersymlinkrefs yes &&
481 git checkout side &&
482 git checkout main &&
483 it=$(git symbolic-ref HEAD) &&
484 test "z$it" = zrefs/heads/main &&
485 here=$(git rev-parse --verify refs/heads/main) &&
486 git checkout side^ &&
487 test "z$(git rev-parse --verify refs/heads/main)" = "z$here"
488 '
489
490 test_expect_success 'checkout with --track fakes a sensible -b <name>' '
491 git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" &&
492 git update-ref refs/remotes/origin/koala/bear renamer &&
493
494 git checkout --track origin/koala/bear &&
495 test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
496 test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
497
498 git checkout main && git branch -D koala/bear &&
499
500 git checkout --track refs/remotes/origin/koala/bear &&
501 test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
502 test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
503
504 git checkout main && git branch -D koala/bear &&
505
506 git checkout --track remotes/origin/koala/bear &&
507 test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
508 test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
509 '
510
511 test_expect_success 'checkout with --track, but without -b, fails with too short tracked name' '
512 test_must_fail git checkout --track renamer
513 '
514
515 setup_conflicting_index () {
516 rm -f .git/index &&
517 O=$(echo original | git hash-object -w --stdin) &&
518 A=$(echo ourside | git hash-object -w --stdin) &&
519 B=$(echo theirside | git hash-object -w --stdin) &&
520 (
521 echo "100644 $A 0 fild" &&
522 echo "100644 $O 1 file" &&
523 echo "100644 $A 2 file" &&
524 echo "100644 $B 3 file" &&
525 echo "100644 $A 0 filf"
526 ) | git update-index --index-info
527 }
528
529 test_expect_success 'checkout an unmerged path should fail' '
530 setup_conflicting_index &&
531 echo "none of the above" >sample &&
532 cat sample >fild &&
533 cat sample >file &&
534 cat sample >filf &&
535 test_must_fail git checkout fild file filf &&
536 test_cmp sample fild &&
537 test_cmp sample filf &&
538 test_cmp sample file
539 '
540
541 test_expect_success 'checkout with an unmerged path can be ignored' '
542 setup_conflicting_index &&
543 echo "none of the above" >sample &&
544 echo ourside >expect &&
545 cat sample >fild &&
546 cat sample >file &&
547 cat sample >filf &&
548 git checkout -f fild file filf &&
549 test_cmp expect fild &&
550 test_cmp expect filf &&
551 test_cmp sample file
552 '
553
554 test_expect_success 'checkout unmerged stage' '
555 setup_conflicting_index &&
556 echo "none of the above" >sample &&
557 echo ourside >expect &&
558 cat sample >fild &&
559 cat sample >file &&
560 cat sample >filf &&
561 git checkout --ours . &&
562 test_cmp expect fild &&
563 test_cmp expect filf &&
564 test_cmp expect file &&
565 git checkout --theirs file &&
566 test ztheirside = "z$(cat file)"
567 '
568
569 test_expect_success 'checkout --ours is incompatible with switching' '
570 test_must_fail git checkout --ours 2>error &&
571 test_grep "needs the paths to check out" error &&
572
573 test_must_fail git checkout --ours HEAD 2>error &&
574 test_grep "cannot be used with switching" error &&
575
576 test_must_fail git checkout --ours main 2>error &&
577 test_grep "cannot be used with switching" error &&
578
579 git checkout --ours file
580 '
581
582 test_expect_success 'checkout path with --merge from tree-ish is a no-no' '
583 setup_conflicting_index &&
584 test_must_fail git checkout -m HEAD -- file
585 '
586
587 test_expect_success 'checkout with --merge' '
588 setup_conflicting_index &&
589 echo "none of the above" >sample &&
590 echo ourside >expect &&
591 cat sample >fild &&
592 cat sample >file &&
593 cat sample >filf &&
594 git checkout -m -- fild file filf &&
595 (
596 echo "<<<<<<< ours" &&
597 echo ourside &&
598 echo "=======" &&
599 echo theirside &&
600 echo ">>>>>>> theirs"
601 ) >merged &&
602 test_cmp expect fild &&
603 test_cmp expect filf &&
604 test_cmp merged file
605 '
606
607 test_expect_success 'checkout -m works after (mistaken) resolution' '
608 setup_conflicting_index &&
609 echo "none of the above" >sample &&
610 cat sample >fild &&
611 cat sample >file &&
612 cat sample >filf &&
613 # resolve to something
614 git add file &&
615 git checkout --merge -- fild file filf &&
616 {
617 echo "<<<<<<< ours" &&
618 echo ourside &&
619 echo "=======" &&
620 echo theirside &&
621 echo ">>>>>>> theirs"
622 } >merged &&
623 test_cmp expect fild &&
624 test_cmp expect filf &&
625 test_cmp merged file
626 '
627
628 test_expect_success 'checkout -m works after (mistaken) resolution to remove' '
629 setup_conflicting_index &&
630 echo "none of the above" >sample &&
631 cat sample >fild &&
632 cat sample >file &&
633 cat sample >filf &&
634 # resolve to remove
635 git rm file &&
636 git checkout --merge -- fild file filf &&
637 {
638 echo "<<<<<<< ours" &&
639 echo ourside &&
640 echo "=======" &&
641 echo theirside &&
642 echo ">>>>>>> theirs"
643 } >merged &&
644 test_cmp expect fild &&
645 test_cmp expect filf &&
646 test_cmp merged file
647 '
648
649 test_expect_success 'checkout with --merge, in diff3 -m style' '
650 git config merge.conflictstyle diff3 &&
651 setup_conflicting_index &&
652 echo "none of the above" >sample &&
653 echo ourside >expect &&
654 cat sample >fild &&
655 cat sample >file &&
656 cat sample >filf &&
657 git checkout -m -- fild file filf &&
658 (
659 echo "<<<<<<< ours" &&
660 echo ourside &&
661 echo "||||||| base" &&
662 echo original &&
663 echo "=======" &&
664 echo theirside &&
665 echo ">>>>>>> theirs"
666 ) >merged &&
667 test_cmp expect fild &&
668 test_cmp expect filf &&
669 test_cmp merged file
670 '
671
672 test_expect_success 'checkout --conflict=merge, overriding config' '
673 git config merge.conflictstyle diff3 &&
674 setup_conflicting_index &&
675 echo "none of the above" >sample &&
676 echo ourside >expect &&
677 cat sample >fild &&
678 cat sample >file &&
679 cat sample >filf &&
680 git checkout --conflict=merge -- fild file filf &&
681 (
682 echo "<<<<<<< ours" &&
683 echo ourside &&
684 echo "=======" &&
685 echo theirside &&
686 echo ">>>>>>> theirs"
687 ) >merged &&
688 test_cmp expect fild &&
689 test_cmp expect filf &&
690 test_cmp merged file
691 '
692
693 test_expect_success 'checkout --conflict=diff3' '
694 test_unconfig merge.conflictstyle &&
695 setup_conflicting_index &&
696 echo "none of the above" >sample &&
697 echo ourside >expect &&
698 cat sample >fild &&
699 cat sample >file &&
700 cat sample >filf &&
701 git checkout --conflict=diff3 -- fild file filf &&
702 (
703 echo "<<<<<<< ours" &&
704 echo ourside &&
705 echo "||||||| base" &&
706 echo original &&
707 echo "=======" &&
708 echo theirside &&
709 echo ">>>>>>> theirs"
710 ) >merged &&
711 test_cmp expect fild &&
712 test_cmp expect filf &&
713 test_cmp merged file
714 '
715
716 test_expect_success 'checkout --conflict=diff3 --no-conflict does not merge' '
717 setup_conflicting_index &&
718 echo "none of the above" >expect &&
719 cat expect >fild &&
720 cat expect >file &&
721 test_must_fail git checkout --conflict=diff3 --no-conflict -- fild file 2>err &&
722 test_cmp expect file &&
723 test_cmp expect fild &&
724 echo "error: path ${SQ}file${SQ} is unmerged" >expect &&
725 test_cmp expect err
726 '
727
728 test_expect_success 'checkout --conflict=diff3 --no-merge does not merge' '
729 setup_conflicting_index &&
730 echo "none of the above" >expect &&
731 cat expect >fild &&
732 cat expect >file &&
733 test_must_fail git checkout --conflict=diff3 --no-merge -- fild file 2>err &&
734 test_cmp expect file &&
735 test_cmp expect fild &&
736 echo "error: path ${SQ}file${SQ} is unmerged" >expect &&
737 test_cmp expect err
738 '
739
740 test_expect_success 'checkout --no-merge --conflict=diff3 does merge' '
741 setup_conflicting_index &&
742 echo "none of the above" >fild &&
743 echo "none of the above" >file &&
744 git checkout --no-merge --conflict=diff3 -- fild file &&
745 echo "ourside" >expect &&
746 test_cmp expect fild &&
747 cat >expect <<-\EOF &&
748 <<<<<<< ours
749 ourside
750 ||||||| base
751 original
752 =======
753 theirside
754 >>>>>>> theirs
755 EOF
756 test_cmp expect file
757 '
758
759 test_expect_success 'checkout --merge --conflict=diff3 --no-conflict does merge' '
760 setup_conflicting_index &&
761 echo "none of the above" >fild &&
762 echo "none of the above" >file &&
763 git checkout --merge --conflict=diff3 --no-conflict -- fild file &&
764 echo "ourside" >expect &&
765 test_cmp expect fild &&
766 cat >expect <<-\EOF &&
767 <<<<<<< ours
768 ourside
769 =======
770 theirside
771 >>>>>>> theirs
772 EOF
773 test_cmp expect file
774 '
775
776 test_expect_success 'checkout with invalid conflict style' '
777 test_must_fail git checkout --conflict=bad 2>actual -- file &&
778 echo "error: unknown conflict style ${SQ}bad${SQ}" >expect &&
779 test_cmp expect actual
780 '
781
782 test_expect_success 'failing checkout -b should not break working tree' '
783 git clean -fd && # Remove untracked files in the way
784 git reset --hard main &&
785 git symbolic-ref HEAD refs/heads/main &&
786 test_must_fail git checkout -b renamer side^ &&
787 test $(git symbolic-ref HEAD) = refs/heads/main &&
788 git diff --exit-code &&
789 git diff --cached --exit-code
790 '
791
792 test_expect_success 'switch out of non-branch' '
793 git reset --hard main &&
794 git checkout main^0 &&
795 echo modified >one &&
796 test_must_fail git checkout renamer 2>error.log &&
797 test_grep ! "^Previous HEAD" error.log
798 '
799
800 (
801 echo "#!$SHELL_PATH"
802 cat <<\EOF
803 O=$1 A=$2 B=$3
804 cat "$A" >.tmp
805 exec >"$A"
806 echo '<<<<<<< filfre-theirs'
807 cat "$B"
808 echo '||||||| filfre-common'
809 cat "$O"
810 echo '======='
811 cat ".tmp"
812 echo '>>>>>>> filfre-ours'
813 rm -f .tmp
814 exit 1
815 EOF
816 ) >filfre.sh
817 chmod +x filfre.sh
818
819 test_expect_success 'custom merge driver with checkout -m' '
820 git reset --hard &&
821
822 git config merge.filfre.driver "./filfre.sh %O %A %B" &&
823 git config merge.filfre.name "Feel-free merge driver" &&
824 git config merge.filfre.recursive binary &&
825 echo "arm merge=filfre" >.gitattributes &&
826
827 git checkout -b left &&
828 echo neutral >arm &&
829 git add arm .gitattributes &&
830 test_tick &&
831 git commit -m neutral &&
832 git branch right &&
833
834 echo left >arm &&
835 test_tick &&
836 git commit -a -m left &&
837 git checkout right &&
838
839 echo right >arm &&
840 test_tick &&
841 git commit -a -m right &&
842
843 test_must_fail git merge left &&
844 (
845 for t in filfre-common left right
846 do
847 test_grep $t arm || exit 1
848 done
849 ) &&
850
851 mv arm expect &&
852 git checkout -m arm &&
853 test_cmp expect arm
854 '
855
856 test_expect_success 'tracking info copied with autoSetupMerge=inherit' '
857 git reset --hard main &&
858 # default config does not copy tracking info
859 git checkout -b foo-no-inherit koala/bear &&
860 test_cmp_config "" --default "" branch.foo-no-inherit.remote &&
861 test_cmp_config "" --default "" branch.foo-no-inherit.merge &&
862 # with autoSetupMerge=inherit, we copy tracking info from koala/bear
863 test_config branch.autoSetupMerge inherit &&
864 git checkout -b foo koala/bear &&
865 test_cmp_config origin branch.foo.remote &&
866 test_cmp_config refs/heads/koala/bear branch.foo.merge &&
867 # no tracking info to inherit from main
868 git checkout -b main2 main &&
869 test_cmp_config "" --default "" branch.main2.remote &&
870 test_cmp_config "" --default "" branch.main2.merge
871 '
872
873 test_expect_success 'setup upstream for --track=fetch tests' '
874 git checkout main &&
875 git init fetch_upstream &&
876 test_commit -C fetch_upstream u_main &&
877 git remote add fetch_upstream fetch_upstream &&
878 git fetch fetch_upstream &&
879 git -C fetch_upstream checkout -b fetch_new &&
880 test_commit -C fetch_upstream u_new
881 '
882
883 test_expect_success 'checkout --track=fetch -b picks up branch created upstream after clone' '
884 git checkout main &&
885 test_must_fail git rev-parse --verify refs/remotes/fetch_upstream/fetch_new &&
886 git checkout --track=fetch -b local_new fetch_upstream/fetch_new &&
887 test_cmp_rev refs/remotes/fetch_upstream/fetch_new HEAD &&
888 test_cmp_config fetch_upstream branch.local_new.remote &&
889 test_cmp_config refs/heads/fetch_new branch.local_new.merge
890 '
891
892 test_expect_success 'checkout --track=fetch <remote>/<branch> leaves other tracking branches untouched' '
893 git checkout main &&
894 git -C fetch_upstream checkout -b fetch_target &&
895 test_commit -C fetch_upstream u_target_pre &&
896 git -C fetch_upstream checkout -b fetch_other &&
897 test_commit -C fetch_upstream u_other_pre &&
898 git fetch fetch_upstream &&
899 git update-ref refs/heads/snapshot_other refs/remotes/fetch_upstream/fetch_other &&
900 git -C fetch_upstream checkout fetch_target &&
901 test_commit -C fetch_upstream u_target_post &&
902 git -C fetch_upstream checkout fetch_other &&
903 test_commit -C fetch_upstream u_other_post &&
904 git checkout --track=fetch -b local_target fetch_upstream/fetch_target &&
905 test_cmp_rev refs/remotes/fetch_upstream/fetch_target HEAD &&
906 test_cmp_rev refs/remotes/fetch_upstream/fetch_other snapshot_other
907 '
908
909 test_expect_success 'checkout --track=fetch with bare remote name fetches only <remote>/HEAD target' '
910 git checkout main &&
911 git -C fetch_upstream checkout main &&
912 git remote set-head fetch_upstream main &&
913 git -C fetch_upstream checkout -b fetch_unrelated &&
914 test_commit -C fetch_upstream u_unrelated_pre &&
915 git fetch fetch_upstream fetch_unrelated &&
916 git update-ref refs/heads/snapshot_unrelated \
917 refs/remotes/fetch_upstream/fetch_unrelated &&
918 git -C fetch_upstream checkout main &&
919 test_commit -C fetch_upstream u_main_post &&
920 git -C fetch_upstream checkout fetch_unrelated &&
921 test_commit -C fetch_upstream u_unrelated_post &&
922 git checkout --track=fetch -b local_from_remote fetch_upstream &&
923 test_cmp_rev refs/remotes/fetch_upstream/main HEAD &&
924 test_cmp_rev refs/remotes/fetch_upstream/fetch_unrelated snapshot_unrelated
925 '
926
927 test_expect_success 'checkout --track=fetch aborts and does not create branch when no existing ref' '
928 git checkout main &&
929 test_might_fail git branch -D bogus &&
930 test_must_fail git checkout --track=fetch -b bogus fetch_upstream/does_not_exist &&
931 test_must_fail git rev-parse --verify refs/heads/bogus
932 '
933
934 test_expect_success 'checkout --track=fetch warns and proceeds when fetch fails but ref exists' '
935 git checkout main &&
936 git -C fetch_upstream checkout -b fetch_offline &&
937 test_commit -C fetch_upstream u_offline &&
938 git fetch fetch_upstream fetch_offline &&
939 saved_url=$(git config remote.fetch_upstream.url) &&
940 test_when_finished "git config remote.fetch_upstream.url \"$saved_url\"" &&
941 git config remote.fetch_upstream.url ./does-not-exist &&
942 git checkout --track=fetch -b local_offline fetch_upstream/fetch_offline 2>err &&
943 test_grep "failed to fetch" err &&
944 test_cmp_rev refs/remotes/fetch_upstream/fetch_offline HEAD
945 '
946
947 test_expect_success 'checkout --track=fetch resolves through configured fetch refspec' '
948 git checkout main &&
949 git remote add fetch_custom ./fetch_upstream &&
950 test_when_finished "git remote remove fetch_custom" &&
951 git config --replace-all remote.fetch_custom.fetch \
952 "+refs/heads/*:refs/remotes/custom-ns/*" &&
953 git -C fetch_upstream checkout -b fetch_refspec &&
954 test_commit -C fetch_upstream u_refspec &&
955 test_must_fail git rev-parse --verify refs/remotes/custom-ns/fetch_refspec &&
956 git checkout --track=fetch -b local_refspec custom-ns/fetch_refspec &&
957 test_cmp_rev refs/remotes/custom-ns/fetch_refspec HEAD
958 '
959
960 test_expect_success 'checkout --track=fetch on bare remote-tracking prefix follows <prefix>/HEAD' '
961 git checkout main &&
962 git remote add fetch_ns ./fetch_upstream &&
963 test_when_finished "git remote remove fetch_ns" &&
964 test_when_finished "git update-ref -d refs/remotes/ns_alias/HEAD" &&
965 git config --replace-all remote.fetch_ns.fetch \
966 "+refs/heads/*:refs/remotes/ns_alias/*" &&
967 git fetch fetch_ns &&
968 git symbolic-ref refs/remotes/ns_alias/HEAD refs/remotes/ns_alias/main &&
969 git -C fetch_upstream checkout main &&
970 test_commit -C fetch_upstream u_ns_post &&
971 git checkout --track=fetch -b local_ns ns_alias &&
972 test_cmp_rev refs/remotes/ns_alias/main HEAD &&
973 test_cmp_config fetch_ns branch.local_ns.remote &&
974 test_cmp_config refs/heads/main branch.local_ns.merge
975 '
976
977 test_expect_success 'checkout --track=fetch dies on bare remote name with no <ns>/HEAD' '
978 git checkout main &&
979 git remote add fetch_nohead ./fetch_upstream &&
980 test_when_finished "git remote remove fetch_nohead" &&
981 test_might_fail git symbolic-ref -d refs/remotes/fetch_nohead/HEAD &&
982 test_must_fail git checkout --track=fetch -b local_nohead fetch_nohead 2>err &&
983 test_grep "refs/remotes/fetch_nohead/HEAD" err &&
984 test_grep "git remote set-head fetch_nohead --auto" err &&
985 test_must_fail git rev-parse --verify refs/heads/local_nohead
986 '
987
988 test_expect_success 'checkout --track=fetch on bare unknown name does not suggest set-head' '
989 git checkout main &&
990 test_must_fail git rev-parse --verify refs/remotes/no_such_ns/HEAD &&
991 test_must_fail git config --get remote.no_such_ns.url &&
992 test_must_fail git checkout --track=fetch -b local_unknown no_such_ns 2>err &&
993 test_grep "no configured remote" err &&
994 test_grep ! "set-head" err &&
995 test_must_fail git rev-parse --verify refs/heads/local_unknown
996 '
997
998 test_expect_success 'checkout --track=fetch rejects <ns>/HEAD pointing outside the tracking prefix' '
999 git checkout main &&
1000 git remote add fetch_crossns ./fetch_upstream &&
1001 test_when_finished "git remote remove fetch_crossns" &&
1002 test_when_finished "git update-ref -d refs/remotes/fetch_crossns/HEAD" &&
1003 git fetch fetch_crossns &&
1004 git symbolic-ref refs/remotes/fetch_crossns/HEAD \
1005 refs/remotes/fetch_upstream/u_main &&
1006 test_must_fail git checkout --track=fetch -b local_crossns fetch_crossns 2>err &&
1007 test_grep "refs/remotes/fetch_crossns/HEAD" err &&
1008 test_must_fail git rev-parse --verify refs/heads/local_crossns
1009 '
1010
1011 test_expect_success 'checkout --track=fetch dies on ambiguous fetch refspec match' '
1012 git checkout main &&
1013 git remote add fetch_ambig_a ./fetch_upstream &&
1014 git remote add fetch_ambig_b ./fetch_upstream &&
1015 test_when_finished "git remote remove fetch_ambig_a" &&
1016 test_when_finished "git remote remove fetch_ambig_b" &&
1017 git config --replace-all remote.fetch_ambig_a.fetch \
1018 "+refs/heads/*:refs/remotes/ambig_ns/*" &&
1019 git config --replace-all remote.fetch_ambig_b.fetch \
1020 "+refs/heads/*:refs/remotes/ambig_ns/*" &&
1021 git -C fetch_upstream checkout -b fetch_ambig &&
1022 test_commit -C fetch_upstream u_ambig &&
1023 test_must_fail git checkout --track=fetch -b local_ambig ambig_ns/fetch_ambig 2>err &&
1024 test_grep "fetch_ambig_a" err &&
1025 test_grep "fetch_ambig_b" err &&
1026 test_grep "tracking namespaces" err &&
1027 test_must_fail git rev-parse --verify refs/heads/local_ambig
1028 '
1029
1030 test_expect_success 'checkout --track=fetch rejects invalid refname components' '
1031 git checkout main &&
1032 test_must_fail git checkout --track=fetch -b local_invalid "foo..bar" 2>err &&
1033 test_grep "valid" err &&
1034 test_must_fail git rev-parse --verify refs/heads/local_invalid
1035 '
1036
1037 test_expect_success 'checkout --track=inherit,direct is rejected' '
1038 test_must_fail git checkout --track=inherit,direct -b bad fetch_upstream/fetch_new 2>err &&
1039 test_grep "cannot combine" err
1040 '
1041
1042 test_expect_success 'checkout --track=fetch then --track=direct drops fetch (last-one-wins)' '
1043 git checkout main &&
1044 git -C fetch_upstream checkout -b fetch_lastwin &&
1045 test_commit -C fetch_upstream u_lastwin &&
1046 test_must_fail git rev-parse --verify refs/remotes/fetch_upstream/fetch_lastwin &&
1047 test_must_fail git checkout --track=fetch --track=direct \
1048 -b local_lastwin fetch_upstream/fetch_lastwin &&
1049 test_must_fail git rev-parse --verify refs/remotes/fetch_upstream/fetch_lastwin
1050 '
1051
1052 test_expect_success 'checkout --track=fetch,inherit fetches remote-tracking start-point' '
1053 git checkout main &&
1054 git -C fetch_upstream checkout -b fetch_inherit &&
1055 test_commit -C fetch_upstream u_inherit &&
1056 test_must_fail git rev-parse --verify refs/remotes/fetch_upstream/fetch_inherit &&
1057 git checkout --track=fetch,inherit -b local_inherit \
1058 fetch_upstream/fetch_inherit &&
1059 test_cmp_rev refs/remotes/fetch_upstream/fetch_inherit HEAD
1060 '
1061
1062 test_expect_success 'checkout --track=fetch on local start-point errors' '
1063 git checkout main &&
1064 test_must_fail git checkout --track=fetch -b bad main 2>err &&
1065 test_grep "no configured remote" err &&
1066 test_must_fail git rev-parse --verify refs/heads/bad
1067 '
1068
1069 test_expect_success 'checkout --track=bogus reports an error' '
1070 git checkout main &&
1071 test_must_fail git checkout --track=bogus -b bogus_branch fetch_upstream/fetch_new 2>err &&
1072 test_grep "expects" err
1073 '
1074
1075 test_expect_success 'checkout -q --track=fetch silences the fetch output' '
1076 git checkout main &&
1077 git -C fetch_upstream checkout -b fetch_quiet &&
1078 test_commit -C fetch_upstream u_quiet &&
1079 test_must_fail git rev-parse --verify refs/remotes/fetch_upstream/fetch_quiet &&
1080 git checkout -q --track=fetch -b local_quiet \
1081 fetch_upstream/fetch_quiet 2>err &&
1082 test_grep ! "-> fetch_upstream/fetch_quiet" err &&
1083 test_cmp_rev refs/remotes/fetch_upstream/fetch_quiet HEAD
1084 '
1085
1086 test_expect_success 'switch --track=fetch -c picks up branch created upstream after clone' '
1087 git checkout main &&
1088 git -C fetch_upstream checkout -b fetch_switch &&
1089 test_commit -C fetch_upstream u_switch &&
1090 test_must_fail git rev-parse --verify refs/remotes/fetch_upstream/fetch_switch &&
1091 git switch --track=fetch -c local_switch fetch_upstream/fetch_switch &&
1092 test_cmp_rev refs/remotes/fetch_upstream/fetch_switch HEAD
1093 '
1094
1095 test_done