stash: learn to parse -m/--message like commit does
[git] / t / t7201-co.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2006 Junio C Hamano
4 #
5
6 test_description='git checkout tests.
7
8 Creates master, forks renamer and side branches from it.
9 Test switching across them.
10
11   ! [master] 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   +*++ [master] Initial A one, A two
20
21 '
22
23 . ./test-lib.sh
24
25 test_tick
26
27 fill () {
28         for i
29         do
30                 echo "$i"
31         done
32 }
33
34
35 test_expect_success setup '
36
37         fill x y z > same &&
38         fill 1 2 3 4 5 6 7 8 >one &&
39         fill a b c d e >two &&
40         git add same one two &&
41         git commit -m "Initial A one, A two" &&
42
43         git checkout -b renamer &&
44         rm -f one &&
45         fill 1 3 4 5 6 7 8 >uno &&
46         git add uno &&
47         fill a b c d e f >two &&
48         git commit -a -m "Renamer R one->uno, M two" &&
49
50         git checkout -b side master &&
51         fill 1 2 3 4 5 6 7 >one &&
52         fill A B C D E >three &&
53         rm -f two &&
54         git update-index --add --remove one two three &&
55         git commit -m "Side M one, D two, A three" &&
56
57         git checkout -b simple master &&
58         rm -f one &&
59         fill a c e > two &&
60         git commit -a -m "Simple D one, M two" &&
61
62         git checkout master
63 '
64
65 test_expect_success "checkout from non-existing branch" '
66
67         git checkout -b delete-me master &&
68         rm .git/refs/heads/delete-me &&
69         test refs/heads/delete-me = "$(git symbolic-ref HEAD)" &&
70         git checkout master &&
71         test refs/heads/master = "$(git symbolic-ref HEAD)"
72 '
73
74 test_expect_success "checkout with dirty tree without -m" '
75
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
87 test_expect_success "checkout with unrelated dirty tree without -m" '
88
89         git checkout -f master &&
90         fill 0 1 2 3 4 5 6 7 8 >same &&
91         cp same kept &&
92         git checkout side >messages &&
93         test_cmp same kept &&
94         printf "M\t%s\n" same >messages.expect &&
95         test_cmp messages.expect messages
96 '
97
98 test_expect_success "checkout -m with dirty tree" '
99
100         git checkout -f master &&
101         git clean -f &&
102
103         fill 0 1 2 3 4 5 6 7 8 >one &&
104         git checkout -m side > messages &&
105
106         test "$(git symbolic-ref HEAD)" = "refs/heads/side" &&
107
108         printf "M\t%s\n" one >expect.messages &&
109         test_cmp expect.messages messages &&
110
111         fill "M one" "A three" "D       two" >expect.master &&
112         git diff --name-status master >current.master &&
113         test_cmp expect.master current.master &&
114
115         fill "M one" >expect.side &&
116         git diff --name-status side >current.side &&
117         test_cmp expect.side current.side &&
118
119         : >expect.index &&
120         git diff --cached >current.index &&
121         test_cmp expect.index current.index
122 '
123
124 test_expect_success "checkout -m with dirty tree, renamed" '
125
126         git checkout -f master && git clean -f &&
127
128         fill 1 2 3 4 5 7 8 >one &&
129         if git checkout renamer
130         then
131                 echo Not happy
132                 false
133         else
134                 echo "happy - failed correctly"
135         fi &&
136
137         git checkout -m renamer &&
138         fill 1 3 4 5 7 8 >expect &&
139         test_cmp expect uno &&
140         ! test -f one &&
141         git diff --cached >current &&
142         ! test -s current
143
144 '
145
146 test_expect_success 'checkout -m with merge conflict' '
147
148         git checkout -f master && git clean -f &&
149
150         fill 1 T 3 4 5 6 S 8 >one &&
151         if git checkout renamer
152         then
153                 echo Not happy
154                 false
155         else
156                 echo "happy - failed correctly"
157         fi &&
158
159         git checkout -m renamer &&
160
161         git diff master:one :3:uno |
162         sed -e "1,/^@@/d" -e "/^ /d" -e "s/^-/d/" -e "s/^+/a/" >current &&
163         fill d2 aT d7 aS >expect &&
164         test_cmp current expect &&
165         git diff --cached two >current &&
166         ! test -s current
167 '
168
169 test_expect_success 'format of merge conflict from checkout -m' '
170
171         git checkout -f master && git clean -f &&
172
173         fill b d > two &&
174         git checkout -m simple &&
175
176         git ls-files >current &&
177         fill same two two two >expect &&
178         test_cmp current expect &&
179
180         cat <<-EOF >expect &&
181         <<<<<<< simple
182         a
183         c
184         e
185         =======
186         b
187         d
188         >>>>>>> local
189         EOF
190         test_cmp two expect
191 '
192
193 test_expect_success 'checkout --merge --conflict=diff3 <branch>' '
194
195         git checkout -f master && git reset --hard && git clean -f &&
196
197         fill b d > two &&
198         git checkout --merge --conflict=diff3 simple &&
199
200         cat <<-EOF >expect &&
201         <<<<<<< simple
202         a
203         c
204         e
205         ||||||| master
206         a
207         b
208         c
209         d
210         e
211         =======
212         b
213         d
214         >>>>>>> local
215         EOF
216         test_cmp two expect
217 '
218
219 test_expect_success 'switch to another branch while carrying a deletion' '
220
221         git checkout -f master && git reset --hard && git clean -f &&
222         git rm two &&
223
224         test_must_fail git checkout simple 2>errs &&
225         test_i18ngrep overwritten errs &&
226
227         git checkout --merge simple 2>errs &&
228         test_i18ngrep ! overwritten errs &&
229         git ls-files -u &&
230         test_must_fail git cat-file -t :0:two &&
231         test "$(git cat-file -t :1:two)" = blob &&
232         test "$(git cat-file -t :2:two)" = blob &&
233         test_must_fail git cat-file -t :3:two
234 '
235
236 test_expect_success 'checkout to detach HEAD (with advice declined)' '
237
238         git config advice.detachedHead false &&
239         git checkout -f renamer && git clean -f &&
240         git checkout renamer^ 2>messages &&
241         test_i18ngrep "HEAD is now at 7329388" messages &&
242         test_line_count = 1 messages &&
243         H=$(git rev-parse --verify HEAD) &&
244         M=$(git show-ref -s --verify refs/heads/master) &&
245         test "z$H" = "z$M" &&
246         if git symbolic-ref HEAD >/dev/null 2>&1
247         then
248                 echo "OOPS, HEAD is still symbolic???"
249                 false
250         else
251                 : happy
252         fi
253 '
254
255 test_expect_success 'checkout to detach HEAD' '
256         git config advice.detachedHead true &&
257         git checkout -f renamer && git clean -f &&
258         git checkout renamer^ 2>messages &&
259         test_i18ngrep "HEAD is now at 7329388" messages &&
260         (test_line_count -gt 1 messages || test -n "$GETTEXT_POISON") &&
261         H=$(git rev-parse --verify HEAD) &&
262         M=$(git show-ref -s --verify refs/heads/master) &&
263         test "z$H" = "z$M" &&
264         if git symbolic-ref HEAD >/dev/null 2>&1
265         then
266                 echo "OOPS, HEAD is still symbolic???"
267                 false
268         else
269                 : happy
270         fi
271 '
272
273 test_expect_success 'checkout to detach HEAD with branchname^' '
274
275         git checkout -f master && git clean -f &&
276         git checkout renamer^ &&
277         H=$(git rev-parse --verify HEAD) &&
278         M=$(git show-ref -s --verify refs/heads/master) &&
279         test "z$H" = "z$M" &&
280         if git symbolic-ref HEAD >/dev/null 2>&1
281         then
282                 echo "OOPS, HEAD is still symbolic???"
283                 false
284         else
285                 : happy
286         fi
287 '
288
289 test_expect_success 'checkout to detach HEAD with :/message' '
290
291         git checkout -f master && git clean -f &&
292         git checkout ":/Initial" &&
293         H=$(git rev-parse --verify HEAD) &&
294         M=$(git show-ref -s --verify refs/heads/master) &&
295         test "z$H" = "z$M" &&
296         if git symbolic-ref HEAD >/dev/null 2>&1
297         then
298                 echo "OOPS, HEAD is still symbolic???"
299                 false
300         else
301                 : happy
302         fi
303 '
304
305 test_expect_success 'checkout to detach HEAD with HEAD^0' '
306
307         git checkout -f master && git clean -f &&
308         git checkout HEAD^0 &&
309         H=$(git rev-parse --verify HEAD) &&
310         M=$(git show-ref -s --verify refs/heads/master) &&
311         test "z$H" = "z$M" &&
312         if git symbolic-ref HEAD >/dev/null 2>&1
313         then
314                 echo "OOPS, HEAD is still symbolic???"
315                 false
316         else
317                 : happy
318         fi
319 '
320
321 test_expect_success 'checkout with ambiguous tag/branch names' '
322
323         git tag both side &&
324         git branch both master &&
325         git reset --hard &&
326         git checkout master &&
327
328         git checkout both &&
329         H=$(git rev-parse --verify HEAD) &&
330         M=$(git show-ref -s --verify refs/heads/master) &&
331         test "z$H" = "z$M" &&
332         name=$(git symbolic-ref HEAD 2>/dev/null) &&
333         test "z$name" = zrefs/heads/both
334
335 '
336
337 test_expect_success 'checkout with ambiguous tag/branch names' '
338
339         git reset --hard &&
340         git checkout master &&
341
342         git tag frotz side &&
343         git branch frotz master &&
344         git reset --hard &&
345         git checkout master &&
346
347         git checkout tags/frotz &&
348         H=$(git rev-parse --verify HEAD) &&
349         S=$(git show-ref -s --verify refs/heads/side) &&
350         test "z$H" = "z$S" &&
351         if name=$(git symbolic-ref HEAD 2>/dev/null)
352         then
353                 echo "Bad -- should have detached"
354                 false
355         else
356                 : happy
357         fi
358
359 '
360
361 test_expect_success 'switch branches while in subdirectory' '
362
363         git reset --hard &&
364         git checkout master &&
365
366         mkdir subs &&
367         (
368                 cd subs &&
369                 git checkout side
370         ) &&
371         ! test -f subs/one &&
372         rm -fr subs
373
374 '
375
376 test_expect_success 'checkout specific path while in subdirectory' '
377
378         git reset --hard &&
379         git checkout side &&
380         mkdir subs &&
381         >subs/bero &&
382         git add subs/bero &&
383         git commit -m "add subs/bero" &&
384
385         git checkout master &&
386         mkdir -p subs &&
387         (
388                 cd subs &&
389                 git checkout side -- bero
390         ) &&
391         test -f subs/bero
392
393 '
394
395 test_expect_success \
396     'checkout w/--track sets up tracking' '
397     git config branch.autosetupmerge false &&
398     git checkout master &&
399     git checkout --track -b track1 &&
400     test "$(git config branch.track1.remote)" &&
401     test "$(git config branch.track1.merge)"'
402
403 test_expect_success \
404     'checkout w/autosetupmerge=always sets up tracking' '
405     test_when_finished git config branch.autosetupmerge false &&
406     git config branch.autosetupmerge always &&
407     git checkout master &&
408     git checkout -b track2 &&
409     test "$(git config branch.track2.remote)" &&
410     test "$(git config branch.track2.merge)"'
411
412 test_expect_success 'checkout w/--track from non-branch HEAD fails' '
413     git checkout master^0 &&
414     test_must_fail git symbolic-ref HEAD &&
415     test_must_fail git checkout --track -b track &&
416     test_must_fail git rev-parse --verify track &&
417     test_must_fail git symbolic-ref HEAD &&
418     test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
419 '
420
421 test_expect_success 'checkout w/--track from tag fails' '
422     git checkout master^0 &&
423     test_must_fail git symbolic-ref HEAD &&
424     test_must_fail git checkout --track -b track frotz &&
425     test_must_fail git rev-parse --verify track &&
426     test_must_fail git symbolic-ref HEAD &&
427     test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
428 '
429
430 test_expect_success 'detach a symbolic link HEAD' '
431     git checkout master &&
432     git config --bool core.prefersymlinkrefs yes &&
433     git checkout side &&
434     git checkout master &&
435     it=$(git symbolic-ref HEAD) &&
436     test "z$it" = zrefs/heads/master &&
437     here=$(git rev-parse --verify refs/heads/master) &&
438     git checkout side^ &&
439     test "z$(git rev-parse --verify refs/heads/master)" = "z$here"
440 '
441
442 test_expect_success \
443     'checkout with --track fakes a sensible -b <name>' '
444     git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" &&
445     git update-ref refs/remotes/origin/koala/bear renamer &&
446
447     git checkout --track origin/koala/bear &&
448     test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
449     test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
450
451     git checkout master && git branch -D koala/bear &&
452
453     git checkout --track refs/remotes/origin/koala/bear &&
454     test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
455     test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
456
457     git checkout master && git branch -D koala/bear &&
458
459     git checkout --track remotes/origin/koala/bear &&
460     test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
461     test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
462 '
463
464 test_expect_success \
465     'checkout with --track, but without -b, fails with too short tracked name' '
466     test_must_fail git checkout --track renamer'
467
468 setup_conflicting_index () {
469         rm -f .git/index &&
470         O=$(echo original | git hash-object -w --stdin) &&
471         A=$(echo ourside | git hash-object -w --stdin) &&
472         B=$(echo theirside | git hash-object -w --stdin) &&
473         (
474                 echo "100644 $A 0       fild" &&
475                 echo "100644 $O 1       file" &&
476                 echo "100644 $A 2       file" &&
477                 echo "100644 $B 3       file" &&
478                 echo "100644 $A 0       filf"
479         ) | git update-index --index-info
480 }
481
482 test_expect_success 'checkout an unmerged path should fail' '
483         setup_conflicting_index &&
484         echo "none of the above" >sample &&
485         cat sample >fild &&
486         cat sample >file &&
487         cat sample >filf &&
488         test_must_fail git checkout fild file filf &&
489         test_cmp sample fild &&
490         test_cmp sample filf &&
491         test_cmp sample file
492 '
493
494 test_expect_success 'checkout with an unmerged path can be ignored' '
495         setup_conflicting_index &&
496         echo "none of the above" >sample &&
497         echo ourside >expect &&
498         cat sample >fild &&
499         cat sample >file &&
500         cat sample >filf &&
501         git checkout -f fild file filf &&
502         test_cmp expect fild &&
503         test_cmp expect filf &&
504         test_cmp sample file
505 '
506
507 test_expect_success 'checkout unmerged stage' '
508         setup_conflicting_index &&
509         echo "none of the above" >sample &&
510         echo ourside >expect &&
511         cat sample >fild &&
512         cat sample >file &&
513         cat sample >filf &&
514         git checkout --ours . &&
515         test_cmp expect fild &&
516         test_cmp expect filf &&
517         test_cmp expect file &&
518         git checkout --theirs file &&
519         test ztheirside = "z$(cat file)"
520 '
521
522 test_expect_success 'checkout with --merge' '
523         setup_conflicting_index &&
524         echo "none of the above" >sample &&
525         echo ourside >expect &&
526         cat sample >fild &&
527         cat sample >file &&
528         cat sample >filf &&
529         git checkout -m -- fild file filf &&
530         (
531                 echo "<<<<<<< ours"
532                 echo ourside
533                 echo "======="
534                 echo theirside
535                 echo ">>>>>>> theirs"
536         ) >merged &&
537         test_cmp expect fild &&
538         test_cmp expect filf &&
539         test_cmp merged file
540 '
541
542 test_expect_success 'checkout with --merge, in diff3 -m style' '
543         git config merge.conflictstyle diff3 &&
544         setup_conflicting_index &&
545         echo "none of the above" >sample &&
546         echo ourside >expect &&
547         cat sample >fild &&
548         cat sample >file &&
549         cat sample >filf &&
550         git checkout -m -- fild file filf &&
551         (
552                 echo "<<<<<<< ours"
553                 echo ourside
554                 echo "||||||| base"
555                 echo original
556                 echo "======="
557                 echo theirside
558                 echo ">>>>>>> theirs"
559         ) >merged &&
560         test_cmp expect fild &&
561         test_cmp expect filf &&
562         test_cmp merged file
563 '
564
565 test_expect_success 'checkout --conflict=merge, overriding config' '
566         git config merge.conflictstyle diff3 &&
567         setup_conflicting_index &&
568         echo "none of the above" >sample &&
569         echo ourside >expect &&
570         cat sample >fild &&
571         cat sample >file &&
572         cat sample >filf &&
573         git checkout --conflict=merge -- fild file filf &&
574         (
575                 echo "<<<<<<< ours"
576                 echo ourside
577                 echo "======="
578                 echo theirside
579                 echo ">>>>>>> theirs"
580         ) >merged &&
581         test_cmp expect fild &&
582         test_cmp expect filf &&
583         test_cmp merged file
584 '
585
586 test_expect_success 'checkout --conflict=diff3' '
587         test_unconfig merge.conflictstyle &&
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 --conflict=diff3 -- fild file filf &&
595         (
596                 echo "<<<<<<< ours"
597                 echo ourside
598                 echo "||||||| base"
599                 echo original
600                 echo "======="
601                 echo theirside
602                 echo ">>>>>>> theirs"
603         ) >merged &&
604         test_cmp expect fild &&
605         test_cmp expect filf &&
606         test_cmp merged file
607 '
608
609 test_expect_success 'failing checkout -b should not break working tree' '
610         git reset --hard master &&
611         git symbolic-ref HEAD refs/heads/master &&
612         test_must_fail git checkout -b renamer side^ &&
613         test $(git symbolic-ref HEAD) = refs/heads/master &&
614         git diff --exit-code &&
615         git diff --cached --exit-code
616
617 '
618
619 test_expect_success 'switch out of non-branch' '
620         git reset --hard master &&
621         git checkout master^0 &&
622         echo modified >one &&
623         test_must_fail git checkout renamer 2>error.log &&
624         ! grep "^Previous HEAD" error.log
625 '
626
627 (
628  echo "#!$SHELL_PATH"
629  cat <<\EOF
630 O=$1 A=$2 B=$3
631 cat "$A" >.tmp
632 exec >"$A"
633 echo '<<<<<<< filfre-theirs'
634 cat "$B"
635 echo '||||||| filfre-common'
636 cat "$O"
637 echo '======='
638 cat ".tmp"
639 echo '>>>>>>> filfre-ours'
640 rm -f .tmp
641 exit 1
642 EOF
643 ) >filfre.sh
644 chmod +x filfre.sh
645
646 test_expect_success 'custom merge driver with checkout -m' '
647         git reset --hard &&
648
649         git config merge.filfre.driver "./filfre.sh %O %A %B" &&
650         git config merge.filfre.name "Feel-free merge driver" &&
651         git config merge.filfre.recursive binary &&
652         echo "arm merge=filfre" >.gitattributes &&
653
654         git checkout -b left &&
655         echo neutral >arm &&
656         git add arm .gitattributes &&
657         test_tick &&
658         git commit -m neutral &&
659         git branch right &&
660
661         echo left >arm &&
662         test_tick &&
663         git commit -a -m left &&
664         git checkout right &&
665
666         echo right >arm &&
667         test_tick &&
668         git commit -a -m right &&
669
670         test_must_fail git merge left &&
671         (
672                 for t in filfre-common left right
673                 do
674                         grep $t arm || exit 1
675                 done
676                 exit 0
677         ) &&
678
679         mv arm expect &&
680         git checkout -m arm &&
681         test_cmp expect arm
682 '
683
684 test_done