Merge branch 'jc/maint-verify-objects-remove-pessimism'
[git] / t / t7600-merge.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2007 Lars Hjemli
4 #
5
6 test_description='git merge
7
8 Testing basic merge operations/option parsing.
9
10 ! [c0] commit 0
11  ! [c1] commit 1
12   ! [c2] commit 2
13    ! [c3] commit 3
14     ! [c4] c4
15      ! [c5] c5
16       ! [c6] c6
17        * [master] Merge commit 'c1'
18 --------
19        - [master] Merge commit 'c1'
20  +     * [c1] commit 1
21       +  [c6] c6
22      +   [c5] c5
23     ++   [c4] c4
24    ++++  [c3] commit 3
25   +      [c2] commit 2
26 +++++++* [c0] commit 0
27 '
28
29 . ./test-lib.sh
30 . "$TEST_DIRECTORY"/lib-gpg.sh
31
32 printf '%s\n' 1 2 3 4 5 6 7 8 9 >file
33 printf '%s\n' '1 X' 2 3 4 5 6 7 8 9 >file.1
34 printf '%s\n' 1 2 3 4 '5 X' 6 7 8 9 >file.5
35 printf '%s\n' 1 2 3 4 5 6 7 8 '9 X' >file.9
36 printf '%s\n' '1 X' 2 3 4 5 6 7 8 9 >result.1
37 printf '%s\n' '1 X' 2 3 4 '5 X' 6 7 8 9 >result.1-5
38 printf '%s\n' '1 X' 2 3 4 '5 X' 6 7 8 '9 X' >result.1-5-9
39 >empty
40
41 create_merge_msgs () {
42         echo "Merge tag 'c2'" >msg.1-5 &&
43         echo "Merge tags 'c2' and 'c3'" >msg.1-5-9 &&
44         {
45                 echo "Squashed commit of the following:" &&
46                 echo &&
47                 git log --no-merges ^HEAD c1
48         } >squash.1 &&
49         {
50                 echo "Squashed commit of the following:" &&
51                 echo &&
52                 git log --no-merges ^HEAD c2
53         } >squash.1-5 &&
54         {
55                 echo "Squashed commit of the following:" &&
56                 echo &&
57                 git log --no-merges ^HEAD c2 c3
58         } >squash.1-5-9 &&
59         echo >msg.nolog &&
60         {
61                 echo "* tag 'c3':" &&
62                 echo "  commit 3" &&
63                 echo
64         } >msg.log
65 }
66
67 verify_merge () {
68         test_cmp "$2" "$1" &&
69         git update-index --refresh &&
70         git diff --exit-code &&
71         if test -n "$3"
72         then
73                 git show -s --pretty=format:%s HEAD >msg.act &&
74                 test_cmp "$3" msg.act
75         fi
76 }
77
78 verify_head () {
79         echo "$1" >head.expected &&
80         git rev-parse HEAD >head.actual &&
81         test_cmp head.expected head.actual
82 }
83
84 verify_parents () {
85         printf '%s\n' "$@" >parents.expected &&
86         >parents.actual &&
87         i=1 &&
88         while test $i -le $#
89         do
90                 git rev-parse HEAD^$i >>parents.actual &&
91                 i=$(expr $i + 1) ||
92                 return 1
93         done &&
94         test_must_fail git rev-parse --verify "HEAD^$i" &&
95         test_cmp parents.expected parents.actual
96 }
97
98 verify_mergeheads () {
99         printf '%s\n' "$@" >mergehead.expected &&
100         while read sha1 rest
101         do
102                 git rev-parse $sha1
103         done <.git/MERGE_HEAD >mergehead.actual &&
104         test_cmp mergehead.expected mergehead.actual
105 }
106
107 verify_no_mergehead () {
108         ! test -e .git/MERGE_HEAD
109 }
110
111 test_expect_success 'setup' '
112         git add file &&
113         test_tick &&
114         git commit -m "commit 0" &&
115         git tag c0 &&
116         c0=$(git rev-parse HEAD) &&
117         cp file.1 file &&
118         git add file &&
119         test_tick &&
120         git commit -m "commit 1" &&
121         git tag c1 &&
122         c1=$(git rev-parse HEAD) &&
123         git reset --hard "$c0" &&
124         cp file.5 file &&
125         git add file &&
126         test_tick &&
127         git commit -m "commit 2" &&
128         git tag c2 &&
129         c2=$(git rev-parse HEAD) &&
130         git reset --hard "$c0" &&
131         cp file.9 file &&
132         git add file &&
133         test_tick &&
134         git commit -m "commit 3" &&
135         git tag c3 &&
136         c3=$(git rev-parse HEAD)
137         git reset --hard "$c0" &&
138         create_merge_msgs
139 '
140
141 test_debug 'git log --graph --decorate --oneline --all'
142
143 test_expect_success 'test option parsing' '
144         test_must_fail git merge -$ c1 &&
145         test_must_fail git merge --no-such c1 &&
146         test_must_fail git merge -s foobar c1 &&
147         test_must_fail git merge -s=foobar c1 &&
148         test_must_fail git merge -m &&
149         test_must_fail git merge
150 '
151
152 test_expect_success 'merge -h with invalid index' '
153         mkdir broken &&
154         (
155                 cd broken &&
156                 git init &&
157                 >.git/index &&
158                 test_expect_code 129 git merge -h 2>usage
159         ) &&
160         grep "[Uu]sage: git merge" broken/usage
161 '
162
163 test_expect_success 'reject non-strategy with a git-merge-foo name' '
164         test_must_fail git merge -s index c1
165 '
166
167 test_expect_success 'merge c0 with c1' '
168         echo "OBJID HEAD@{0}: merge c1: Fast-forward" >reflog.expected &&
169
170         git reset --hard c0 &&
171         git merge c1 &&
172         verify_merge file result.1 &&
173         verify_head "$c1" &&
174
175         git reflog -1 >reflog.actual &&
176         sed "s/$_x05[0-9a-f]*/OBJID/g" reflog.actual >reflog.fuzzy &&
177         test_cmp reflog.expected reflog.fuzzy
178 '
179
180 test_debug 'git log --graph --decorate --oneline --all'
181
182 test_expect_success 'merge c0 with c1 with --ff-only' '
183         git reset --hard c0 &&
184         git merge --ff-only c1 &&
185         git merge --ff-only HEAD c0 c1 &&
186         verify_merge file result.1 &&
187         verify_head "$c1"
188 '
189
190 test_debug 'git log --graph --decorate --oneline --all'
191
192 test_expect_success 'merge from unborn branch' '
193         git checkout -f master &&
194         test_might_fail git branch -D kid &&
195
196         echo "OBJID HEAD@{0}: initial pull" >reflog.expected &&
197
198         git checkout --orphan kid &&
199         test_when_finished "git checkout -f master" &&
200         git rm -fr . &&
201         test_tick &&
202         git merge --ff-only c1 &&
203         verify_merge file result.1 &&
204         verify_head "$c1" &&
205
206         git reflog -1 >reflog.actual &&
207         sed "s/$_x05[0-9a-f][0-9a-f]/OBJID/g" reflog.actual >reflog.fuzzy &&
208         test_cmp reflog.expected reflog.fuzzy
209 '
210
211 test_debug 'git log --graph --decorate --oneline --all'
212
213 test_expect_success 'merge c1 with c2' '
214         git reset --hard c1 &&
215         test_tick &&
216         git merge c2 &&
217         verify_merge file result.1-5 msg.1-5 &&
218         verify_parents $c1 $c2
219 '
220
221 test_debug 'git log --graph --decorate --oneline --all'
222
223 test_expect_success 'merge c1 with c2 and c3' '
224         git reset --hard c1 &&
225         test_tick &&
226         git merge c2 c3 &&
227         verify_merge file result.1-5-9 msg.1-5-9 &&
228         verify_parents $c1 $c2 $c3
229 '
230
231 test_debug 'git log --graph --decorate --oneline --all'
232
233 test_expect_success 'merges with --ff-only' '
234         git reset --hard c1 &&
235         test_tick &&
236         test_must_fail git merge --ff-only c2 &&
237         test_must_fail git merge --ff-only c3 &&
238         test_must_fail git merge --ff-only c2 c3 &&
239         git reset --hard c0 &&
240         git merge c3 &&
241         verify_head $c3
242 '
243
244 test_expect_success 'merges with merge.ff=only' '
245         git reset --hard c1 &&
246         test_tick &&
247         test_when_finished "git config --unset merge.ff" &&
248         git config merge.ff only &&
249         test_must_fail git merge c2 &&
250         test_must_fail git merge c3 &&
251         test_must_fail git merge c2 c3 &&
252         git reset --hard c0 &&
253         git merge c3 &&
254         verify_head $c3
255 '
256
257 test_expect_success 'merge c0 with c1 (no-commit)' '
258         git reset --hard c0 &&
259         git merge --no-commit c1 &&
260         verify_merge file result.1 &&
261         verify_head $c1
262 '
263
264 test_debug 'git log --graph --decorate --oneline --all'
265
266 test_expect_success 'merge c1 with c2 (no-commit)' '
267         git reset --hard c1 &&
268         git merge --no-commit c2 &&
269         verify_merge file result.1-5 &&
270         verify_head $c1 &&
271         verify_mergeheads $c2
272 '
273
274 test_debug 'git log --graph --decorate --oneline --all'
275
276 test_expect_success 'merge c1 with c2 and c3 (no-commit)' '
277         git reset --hard c1 &&
278         git merge --no-commit c2 c3 &&
279         verify_merge file result.1-5-9 &&
280         verify_head $c1 &&
281         verify_mergeheads $c2 $c3
282 '
283
284 test_debug 'git log --graph --decorate --oneline --all'
285
286 test_expect_success 'merge c0 with c1 (squash)' '
287         git reset --hard c0 &&
288         git merge --squash c1 &&
289         verify_merge file result.1 &&
290         verify_head $c0 &&
291         verify_no_mergehead &&
292         test_cmp squash.1 .git/SQUASH_MSG
293 '
294
295 test_debug 'git log --graph --decorate --oneline --all'
296
297 test_expect_success 'merge c0 with c1 (squash, ff-only)' '
298         git reset --hard c0 &&
299         git merge --squash --ff-only c1 &&
300         verify_merge file result.1 &&
301         verify_head $c0 &&
302         verify_no_mergehead &&
303         test_cmp squash.1 .git/SQUASH_MSG
304 '
305
306 test_debug 'git log --graph --decorate --oneline --all'
307
308 test_expect_success 'merge c1 with c2 (squash)' '
309         git reset --hard c1 &&
310         git merge --squash c2 &&
311         verify_merge file result.1-5 &&
312         verify_head $c1 &&
313         verify_no_mergehead &&
314         test_cmp squash.1-5 .git/SQUASH_MSG
315 '
316
317 test_debug 'git log --graph --decorate --oneline --all'
318
319 test_expect_success 'unsuccesful merge of c1 with c2 (squash, ff-only)' '
320         git reset --hard c1 &&
321         test_must_fail git merge --squash --ff-only c2
322 '
323
324 test_debug 'git log --graph --decorate --oneline --all'
325
326 test_expect_success 'merge c1 with c2 and c3 (squash)' '
327         git reset --hard c1 &&
328         git merge --squash c2 c3 &&
329         verify_merge file result.1-5-9 &&
330         verify_head $c1 &&
331         verify_no_mergehead &&
332         test_cmp squash.1-5-9 .git/SQUASH_MSG
333 '
334
335 test_debug 'git log --graph --decorate --oneline --all'
336
337 test_expect_success 'merge c1 with c2 (no-commit in config)' '
338         git reset --hard c1 &&
339         git config branch.master.mergeoptions "--no-commit" &&
340         git merge c2 &&
341         verify_merge file result.1-5 &&
342         verify_head $c1 &&
343         verify_mergeheads $c2
344 '
345
346 test_debug 'git log --graph --decorate --oneline --all'
347
348 test_expect_success 'merge c1 with c2 (log in config)' '
349         git config branch.master.mergeoptions "" &&
350         git reset --hard c1 &&
351         git merge --log c2 &&
352         git show -s --pretty=tformat:%s%n%b >expect &&
353
354         git config branch.master.mergeoptions --log &&
355         git reset --hard c1 &&
356         git merge c2 &&
357         git show -s --pretty=tformat:%s%n%b >actual &&
358
359         test_cmp expect actual
360 '
361
362 test_expect_success 'merge c1 with c2 (log in config gets overridden)' '
363         test_when_finished "git config --remove-section branch.master" &&
364         test_when_finished "git config --remove-section merge" &&
365         test_might_fail git config --remove-section branch.master &&
366         test_might_fail git config --remove-section merge &&
367
368         git reset --hard c1 &&
369         git merge c2 &&
370         git show -s --pretty=tformat:%s%n%b >expect &&
371
372         git config branch.master.mergeoptions "--no-log" &&
373         git config merge.log true &&
374         git reset --hard c1 &&
375         git merge c2 &&
376         git show -s --pretty=tformat:%s%n%b >actual &&
377
378         test_cmp expect actual
379 '
380
381 test_expect_success 'merge c1 with c2 (squash in config)' '
382         git reset --hard c1 &&
383         git config branch.master.mergeoptions "--squash" &&
384         git merge c2 &&
385         verify_merge file result.1-5 &&
386         verify_head $c1 &&
387         verify_no_mergehead &&
388         test_cmp squash.1-5 .git/SQUASH_MSG
389 '
390
391 test_debug 'git log --graph --decorate --oneline --all'
392
393 test_expect_success 'override config option -n with --summary' '
394         git reset --hard c1 &&
395         git config branch.master.mergeoptions "-n" &&
396         test_tick &&
397         git merge --summary c2 >diffstat.txt &&
398         verify_merge file result.1-5 msg.1-5 &&
399         verify_parents $c1 $c2 &&
400         if ! grep "^ file |  *2 +-$" diffstat.txt
401         then
402                 echo "[OOPS] diffstat was not generated with --summary"
403                 false
404         fi
405 '
406
407 test_expect_success 'override config option -n with --stat' '
408         git reset --hard c1 &&
409         git config branch.master.mergeoptions "-n" &&
410         test_tick &&
411         git merge --stat c2 >diffstat.txt &&
412         verify_merge file result.1-5 msg.1-5 &&
413         verify_parents $c1 $c2 &&
414         if ! grep "^ file |  *2 +-$" diffstat.txt
415         then
416                 echo "[OOPS] diffstat was not generated with --stat"
417                 false
418         fi
419 '
420
421 test_debug 'git log --graph --decorate --oneline --all'
422
423 test_expect_success 'override config option --stat' '
424         git reset --hard c1 &&
425         git config branch.master.mergeoptions "--stat" &&
426         test_tick &&
427         git merge -n c2 >diffstat.txt &&
428         verify_merge file result.1-5 msg.1-5 &&
429         verify_parents $c1 $c2 &&
430         if grep "^ file |  *2 +-$" diffstat.txt
431         then
432                 echo "[OOPS] diffstat was generated"
433                 false
434         fi
435 '
436
437 test_debug 'git log --graph --decorate --oneline --all'
438
439 test_expect_success 'merge c1 with c2 (override --no-commit)' '
440         git reset --hard c1 &&
441         git config branch.master.mergeoptions "--no-commit" &&
442         test_tick &&
443         git merge --commit c2 &&
444         verify_merge file result.1-5 msg.1-5 &&
445         verify_parents $c1 $c2
446 '
447
448 test_debug 'git log --graph --decorate --oneline --all'
449
450 test_expect_success 'merge c1 with c2 (override --squash)' '
451         git reset --hard c1 &&
452         git config branch.master.mergeoptions "--squash" &&
453         test_tick &&
454         git merge --no-squash c2 &&
455         verify_merge file result.1-5 msg.1-5 &&
456         verify_parents $c1 $c2
457 '
458
459 test_debug 'git log --graph --decorate --oneline --all'
460
461 test_expect_success 'merge c0 with c1 (no-ff)' '
462         git reset --hard c0 &&
463         git config branch.master.mergeoptions "" &&
464         test_tick &&
465         git merge --no-ff c1 &&
466         verify_merge file result.1 &&
467         verify_parents $c0 $c1
468 '
469
470 test_debug 'git log --graph --decorate --oneline --all'
471
472 test_expect_success 'merge c0 with c1 (merge.ff=false)' '
473         git reset --hard c0 &&
474         git config merge.ff false &&
475         test_tick &&
476         git merge c1 &&
477         git config --remove-section merge &&
478         verify_merge file result.1 &&
479         verify_parents $c0 $c1
480 '
481 test_debug 'git log --graph --decorate --oneline --all'
482
483 test_expect_success 'combine branch.master.mergeoptions with merge.ff' '
484         git reset --hard c0 &&
485         git config branch.master.mergeoptions --ff &&
486         git config merge.ff false &&
487         test_tick &&
488         git merge c1 &&
489         git config --remove-section "branch.master" &&
490         git config --remove-section "merge" &&
491         verify_merge file result.1 &&
492         verify_parents "$c0"
493 '
494
495 test_expect_success 'tolerate unknown values for merge.ff' '
496         git reset --hard c0 &&
497         git config merge.ff something-new &&
498         test_tick &&
499         git merge c1 2>message &&
500         git config --remove-section "merge" &&
501         verify_head "$c1" &&
502         test_cmp empty message
503 '
504
505 test_expect_success 'combining --squash and --no-ff is refused' '
506         git reset --hard c0 &&
507         test_must_fail git merge --squash --no-ff c1 &&
508         test_must_fail git merge --no-ff --squash c1
509 '
510
511 test_expect_success 'combining --ff-only and --no-ff is refused' '
512         test_must_fail git merge --ff-only --no-ff c1 &&
513         test_must_fail git merge --no-ff --ff-only c1
514 '
515
516 test_expect_success 'merge c0 with c1 (ff overrides no-ff)' '
517         git reset --hard c0 &&
518         git config branch.master.mergeoptions "--no-ff" &&
519         git merge --ff c1 &&
520         verify_merge file result.1 &&
521         verify_head $c1
522 '
523
524 test_expect_success 'merge log message' '
525         git reset --hard c0 &&
526         git merge --no-log c2 &&
527         git show -s --pretty=format:%b HEAD >msg.act &&
528         test_cmp msg.nolog msg.act &&
529
530         git merge --log c3 &&
531         git show -s --pretty=format:%b HEAD >msg.act &&
532         test_cmp msg.log msg.act &&
533
534         git reset --hard HEAD^ &&
535         git config merge.log yes &&
536         git merge c3 &&
537         git show -s --pretty=format:%b HEAD >msg.act &&
538         test_cmp msg.log msg.act
539 '
540
541 test_debug 'git log --graph --decorate --oneline --all'
542
543 test_expect_success 'merge c1 with c0, c2, c0, and c1' '
544        git reset --hard c1 &&
545        git config branch.master.mergeoptions "" &&
546        test_tick &&
547        git merge c0 c2 c0 c1 &&
548        verify_merge file result.1-5 &&
549        verify_parents $c1 $c2
550 '
551
552 test_debug 'git log --graph --decorate --oneline --all'
553
554 test_expect_success 'merge c1 with c0, c2, c0, and c1' '
555        git reset --hard c1 &&
556        git config branch.master.mergeoptions "" &&
557        test_tick &&
558        git merge c0 c2 c0 c1 &&
559        verify_merge file result.1-5 &&
560        verify_parents $c1 $c2
561 '
562
563 test_debug 'git log --graph --decorate --oneline --all'
564
565 test_expect_success 'merge c1 with c1 and c2' '
566        git reset --hard c1 &&
567        git config branch.master.mergeoptions "" &&
568        test_tick &&
569        git merge c1 c2 &&
570        verify_merge file result.1-5 &&
571        verify_parents $c1 $c2
572 '
573
574 test_debug 'git log --graph --decorate --oneline --all'
575
576 test_expect_success 'merge fast-forward in a dirty tree' '
577        git reset --hard c0 &&
578        mv file file1 &&
579        cat file1 >file &&
580        rm -f file1 &&
581        git merge c2
582 '
583
584 test_debug 'git log --graph --decorate --oneline --all'
585
586 test_expect_success 'in-index merge' '
587         git reset --hard c0 &&
588         git merge --no-ff -s resolve c1 >out &&
589         test_i18ngrep "Wonderful." out &&
590         verify_parents $c0 $c1
591 '
592
593 test_debug 'git log --graph --decorate --oneline --all'
594
595 test_expect_success 'refresh the index before merging' '
596         git reset --hard c1 &&
597         cp file file.n && mv -f file.n file &&
598         git merge c3
599 '
600
601 cat >expected.branch <<\EOF
602 Merge branch 'c5-branch' (early part)
603 EOF
604 cat >expected.tag <<\EOF
605 Merge commit 'c5~1'
606 EOF
607
608 test_expect_success 'merge early part of c2' '
609         git reset --hard c3 &&
610         echo c4 >c4.c &&
611         git add c4.c &&
612         git commit -m c4 &&
613         git tag c4 &&
614         echo c5 >c5.c &&
615         git add c5.c &&
616         git commit -m c5 &&
617         git tag c5 &&
618         git reset --hard c3 &&
619         echo c6 >c6.c &&
620         git add c6.c &&
621         git commit -m c6 &&
622         git tag c6 &&
623         git branch -f c5-branch c5 &&
624         git merge c5-branch~1 &&
625         git show -s --pretty=format:%s HEAD >actual.branch &&
626         git reset --keep HEAD^ &&
627         git merge c5~1 &&
628         git show -s --pretty=format:%s HEAD >actual.tag &&
629         test_cmp expected.branch actual.branch &&
630         test_cmp expected.tag actual.tag
631 '
632
633 test_debug 'git log --graph --decorate --oneline --all'
634
635 test_expect_success 'merge --no-ff --no-commit && commit' '
636         git reset --hard c0 &&
637         git merge --no-ff --no-commit c1 &&
638         EDITOR=: git commit &&
639         verify_parents $c0 $c1
640 '
641
642 test_debug 'git log --graph --decorate --oneline --all'
643
644 test_expect_success 'amending no-ff merge commit' '
645         EDITOR=: git commit --amend &&
646         verify_parents $c0 $c1
647 '
648
649 test_debug 'git log --graph --decorate --oneline --all'
650
651 cat >editor <<\EOF
652 #!/bin/sh
653 # Add a new message string that was not in the template
654 (
655         echo "Merge work done on the side branch c1"
656         echo
657         cat <"$1"
658 ) >"$1.tmp" && mv "$1.tmp" "$1"
659 # strip comments and blank lines from end of message
660 sed -e '/^#/d' < "$1" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' > expected
661 EOF
662 chmod 755 editor
663
664 test_expect_success 'merge --no-ff --edit' '
665         git reset --hard c0 &&
666         EDITOR=./editor git merge --no-ff --edit c1 &&
667         verify_parents $c0 $c1 &&
668         git cat-file commit HEAD >raw &&
669         grep "work done on the side branch" raw &&
670         sed "1,/^$/d" >actual raw &&
671         test_cmp actual expected
672 '
673
674 test_expect_success GPG 'merge --ff-only tag' '
675         git reset --hard c0 &&
676         git commit --allow-empty -m "A newer commit" &&
677         git tag -s -m "A newer commit" signed &&
678         git reset --hard c0 &&
679
680         git merge --ff-only signed &&
681         git rev-parse signed^0 >expect &&
682         git rev-parse HEAD >actual &&
683         test_cmp actual expect
684 '
685
686 test_expect_success GPG 'merge --no-edit tag should skip editor' '
687         git reset --hard c0 &&
688         git commit --allow-empty -m "A newer commit" &&
689         git tag -f -s -m "A newer commit" signed &&
690         git reset --hard c0 &&
691
692         EDITOR=false git merge --no-edit signed &&
693         git rev-parse signed^0 >expect &&
694         git rev-parse HEAD^2 >actual &&
695         test_cmp actual expect
696 '
697
698 test_done