1#!/bin/sh
2
3test_description='recursive merge corner cases involving criss-cross merges'
4
5. ./test-lib.sh
6
7#
8# L1 L2
9# o---o
10# / \ / \
11# o X ?
12# \ / \ /
13# o---o
14# R1 R2
15#
16
17test_expect_success 'setup basic criss-cross + rename with no modifications' '
18 test_create_repo basic-rename &&
19 (
20 cd basic-rename &&
21
22 ten="0 1 2 3 4 5 6 7 8 9" &&
23 for i in $ten
24 do
25 echo line $i in a sample file
26 done >one &&
27 for i in $ten
28 do
29 echo line $i in another sample file
30 done >two &&
31 git add one two &&
32 test_tick && git commit -m initial &&
33
34 git branch L1 &&
35 git checkout -b R1 &&
36 git mv one three &&
37 test_tick && git commit -m R1 &&
38
39 git checkout L1 &&
40 git mv two three &&
41 test_tick && git commit -m L1 &&
42
43 git checkout L1^0 &&
44 test_tick && git merge -s ours R1 &&
45 git tag L2 &&
46
47 git checkout R1^0 &&
48 test_tick && git merge -s ours L1 &&
49 git tag R2
50 )
51'
52
53test_expect_success 'merge simple rename+criss-cross with no modifications' '
54 (
55 cd basic-rename &&
56
57 git reset --hard &&
58 git checkout L2^0 &&
59
60 test_must_fail git merge -s recursive R2^0 &&
61
62 git ls-files -s >out &&
63 test_line_count = 2 out &&
64 git ls-files -u >out &&
65 test_line_count = 2 out &&
66 git ls-files -o >out &&
67 test_line_count = 1 out &&
68
69 git rev-parse >expect \
70 L2:three R2:three &&
71 git rev-parse >actual \
72 :2:three :3:three &&
73 test_cmp expect actual
74 )
75'
76
77#
78# Same as before, but modify L1 slightly:
79#
80# L1m L2
81# o---o
82# / \ / \
83# o X ?
84# \ / \ /
85# o---o
86# R1 R2
87#
88
89test_expect_success 'setup criss-cross + rename merges with basic modification' '
90 test_create_repo rename-modify &&
91 (
92 cd rename-modify &&
93
94 ten="0 1 2 3 4 5 6 7 8 9" &&
95 for i in $ten
96 do
97 echo line $i in a sample file
98 done >one &&
99 for i in $ten
100 do
101 echo line $i in another sample file
102 done >two &&
103 git add one two &&
104 test_tick && git commit -m initial &&
105
106 git branch L1 &&
107 git checkout -b R1 &&
108 git mv one three &&
109 echo more >>two &&
110 git add two &&
111 test_tick && git commit -m R1 &&
112
113 git checkout L1 &&
114 git mv two three &&
115 test_tick && git commit -m L1 &&
116
117 git checkout L1^0 &&
118 test_tick && git merge -s ours R1 &&
119 git tag L2 &&
120
121 git checkout R1^0 &&
122 test_tick && git merge -s ours L1 &&
123 git tag R2
124 )
125'
126
127test_expect_success 'merge criss-cross + rename merges with basic modification' '
128 (
129 cd rename-modify &&
130
131 git checkout L2^0 &&
132
133 test_must_fail git merge -s recursive R2^0 &&
134
135 git ls-files -s >out &&
136 test_line_count = 2 out &&
137 git ls-files -u >out &&
138 test_line_count = 2 out &&
139 git ls-files -o >out &&
140 test_line_count = 1 out &&
141
142 git rev-parse >expect \
143 L2:three R2:three &&
144 git rev-parse >actual \
145 :2:three :3:three &&
146 test_cmp expect actual
147 )
148'
149
150#
151# For the next test, we start with three commits in two lines of development
152# which setup a rename/add conflict:
153# Commit A: File 'a' exists
154# Commit B: Rename 'a' -> 'new_a'
155# Commit C: Modify 'a', create different 'new_a'
156# Later, two different people merge and resolve differently:
157# Commit D: Merge B & C, ignoring separately created 'new_a'
158# Commit E: Merge B & C making use of some piece of secondary 'new_a'
159# Finally, someone goes to merge D & E. Does git detect the conflict?
160#
161# B D
162# o---o
163# / \ / \
164# A o X ? F
165# \ / \ /
166# o---o
167# C E
168#
169
170test_expect_success 'setup differently handled merges of rename/add conflict' '
171 test_create_repo rename-add &&
172 (
173 cd rename-add &&
174
175 printf "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n" >a &&
176 git add a &&
177 test_tick && git commit -m A &&
178
179 git branch B &&
180 git checkout -b C &&
181 echo 10 >>a &&
182 test_write_lines 0 1 2 3 4 5 6 7 foobar >new_a &&
183 git add a new_a &&
184 test_tick && git commit -m C &&
185
186 git checkout B &&
187 git mv a new_a &&
188 test_tick && git commit -m B &&
189
190 git checkout B^0 &&
191 test_must_fail git merge C &&
192 git show :2:new_a >new_a &&
193 git add new_a &&
194 test_tick && git commit -m D &&
195 git tag D &&
196
197 git checkout C^0 &&
198 test_must_fail git merge B &&
199 test_write_lines 0 1 2 3 4 5 6 7 bad_merge >new_a &&
200 git add -u &&
201 test_tick && git commit -m E &&
202 git tag E
203 )
204'
205
206test_expect_success 'git detects differently handled merges conflict' '
207 (
208 cd rename-add &&
209
210 git checkout D^0 &&
211
212 test_must_fail git merge -s recursive E^0 &&
213
214 git ls-files -s >out &&
215 test_line_count = 3 out &&
216 git ls-files -u >out &&
217 test_line_count = 3 out &&
218 git ls-files -o >out &&
219 test_line_count = 1 out &&
220
221 git rev-parse >expect \
222 C:new_a D:new_a E:new_a &&
223 git rev-parse >actual \
224 :1:new_a :2:new_a :3:new_a &&
225 test_cmp expect actual &&
226
227 # Test that the two-way merge in new_a is as expected
228 git cat-file -p D:new_a >ours &&
229 git cat-file -p E:new_a >theirs &&
230 >empty &&
231 test_must_fail git merge-file \
232 -L "HEAD" \
233 -L "" \
234 -L "E^0" \
235 ours empty theirs &&
236 sed -e "s/^\([<=>]\)/\1\1\1/" ours >expect &&
237 git hash-object new_a >actual &&
238 git hash-object ours >expect &&
239 test_cmp expect actual
240 )
241'
242
243#
244# criss-cross + modify/delete:
245#
246# B D
247# o---o
248# / \ / \
249# A o X ? F
250# \ / \ /
251# o---o
252# C E
253#
254# Commit A: file with contents 'A\n'
255# Commit B: file with contents 'B\n'
256# Commit C: file not present
257# Commit D: file with contents 'B\n'
258# Commit E: file not present
259#
260# Merging commits D & E should result in modify/delete conflict.
261
262test_expect_success 'setup criss-cross + modify/delete resolved differently' '
263 test_create_repo modify-delete &&
264 (
265 cd modify-delete &&
266
267 echo A >file &&
268 git add file &&
269 test_tick &&
270 git commit -m A &&
271
272 git branch B &&
273 git checkout -b C &&
274 git rm file &&
275 test_tick &&
276 git commit -m C &&
277
278 git checkout B &&
279 echo B >file &&
280 git add file &&
281 test_tick &&
282 git commit -m B &&
283
284 git checkout B^0 &&
285 test_must_fail git merge C &&
286 echo B >file &&
287 git add file &&
288 test_tick &&
289 git commit -m D &&
290 git tag D &&
291
292 git checkout C^0 &&
293 test_must_fail git merge B &&
294 git rm file &&
295 test_tick &&
296 git commit -m E &&
297 git tag E
298 )
299'
300
301test_expect_success 'git detects conflict merging criss-cross+modify/delete' '
302 (
303 cd modify-delete &&
304
305 git checkout D^0 &&
306
307 test_must_fail git merge -s recursive E^0 &&
308
309 git ls-files -s >out &&
310 test_line_count = 2 out &&
311 git ls-files -u >out &&
312 test_line_count = 2 out &&
313
314 git rev-parse >expect \
315 master:file B:file &&
316 git rev-parse >actual \
317 :1:file :2:file &&
318 test_cmp expect actual
319 )
320'
321
322test_expect_success 'git detects conflict merging criss-cross+modify/delete, reverse direction' '
323 (
324 cd modify-delete &&
325
326 git reset --hard &&
327 git checkout E^0 &&
328
329 test_must_fail git merge -s recursive D^0 &&
330
331 git ls-files -s >out &&
332 test_line_count = 2 out &&
333 git ls-files -u >out &&
334 test_line_count = 2 out &&
335
336 git rev-parse >expect \
337 master:file B:file &&
338 git rev-parse >actual \
339 :1:file :3:file &&
340 test_cmp expect actual
341 )
342'
343
344# SORRY FOR THE SUPER LONG DESCRIPTION, BUT THIS NEXT ONE IS HAIRY
345#
346# criss-cross + d/f conflict via add/add:
347# Commit A: Neither file 'a' nor directory 'a/' exists.
348# Commit B: Introduce 'a'
349# Commit C: Introduce 'a/file'
350# Commit D1: Merge B & C, keeping 'a' and deleting 'a/'
351# Commit E1: Merge B & C, deleting 'a' but keeping 'a/file'
352#
353# B D1 or D2
354# o---o
355# / \ / \
356# A o X ? F
357# \ / \ /
358# o---o
359# C E1 or E2 or E3
360#
361# I'll describe D2, E2, & E3 (which are alternatives for D1 & E1) more below...
362#
363# Merging D1 & E1 requires we first create a virtual merge base X from
364# merging A & B in memory. There are several possibilities for the merge-base:
365# 1: Keep both 'a' and 'a/file' (assuming crazy filesystem allowing a tree
366# with a directory and file at same path): results in merge of D1 & E1
367# being clean with both files deleted. Bad (no conflict detected).
368# 2: Keep 'a' but not 'a/file': Merging D1 & E1 is clean and matches E1. Bad.
369# 3: Keep 'a/file' but not 'a': Merging D1 & E1 is clean and matches D1. Bad.
370# 4: Keep neither file: Merging D1 & E1 reports the D/F add/add conflict.
371#
372# So 4 sounds good for this case, but if we were to merge D1 & E3, where E3
373# is defined as:
374# Commit E3: Merge B & C, keeping modified a, and deleting a/
375# then we'd get an add/add conflict for 'a', which seems suboptimal. A little
376# creativity leads us to an alternate choice:
377# 5: Keep 'a' as 'a~$UNIQUE' and a/file; results:
378# Merge D1 & E1: rename/delete conflict for 'a'; a/file silently deleted
379# Merge D1 & E3 is clean, as expected.
380#
381# So choice 5 at least provides some kind of conflict for the original case,
382# and can merge cleanly as expected with D1 and E3. It also made things just
383# slightly funny for merging D1 and e$, where E4 is defined as:
384# Commit E4: Merge B & C, modifying 'a' and renaming to 'a2', and deleting 'a/'
385# in this case, we'll get a rename/rename(1to2) conflict because a~$UNIQUE
386# gets renamed to 'a' in D1 and to 'a2' in E4. But that's better than having
387# two files (both 'a' and 'a2') sitting around without the user being notified
388# that we could detect they were related and need to be merged. Also, choice
389# 5 makes the handling of 'a/file' seem suboptimal. What if we were to merge
390# D2 and E4, where D2 is:
391# Commit D2: Merge B & C, renaming 'a'->'a2', keeping 'a/file'
392# This would result in a clean merge with 'a2' having three-way merged
393# contents (good), and deleting 'a/' (bad) -- it doesn't detect the
394# conflict in how the different sides treated a/file differently.
395# Continuing down the creative route:
396# 6: Keep 'a' as 'a~$UNIQUE1' and keep 'a/' as 'a~$UNIQUE2/'; results:
397# Merge D1 & E1: rename/delete conflict for 'a' and each path under 'a/'.
398# Merge D1 & E3: clean, as expected.
399# Merge D1 & E4: rename/rename(1to2) conflict on 'a' vs 'a2'.
400# Merge D2 & E4: clean for 'a2', rename/delete for a/file
401#
402# Choice 6 could cause rename detection to take longer (providing more targets
403# that need to be searched). Also, the conflict message for each path under
404# 'a/' might be annoying unless we can detect it at the directory level, print
405# it once, and then suppress it for individual filepaths underneath.
406#
407#
408# As of time of writing, git uses choice 5. Directory rename detection and
409# rename detection performance improvements might make choice 6 a desirable
410# improvement. But we can at least document where we fall short for now...
411#
412#
413# Historically, this testcase also used:
414# Commit E2: Merge B & C, deleting 'a' but keeping slightly modified 'a/file'
415# The merge of D1 & E2 is very similar to D1 & E1 -- it has similar issues for
416# path 'a', but should always result in a modify/delete conflict for path
417# 'a/file'. These tests ran the two merges
418# D1 & E1
419# D1 & E2
420# in both directions, to check for directional issues with D/F conflict
421# handling. Later we added
422# D1 & E3
423# D1 & E4
424# D2 & E4
425# for good measure, though we only ran those one way because we had pretty
426# good confidence in merge-recursive's directional handling of D/F issues.
427#
428# Just to summarize all the intermediate merge commits:
429# Commit D1: Merge B & C, keeping a and deleting a/
430# Commit D2: Merge B & C, renaming a->a2, keeping a/file
431# Commit E1: Merge B & C, deleting a but keeping a/file
432# Commit E2: Merge B & C, deleting a but keeping slightly modified a/file
433# Commit E3: Merge B & C, keeping modified a, and deleting a/
434# Commit E4: Merge B & C, modifying 'a' and renaming to 'a2', and deleting 'a/'
435#
436
437test_expect_success 'setup differently handled merges of directory/file conflict' '
438 test_create_repo directory-file &&
439 (
440 cd directory-file &&
441
442 >ignore-me &&
443 git add ignore-me &&
444 test_tick &&
445 git commit -m A &&
446 git tag A &&
447
448 git branch B &&
449 git checkout -b C &&
450 mkdir a &&
451 test_write_lines a b c d e f g >a/file &&
452 git add a/file &&
453 test_tick &&
454 git commit -m C &&
455
456 git checkout B &&
457 test_write_lines 1 2 3 4 5 6 7 >a &&
458 git add a &&
459 test_tick &&
460 git commit -m B &&
461
462 git checkout B^0 &&
463 git merge -s ours -m D1 C^0 &&
464 git tag D1 &&
465
466 git checkout B^0 &&
467 test_must_fail git merge C^0 &&
468 git clean -fd &&
469 git rm -rf a/ &&
470 git rm a &&
471 git cat-file -p B:a >a2 &&
472 git add a2 &&
473 git commit -m D2 &&
474 git tag D2 &&
475
476 git checkout C^0 &&
477 git merge -s ours -m E1 B^0 &&
478 git tag E1 &&
479
480 git checkout C^0 &&
481 git merge -s ours -m E2 B^0 &&
482 test_write_lines a b c d e f g h >a/file &&
483 git add a/file &&
484 git commit --amend -C HEAD &&
485 git tag E2 &&
486
487 git checkout C^0 &&
488 test_must_fail git merge B^0 &&
489 git clean -fd &&
490 git rm -rf a/ &&
491 test_write_lines 1 2 3 4 5 6 7 8 >a &&
492 git add a &&
493 git commit -m E3 &&
494 git tag E3 &&
495
496 git checkout C^0 &&
497 test_must_fail git merge B^0 &&
498 git clean -fd &&
499 git rm -rf a/ &&
500 git rm a &&
501 test_write_lines 1 2 3 4 5 6 7 8 >a2 &&
502 git add a2 &&
503 git commit -m E4 &&
504 git tag E4
505 )
506'
507
508test_expect_success 'merge of D1 & E1 fails but has appropriate contents' '
509 test_when_finished "git -C directory-file reset --hard" &&
510 test_when_finished "git -C directory-file clean -fdqx" &&
511 (
512 cd directory-file &&
513
514 git checkout D1^0 &&
515
516 test_must_fail git merge -s recursive E1^0 &&
517
518 git ls-files -s >out &&
519 test_line_count = 2 out &&
520 git ls-files -u >out &&
521 test_line_count = 1 out &&
522 git ls-files -o >out &&
523 test_line_count = 1 out &&
524
525 git rev-parse >expect \
526 A:ignore-me B:a &&
527 git rev-parse >actual \
528 :0:ignore-me :2:a &&
529 test_cmp expect actual
530 )
531'
532
533test_expect_success 'merge of E1 & D1 fails but has appropriate contents' '
534 test_when_finished "git -C directory-file reset --hard" &&
535 test_when_finished "git -C directory-file clean -fdqx" &&
536 (
537 cd directory-file &&
538
539 git checkout E1^0 &&
540
541 test_must_fail git merge -s recursive D1^0 &&
542
543 git ls-files -s >out &&
544 test_line_count = 2 out &&
545 git ls-files -u >out &&
546 test_line_count = 1 out &&
547 git ls-files -o >out &&
548 test_line_count = 1 out &&
549
550 git rev-parse >expect \
551 A:ignore-me B:a &&
552 git rev-parse >actual \
553 :0:ignore-me :3:a &&
554 test_cmp expect actual
555 )
556'
557
558test_expect_success 'merge of D1 & E2 fails but has appropriate contents' '
559 test_when_finished "git -C directory-file reset --hard" &&
560 test_when_finished "git -C directory-file clean -fdqx" &&
561 (
562 cd directory-file &&
563
564 git checkout D1^0 &&
565
566 test_must_fail git merge -s recursive E2^0 &&
567
568 git ls-files -s >out &&
569 test_line_count = 4 out &&
570 git ls-files -u >out &&
571 test_line_count = 3 out &&
572 git ls-files -o >out &&
573 test_line_count = 2 out &&
574
575 git rev-parse >expect \
576 B:a E2:a/file C:a/file A:ignore-me &&
577 git rev-parse >actual \
578 :2:a :3:a/file :1:a/file :0:ignore-me &&
579 test_cmp expect actual &&
580
581 test_path_is_file a~HEAD
582 )
583'
584
585test_expect_success 'merge of E2 & D1 fails but has appropriate contents' '
586 test_when_finished "git -C directory-file reset --hard" &&
587 test_when_finished "git -C directory-file clean -fdqx" &&
588 (
589 cd directory-file &&
590
591 git checkout E2^0 &&
592
593 test_must_fail git merge -s recursive D1^0 &&
594
595 git ls-files -s >out &&
596 test_line_count = 4 out &&
597 git ls-files -u >out &&
598 test_line_count = 3 out &&
599 git ls-files -o >out &&
600 test_line_count = 2 out &&
601
602 git rev-parse >expect \
603 B:a E2:a/file C:a/file A:ignore-me &&
604 git rev-parse >actual \
605 :3:a :2:a/file :1:a/file :0:ignore-me &&
606 test_cmp expect actual &&
607
608 test_path_is_file a~D1^0
609 )
610'
611
612test_expect_success 'merge of D1 & E3 succeeds' '
613 test_when_finished "git -C directory-file reset --hard" &&
614 test_when_finished "git -C directory-file clean -fdqx" &&
615 (
616 cd directory-file &&
617
618 git checkout D1^0 &&
619
620 git merge -s recursive E3^0 &&
621
622 git ls-files -s >out &&
623 test_line_count = 2 out &&
624 git ls-files -u >out &&
625 test_line_count = 0 out &&
626 git ls-files -o >out &&
627 test_line_count = 1 out &&
628
629 git rev-parse >expect \
630 A:ignore-me E3:a &&
631 git rev-parse >actual \
632 :0:ignore-me :0:a &&
633 test_cmp expect actual
634 )
635'
636
637test_expect_success 'merge of D1 & E4 notifies user a and a2 are related' '
638 test_when_finished "git -C directory-file reset --hard" &&
639 test_when_finished "git -C directory-file clean -fdqx" &&
640 (
641 cd directory-file &&
642
643 git checkout D1^0 &&
644
645 test_must_fail git merge -s recursive E4^0 &&
646
647 git ls-files -s >out &&
648 test_line_count = 4 out &&
649 git ls-files -u >out &&
650 test_line_count = 3 out &&
651 git ls-files -o >out &&
652 test_line_count = 1 out &&
653
654 git rev-parse >expect \
655 A:ignore-me B:a D1:a E4:a2 &&
656 git rev-parse >actual \
657 :0:ignore-me :1:a~Temporary\ merge\ branch\ 2 :2:a :3:a2 &&
658 test_cmp expect actual
659 )
660'
661
662test_expect_failure 'merge of D2 & E4 merges a2s & reports conflict for a/file' '
663 test_when_finished "git -C directory-file reset --hard" &&
664 test_when_finished "git -C directory-file clean -fdqx" &&
665 (
666 cd directory-file &&
667
668 git checkout D2^0 &&
669
670 test_must_fail git merge -s recursive E4^0 &&
671
672 git ls-files -s >out &&
673 test_line_count = 3 out &&
674 git ls-files -u >out &&
675 test_line_count = 1 out &&
676 git ls-files -o >out &&
677 test_line_count = 1 out &&
678
679 git rev-parse >expect \
680 A:ignore-me E4:a2 D2:a/file &&
681 git rev-parse >actual \
682 :0:ignore-me :0:a2 :2:a/file &&
683 test_cmp expect actual
684 )
685'
686
687#
688# criss-cross with rename/rename(1to2)/modify followed by
689# rename/rename(2to1)/modify:
690#
691# B D
692# o---o
693# / \ / \
694# A o X ? F
695# \ / \ /
696# o---o
697# C E
698#
699# Commit A: new file: a
700# Commit B: rename a->b, modifying by adding a line
701# Commit C: rename a->c
702# Commit D: merge B&C, resolving conflict by keeping contents in newname
703# Commit E: merge B&C, resolving conflict similar to D but adding another line
704#
705# There is a conflict merging B & C, but one of filename not of file
706# content. Whoever created D and E chose specific resolutions for that
707# conflict resolution. Now, since: (1) there is no content conflict
708# merging B & C, (2) D does not modify that merged content further, and (3)
709# both D & E resolve the name conflict in the same way, the modification to
710# newname in E should not cause any conflicts when it is merged with D.
711# (Note that this can be accomplished by having the virtual merge base have
712# the merged contents of b and c stored in a file named a, which seems like
713# the most logical choice anyway.)
714#
715# Comment from Junio: I do not necessarily agree with the choice "a", but
716# it feels sound to say "B and C do not agree what the final pathname
717# should be, but we know this content was derived from the common A:a so we
718# use one path whose name is arbitrary in the virtual merge base X between
719# D and E" and then further let the rename detection to notice that that
720# arbitrary path gets renamed between X-D to "newname" and X-E also to
721# "newname" to resolve it as both sides renaming it to the same new
722# name. It is akin to what we do at the content level, i.e. "B and C do not
723# agree what the final contents should be, so we leave the conflict marker
724# but that may cancel out at the final merge stage".
725
726test_expect_success 'setup rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' '
727 test_create_repo rename-squared-squared &&
728 (
729 cd rename-squared-squared &&
730
731 printf "1\n2\n3\n4\n5\n6\n" >a &&
732 git add a &&
733 git commit -m A &&
734 git tag A &&
735
736 git checkout -b B A &&
737 git mv a b &&
738 echo 7 >>b &&
739 git add -u &&
740 git commit -m B &&
741
742 git checkout -b C A &&
743 git mv a c &&
744 git commit -m C &&
745
746 git checkout -q B^0 &&
747 git merge --no-commit -s ours C^0 &&
748 git mv b newname &&
749 git commit -m "Merge commit C^0 into HEAD" &&
750 git tag D &&
751
752 git checkout -q C^0 &&
753 git merge --no-commit -s ours B^0 &&
754 git mv c newname &&
755 printf "7\n8\n" >>newname &&
756 git add -u &&
757 git commit -m "Merge commit B^0 into HEAD" &&
758 git tag E
759 )
760'
761
762test_expect_success 'handle rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' '
763 (
764 cd rename-squared-squared &&
765
766 git checkout D^0 &&
767
768 git merge -s recursive E^0 &&
769
770 git ls-files -s >out &&
771 test_line_count = 1 out &&
772 git ls-files -u >out &&
773 test_line_count = 0 out &&
774 git ls-files -o >out &&
775 test_line_count = 1 out &&
776
777 test $(git rev-parse HEAD:newname) = $(git rev-parse E:newname)
778 )
779'
780
781#
782# criss-cross with rename/rename(1to2)/add-source + resolvable modify/modify:
783#
784# B D
785# o---o
786# / \ / \
787# A o X ? F
788# \ / \ /
789# o---o
790# C E
791#
792# Commit A: new file: a
793# Commit B: rename a->b
794# Commit C: rename a->c, add different a
795# Commit D: merge B&C, keeping b&c and (new) a modified at beginning
796# Commit E: merge B&C, keeping b&c and (new) a modified at end
797#
798# Merging commits D & E should result in no conflict; doing so correctly
799# requires getting the virtual merge base (from merging B&C) right, handling
800# renaming carefully (both in the virtual merge base and later), and getting
801# content merge handled.
802
803test_expect_success 'setup criss-cross + rename/rename/add-source + modify/modify' '
804 test_create_repo rename-rename-add-source &&
805 (
806 cd rename-rename-add-source &&
807
808 printf "lots\nof\nwords\nand\ncontent\n" >a &&
809 git add a &&
810 git commit -m A &&
811 git tag A &&
812
813 git checkout -b B A &&
814 git mv a b &&
815 git commit -m B &&
816
817 git checkout -b C A &&
818 git mv a c &&
819 printf "2\n3\n4\n5\n6\n7\n" >a &&
820 git add a &&
821 git commit -m C &&
822
823 git checkout B^0 &&
824 git merge --no-commit -s ours C^0 &&
825 git checkout C -- a c &&
826 mv a old_a &&
827 echo 1 >a &&
828 cat old_a >>a &&
829 rm old_a &&
830 git add -u &&
831 git commit -m "Merge commit C^0 into HEAD" &&
832 git tag D &&
833
834 git checkout C^0 &&
835 git merge --no-commit -s ours B^0 &&
836 git checkout B -- b &&
837 echo 8 >>a &&
838 git add -u &&
839 git commit -m "Merge commit B^0 into HEAD" &&
840 git tag E
841 )
842'
843
844test_expect_failure 'detect rename/rename/add-source for virtual merge-base' '
845 (
846 cd rename-rename-add-source &&
847
848 git checkout D^0 &&
849
850 git merge -s recursive E^0 &&
851
852 git ls-files -s >out &&
853 test_line_count = 3 out &&
854 git ls-files -u >out &&
855 test_line_count = 0 out &&
856 git ls-files -o >out &&
857 test_line_count = 1 out &&
858
859 printf "1\n2\n3\n4\n5\n6\n7\n8\n" >correct &&
860 git rev-parse >expect \
861 A:a A:a \
862 correct &&
863 git rev-parse >actual \
864 :0:b :0:c &&
865 git hash-object >>actual \
866 a &&
867 test_cmp expect actual
868 )
869'
870
871#
872# criss-cross with rename/rename(1to2)/add-dest + simple modify:
873#
874# B D
875# o---o
876# / \ / \
877# A o X ? F
878# \ / \ /
879# o---o
880# C E
881#
882# Commit A: new file: a
883# Commit B: rename a->b, add c
884# Commit C: rename a->c
885# Commit D: merge B&C, keeping A:a and B:c
886# Commit E: merge B&C, keeping A:a and slightly modified c from B
887#
888# Merging commits D & E should result in no conflict. The virtual merge
889# base of B & C needs to not delete B:c for that to work, though...
890
891test_expect_success 'setup criss-cross+rename/rename/add-dest + simple modify' '
892 test_create_repo rename-rename-add-dest &&
893 (
894 cd rename-rename-add-dest &&
895
896 >a &&
897 git add a &&
898 git commit -m A &&
899 git tag A &&
900
901 git checkout -b B A &&
902 git mv a b &&
903 printf "1\n2\n3\n4\n5\n6\n7\n" >c &&
904 git add c &&
905 git commit -m B &&
906
907 git checkout -b C A &&
908 git mv a c &&
909 git commit -m C &&
910
911 git checkout B^0 &&
912 git merge --no-commit -s ours C^0 &&
913 git mv b a &&
914 git commit -m "D is like B but renames b back to a" &&
915 git tag D &&
916
917 git checkout B^0 &&
918 git merge --no-commit -s ours C^0 &&
919 git mv b a &&
920 echo 8 >>c &&
921 git add c &&
922 git commit -m "E like D but has mod in c" &&
923 git tag E
924 )
925'
926
927test_expect_success 'virtual merge base handles rename/rename(1to2)/add-dest' '
928 (
929 cd rename-rename-add-dest &&
930
931 git checkout D^0 &&
932
933 git merge -s recursive E^0 &&
934
935 git ls-files -s >out &&
936 test_line_count = 2 out &&
937 git ls-files -u >out &&
938 test_line_count = 0 out &&
939 git ls-files -o >out &&
940 test_line_count = 1 out &&
941
942 git rev-parse >expect \
943 A:a E:c &&
944 git rev-parse >actual \
945 :0:a :0:c &&
946 test_cmp expect actual
947 )
948'
949
950#
951# criss-cross with modify/modify on a symlink:
952#
953# B D
954# o---o
955# / \ / \
956# A o X ? F
957# \ / \ /
958# o---o
959# C E
960#
961# Commit A: simple simlink fickle->lagoon
962# Commit B: redirect fickle->disneyland
963# Commit C: redirect fickle->home
964# Commit D: merge B&C, resolving in favor of B
965# Commit E: merge B&C, resolving in favor of C
966#
967# This is an obvious modify/modify conflict for the symlink 'fickle'. Can
968# git detect it?
969
970test_expect_success 'setup symlink modify/modify' '
971 test_create_repo symlink-modify-modify &&
972 (
973 cd symlink-modify-modify &&
974
975 test_ln_s_add lagoon fickle &&
976 git commit -m A &&
977 git tag A &&
978
979 git checkout -b B A &&
980 git rm fickle &&
981 test_ln_s_add disneyland fickle &&
982 git commit -m B &&
983
984 git checkout -b C A &&
985 git rm fickle &&
986 test_ln_s_add home fickle &&
987 git add fickle &&
988 git commit -m C &&
989
990 git checkout -q B^0 &&
991 git merge -s ours -m D C^0 &&
992 git tag D &&
993
994 git checkout -q C^0 &&
995 git merge -s ours -m E B^0 &&
996 git tag E
997 )
998'
999
1000test_expect_failure 'check symlink modify/modify' '
1001 (
1002 cd symlink-modify-modify &&
1003
1004 git checkout D^0 &&
1005
1006 test_must_fail git merge -s recursive E^0 &&
1007
1008 git ls-files -s >out &&
1009 test_line_count = 3 out &&
1010 git ls-files -u >out &&
1011 test_line_count = 3 out &&
1012 git ls-files -o >out &&
1013 test_line_count = 1 out
1014 )
1015'
1016
1017#
1018# criss-cross with add/add of a symlink:
1019#
1020# B D
1021# o---o
1022# / \ / \
1023# A o X ? F
1024# \ / \ /
1025# o---o
1026# C E
1027#
1028# Commit A: No symlink or path exists yet
1029# Commit B: set up symlink: fickle->disneyland
1030# Commit C: set up symlink: fickle->home
1031# Commit D: merge B&C, resolving in favor of B
1032# Commit E: merge B&C, resolving in favor of C
1033#
1034# This is an obvious add/add conflict for the symlink 'fickle'. Can
1035# git detect it?
1036
1037test_expect_success 'setup symlink add/add' '
1038 test_create_repo symlink-add-add &&
1039 (
1040 cd symlink-add-add &&
1041
1042 touch ignoreme &&
1043 git add ignoreme &&
1044 git commit -m A &&
1045 git tag A &&
1046
1047 git checkout -b B A &&
1048 test_ln_s_add disneyland fickle &&
1049 git commit -m B &&
1050
1051 git checkout -b C A &&
1052 test_ln_s_add home fickle &&
1053 git add fickle &&
1054 git commit -m C &&
1055
1056 git checkout -q B^0 &&
1057 git merge -s ours -m D C^0 &&
1058 git tag D &&
1059
1060 git checkout -q C^0 &&
1061 git merge -s ours -m E B^0 &&
1062 git tag E
1063 )
1064'
1065
1066test_expect_failure 'check symlink add/add' '
1067 (
1068 cd symlink-add-add &&
1069
1070 git checkout D^0 &&
1071
1072 test_must_fail git merge -s recursive E^0 &&
1073
1074 git ls-files -s >out &&
1075 test_line_count = 2 out &&
1076 git ls-files -u >out &&
1077 test_line_count = 2 out &&
1078 git ls-files -o >out &&
1079 test_line_count = 1 out
1080 )
1081'
1082
1083#
1084# criss-cross with modify/modify on a submodule:
1085#
1086# B D
1087# o---o
1088# / \ / \
1089# A o X ? F
1090# \ / \ /
1091# o---o
1092# C E
1093#
1094# Commit A: simple submodule repo
1095# Commit B: update repo
1096# Commit C: update repo differently
1097# Commit D: merge B&C, resolving in favor of B
1098# Commit E: merge B&C, resolving in favor of C
1099#
1100# This is an obvious modify/modify conflict for the submodule 'repo'. Can
1101# git detect it?
1102
1103test_expect_success 'setup submodule modify/modify' '
1104 test_create_repo submodule-modify-modify &&
1105 (
1106 cd submodule-modify-modify &&
1107
1108 test_create_repo submod &&
1109 (
1110 cd submod &&
1111 touch file-A &&
1112 git add file-A &&
1113 git commit -m A &&
1114 git tag A &&
1115
1116 git checkout -b B A &&
1117 touch file-B &&
1118 git add file-B &&
1119 git commit -m B &&
1120 git tag B &&
1121
1122 git checkout -b C A &&
1123 touch file-C &&
1124 git add file-C &&
1125 git commit -m C &&
1126 git tag C
1127 ) &&
1128
1129 git -C submod reset --hard A &&
1130 git add submod &&
1131 git commit -m A &&
1132 git tag A &&
1133
1134 git checkout -b B A &&
1135 git -C submod reset --hard B &&
1136 git add submod &&
1137 git commit -m B &&
1138
1139 git checkout -b C A &&
1140 git -C submod reset --hard C &&
1141 git add submod &&
1142 git commit -m C &&
1143
1144 git checkout -q B^0 &&
1145 git merge -s ours -m D C^0 &&
1146 git tag D &&
1147
1148 git checkout -q C^0 &&
1149 git merge -s ours -m E B^0 &&
1150 git tag E
1151 )
1152'
1153
1154test_expect_failure 'check submodule modify/modify' '
1155 (
1156 cd submodule-modify-modify &&
1157
1158 git checkout D^0 &&
1159
1160 test_must_fail git merge -s recursive E^0 &&
1161
1162 git ls-files -s >out &&
1163 test_line_count = 3 out &&
1164 git ls-files -u >out &&
1165 test_line_count = 3 out &&
1166 git ls-files -o >out &&
1167 test_line_count = 1 out
1168 )
1169'
1170
1171#
1172# criss-cross with add/add on a submodule:
1173#
1174# B D
1175# o---o
1176# / \ / \
1177# A o X ? F
1178# \ / \ /
1179# o---o
1180# C E
1181#
1182# Commit A: nothing of note
1183# Commit B: introduce submodule repo
1184# Commit C: introduce submodule repo at different commit
1185# Commit D: merge B&C, resolving in favor of B
1186# Commit E: merge B&C, resolving in favor of C
1187#
1188# This is an obvious add/add conflict for the submodule 'repo'. Can
1189# git detect it?
1190
1191test_expect_success 'setup submodule add/add' '
1192 test_create_repo submodule-add-add &&
1193 (
1194 cd submodule-add-add &&
1195
1196 test_create_repo submod &&
1197 (
1198 cd submod &&
1199 touch file-A &&
1200 git add file-A &&
1201 git commit -m A &&
1202 git tag A &&
1203
1204 git checkout -b B A &&
1205 touch file-B &&
1206 git add file-B &&
1207 git commit -m B &&
1208 git tag B &&
1209
1210 git checkout -b C A &&
1211 touch file-C &&
1212 git add file-C &&
1213 git commit -m C &&
1214 git tag C
1215 ) &&
1216
1217 touch irrelevant-file &&
1218 git add irrelevant-file &&
1219 git commit -m A &&
1220 git tag A &&
1221
1222 git checkout -b B A &&
1223 git -C submod reset --hard B &&
1224 git add submod &&
1225 git commit -m B &&
1226
1227 git checkout -b C A &&
1228 git -C submod reset --hard C &&
1229 git add submod &&
1230 git commit -m C &&
1231
1232 git checkout -q B^0 &&
1233 git merge -s ours -m D C^0 &&
1234 git tag D &&
1235
1236 git checkout -q C^0 &&
1237 git merge -s ours -m E B^0 &&
1238 git tag E
1239 )
1240'
1241
1242test_expect_failure 'check submodule add/add' '
1243 (
1244 cd submodule-add-add &&
1245
1246 git checkout D^0 &&
1247
1248 test_must_fail git merge -s recursive E^0 &&
1249
1250 git ls-files -s >out &&
1251 test_line_count = 3 out &&
1252 git ls-files -u >out &&
1253 test_line_count = 2 out &&
1254 git ls-files -o >out &&
1255 test_line_count = 1 out
1256 )
1257'
1258
1259#
1260# criss-cross with conflicting entry types:
1261#
1262# B D
1263# o---o
1264# / \ / \
1265# A o X ? F
1266# \ / \ /
1267# o---o
1268# C E
1269#
1270# Commit A: nothing of note
1271# Commit B: introduce submodule 'path'
1272# Commit C: introduce symlink 'path'
1273# Commit D: merge B&C, resolving in favor of B
1274# Commit E: merge B&C, resolving in favor of C
1275#
1276# This is an obvious add/add conflict for 'path'. Can git detect it?
1277
1278test_expect_success 'setup conflicting entry types (submodule vs symlink)' '
1279 test_create_repo submodule-symlink-add-add &&
1280 (
1281 cd submodule-symlink-add-add &&
1282
1283 test_create_repo path &&
1284 (
1285 cd path &&
1286 touch file-B &&
1287 git add file-B &&
1288 git commit -m B &&
1289 git tag B
1290 ) &&
1291
1292 touch irrelevant-file &&
1293 git add irrelevant-file &&
1294 git commit -m A &&
1295 git tag A &&
1296
1297 git checkout -b B A &&
1298 git -C path reset --hard B &&
1299 git add path &&
1300 git commit -m B &&
1301
1302 git checkout -b C A &&
1303 rm -rf path/ &&
1304 test_ln_s_add irrelevant-file path &&
1305 git commit -m C &&
1306
1307 git checkout -q B^0 &&
1308 git merge -s ours -m D C^0 &&
1309 git tag D &&
1310
1311 git checkout -q C^0 &&
1312 git merge -s ours -m E B^0 &&
1313 git tag E
1314 )
1315'
1316
1317test_expect_failure 'check conflicting entry types (submodule vs symlink)' '
1318 (
1319 cd submodule-symlink-add-add &&
1320
1321 git checkout D^0 &&
1322
1323 test_must_fail git merge -s recursive E^0 &&
1324
1325 git ls-files -s >out &&
1326 test_line_count = 3 out &&
1327 git ls-files -u >out &&
1328 test_line_count = 2 out &&
1329 git ls-files -o >out &&
1330 test_line_count = 1 out
1331 )
1332'
1333
1334#
1335# criss-cross with regular files that have conflicting modes:
1336#
1337# B D
1338# o---o
1339# / \ / \
1340# A o X ? F
1341# \ / \ /
1342# o---o
1343# C E
1344#
1345# Commit A: nothing of note
1346# Commit B: introduce file source_me.bash, not executable
1347# Commit C: introduce file source_me.bash, executable
1348# Commit D: merge B&C, resolving in favor of B
1349# Commit E: merge B&C, resolving in favor of C
1350#
1351# This is an obvious add/add mode conflict. Can git detect it?
1352
1353test_expect_success 'setup conflicting modes for regular file' '
1354 test_create_repo regular-file-mode-conflict &&
1355 (
1356 cd regular-file-mode-conflict &&
1357
1358 touch irrelevant-file &&
1359 git add irrelevant-file &&
1360 git commit -m A &&
1361 git tag A &&
1362
1363 git checkout -b B A &&
1364 echo "command_to_run" >source_me.bash &&
1365 git add source_me.bash &&
1366 git commit -m B &&
1367
1368 git checkout -b C A &&
1369 echo "command_to_run" >source_me.bash &&
1370 git add source_me.bash &&
1371 test_chmod +x source_me.bash &&
1372 git commit -m C &&
1373
1374 git checkout -q B^0 &&
1375 git merge -s ours -m D C^0 &&
1376 git tag D &&
1377
1378 git checkout -q C^0 &&
1379 git merge -s ours -m E B^0 &&
1380 git tag E
1381 )
1382'
1383
1384test_expect_failure 'check conflicting modes for regular file' '
1385 (
1386 cd regular-file-mode-conflict &&
1387
1388 git checkout D^0 &&
1389
1390 test_must_fail git merge -s recursive E^0 &&
1391
1392 git ls-files -s >out &&
1393 test_line_count = 3 out &&
1394 git ls-files -u >out &&
1395 test_line_count = 2 out &&
1396 git ls-files -o >out &&
1397 test_line_count = 1 out
1398 )
1399'
1400
1401# Setup:
1402# L1---L2
1403# / \ / \
1404# master X ?
1405# \ / \ /
1406# R1---R2
1407#
1408# Where:
1409# master has two files, named 'b' and 'a'
1410# branches L1 and R1 both modify each of the two files in conflicting ways
1411#
1412# L2 is a merge of R1 into L1; more on it later.
1413# R2 is a merge of L1 into R1; more on it later.
1414#
1415# X is an auto-generated merge-base used when merging L2 and R2.
1416# since X is a merge of L1 and R1, it has conflicting versions of each file
1417#
1418# More about L2 and R2:
1419# - both resolve the conflicts in 'b' and 'a' differently
1420# - L2 renames 'b' to 'm'
1421# - R2 renames 'a' to 'm'
1422#
1423# In the end, in file 'm' we have four different conflicting files (from
1424# two versions of 'b' and two of 'a'). In addition, if
1425# merge.conflictstyle is diff3, then the base version also has
1426# conflict markers of its own, leading to a total of three levels of
1427# conflict markers. This is a pretty weird corner case, but we just want
1428# to ensure that we handle it as well as practical.
1429
1430test_expect_success 'setup nested conflicts' '
1431 test_create_repo nested_conflicts &&
1432 (
1433 cd nested_conflicts &&
1434
1435 # Create some related files now
1436 for i in $(test_seq 1 10)
1437 do
1438 echo Random base content line $i
1439 done >initial &&
1440
1441 cp initial b_L1 &&
1442 cp initial b_R1 &&
1443 cp initial b_L2 &&
1444 cp initial b_R2 &&
1445 cp initial a_L1 &&
1446 cp initial a_R1 &&
1447 cp initial a_L2 &&
1448 cp initial a_R2 &&
1449
1450 test_write_lines b b_L1 >>b_L1 &&
1451 test_write_lines b b_R1 >>b_R1 &&
1452 test_write_lines b b_L2 >>b_L2 &&
1453 test_write_lines b b_R2 >>b_R2 &&
1454 test_write_lines a a_L1 >>a_L1 &&
1455 test_write_lines a a_R1 >>a_R1 &&
1456 test_write_lines a a_L2 >>a_L2 &&
1457 test_write_lines a a_R2 >>a_R2 &&
1458
1459 # Setup original commit (or merge-base), consisting of
1460 # files named "b" and "a"
1461 cp initial b &&
1462 cp initial a &&
1463 echo b >>b &&
1464 echo a >>a &&
1465 git add b a &&
1466 test_tick && git commit -m initial &&
1467
1468 git branch L &&
1469 git branch R &&
1470
1471 # Handle the left side
1472 git checkout L &&
1473 mv -f b_L1 b &&
1474 mv -f a_L1 a &&
1475 git add b a &&
1476 test_tick && git commit -m "version L1 of files" &&
1477 git tag L1 &&
1478
1479 # Handle the right side
1480 git checkout R &&
1481 mv -f b_R1 b &&
1482 mv -f a_R1 a &&
1483 git add b a &&
1484 test_tick && git commit -m "verson R1 of files" &&
1485 git tag R1 &&
1486
1487 # Create first merge on left side
1488 git checkout L &&
1489 test_must_fail git merge R1 &&
1490 mv -f b_L2 b &&
1491 mv -f a_L2 a &&
1492 git add b a &&
1493 git mv b m &&
1494 test_tick && git commit -m "left merge, rename b->m" &&
1495 git tag L2 &&
1496
1497 # Create first merge on right side
1498 git checkout R &&
1499 test_must_fail git merge L1 &&
1500 mv -f b_R2 b &&
1501 mv -f a_R2 a &&
1502 git add b a &&
1503 git mv a m &&
1504 test_tick && git commit -m "right merge, rename a->m" &&
1505 git tag R2
1506 )
1507'
1508
1509test_expect_success 'check nested conflicts' '
1510 (
1511 cd nested_conflicts &&
1512
1513 git clean -f &&
1514 git checkout L2^0 &&
1515
1516 # Merge must fail; there is a conflict
1517 test_must_fail git -c merge.conflictstyle=diff3 merge -s recursive R2^0 &&
1518
1519 # Make sure the index has the right number of entries
1520 git ls-files -s >out &&
1521 test_line_count = 2 out &&
1522 git ls-files -u >out &&
1523 test_line_count = 2 out &&
1524 # Ensure we have the correct number of untracked files
1525 git ls-files -o >out &&
1526 test_line_count = 1 out &&
1527
1528 # Create a and b from virtual merge base X
1529 git cat-file -p master:a >base &&
1530 git cat-file -p L1:a >ours &&
1531 git cat-file -p R1:a >theirs &&
1532 test_must_fail git merge-file --diff3 \
1533 -L "Temporary merge branch 1" \
1534 -L "merged common ancestors" \
1535 -L "Temporary merge branch 2" \
1536 ours \
1537 base \
1538 theirs &&
1539 sed -e "s/^\([<|=>]\)/\1\1/" ours >vmb_a &&
1540
1541 git cat-file -p master:b >base &&
1542 git cat-file -p L1:b >ours &&
1543 git cat-file -p R1:b >theirs &&
1544 test_must_fail git merge-file --diff3 \
1545 -L "Temporary merge branch 1" \
1546 -L "merged common ancestors" \
1547 -L "Temporary merge branch 2" \
1548 ours \
1549 base \
1550 theirs &&
1551 sed -e "s/^\([<|=>]\)/\1\1/" ours >vmb_b &&
1552
1553 # Compare :2:m to expected values
1554 git cat-file -p L2:m >ours &&
1555 git cat-file -p R2:b >theirs &&
1556 test_must_fail git merge-file --diff3 \
1557 -L "HEAD:m" \
1558 -L "merged common ancestors:b" \
1559 -L "R2^0:b" \
1560 ours \
1561 vmb_b \
1562 theirs &&
1563 sed -e "s/^\([<|=>]\)/\1\1/" ours >m_stage_2 &&
1564 git cat-file -p :2:m >actual &&
1565 test_cmp m_stage_2 actual &&
1566
1567 # Compare :3:m to expected values
1568 git cat-file -p L2:a >ours &&
1569 git cat-file -p R2:m >theirs &&
1570 test_must_fail git merge-file --diff3 \
1571 -L "HEAD:a" \
1572 -L "merged common ancestors:a" \
1573 -L "R2^0:m" \
1574 ours \
1575 vmb_a \
1576 theirs &&
1577 sed -e "s/^\([<|=>]\)/\1\1/" ours >m_stage_3 &&
1578 git cat-file -p :3:m >actual &&
1579 test_cmp m_stage_3 actual &&
1580
1581 # Compare m to expected contents
1582 >empty &&
1583 cp -a m_stage_2 expected_final_m &&
1584 test_must_fail git merge-file --diff3 \
1585 -L "HEAD" \
1586 -L "merged common ancestors" \
1587 -L "R2^0" \
1588 expected_final_m \
1589 empty \
1590 m_stage_3 &&
1591 test_cmp expected_final_m m
1592 )
1593'
1594
1595# Setup:
1596# L1---L2---L3
1597# / \ / \ / \
1598# master X1 X2 ?
1599# \ / \ / \ /
1600# R1---R2---R3
1601#
1602# Where:
1603# master has one file named 'content'
1604# branches L1 and R1 both modify each of the two files in conflicting ways
1605#
1606# L<n> (n>1) is a merge of R<n-1> into L<n-1>
1607# R<n> (n>1) is a merge of L<n-1> into R<n-1>
1608# L<n> and R<n> resolve the conflicts differently.
1609#
1610# X<n> is an auto-generated merge-base used when merging L<n+1> and R<n+1>.
1611# By construction, X1 has conflict markers due to conflicting versions.
1612# X2, due to using merge.conflictstyle=3, has nested conflict markers.
1613#
1614# So, merging R3 into L3 using merge.conflictstyle=3 should show the
1615# nested conflict markers from X2 in the base version -- that means we
1616# have three levels of conflict markers. Can we distinguish all three?
1617
1618test_expect_success 'setup virtual merge base with nested conflicts' '
1619 test_create_repo virtual_merge_base_has_nested_conflicts &&
1620 (
1621 cd virtual_merge_base_has_nested_conflicts &&
1622
1623 # Create some related files now
1624 for i in $(test_seq 1 10)
1625 do
1626 echo Random base content line $i
1627 done >content &&
1628
1629 # Setup original commit
1630 git add content &&
1631 test_tick && git commit -m initial &&
1632
1633 git branch L &&
1634 git branch R &&
1635
1636 # Create L1
1637 git checkout L &&
1638 echo left >>content &&
1639 git add content &&
1640 test_tick && git commit -m "version L1 of content" &&
1641 git tag L1 &&
1642
1643 # Create R1
1644 git checkout R &&
1645 echo right >>content &&
1646 git add content &&
1647 test_tick && git commit -m "verson R1 of content" &&
1648 git tag R1 &&
1649
1650 # Create L2
1651 git checkout L &&
1652 test_must_fail git -c merge.conflictstyle=diff3 merge R1 &&
1653 git checkout L1 content &&
1654 test_tick && git commit -m "version L2 of content" &&
1655 git tag L2 &&
1656
1657 # Create R2
1658 git checkout R &&
1659 test_must_fail git -c merge.conflictstyle=diff3 merge L1 &&
1660 git checkout R1 content &&
1661 test_tick && git commit -m "version R2 of content" &&
1662 git tag R2 &&
1663
1664 # Create L3
1665 git checkout L &&
1666 test_must_fail git -c merge.conflictstyle=diff3 merge R2 &&
1667 git checkout L1 content &&
1668 test_tick && git commit -m "version L3 of content" &&
1669 git tag L3 &&
1670
1671 # Create R3
1672 git checkout R &&
1673 test_must_fail git -c merge.conflictstyle=diff3 merge L2 &&
1674 git checkout R1 content &&
1675 test_tick && git commit -m "version R3 of content" &&
1676 git tag R3
1677 )
1678'
1679
1680test_expect_success 'check virtual merge base with nested conflicts' '
1681 (
1682 cd virtual_merge_base_has_nested_conflicts &&
1683
1684 git checkout L3^0 &&
1685
1686 # Merge must fail; there is a conflict
1687 test_must_fail git -c merge.conflictstyle=diff3 merge -s recursive R3^0 &&
1688
1689 # Make sure the index has the right number of entries
1690 git ls-files -s >out &&
1691 test_line_count = 3 out &&
1692 git ls-files -u >out &&
1693 test_line_count = 3 out &&
1694 # Ensure we have the correct number of untracked files
1695 git ls-files -o >out &&
1696 test_line_count = 1 out &&
1697
1698 # Compare :[23]:content to expected values
1699 git rev-parse L1:content R1:content >expect &&
1700 git rev-parse :2:content :3:content >actual &&
1701 test_cmp expect actual &&
1702
1703 # Imitate X1 merge base, except without long enough conflict
1704 # markers because a subsequent sed will modify them. Put
1705 # result into vmb.
1706 git cat-file -p master:content >base &&
1707 git cat-file -p L:content >left &&
1708 git cat-file -p R:content >right &&
1709 cp left merged-once &&
1710 test_must_fail git merge-file --diff3 \
1711 -L "Temporary merge branch 1" \
1712 -L "merged common ancestors" \
1713 -L "Temporary merge branch 2" \
1714 merged-once \
1715 base \
1716 right &&
1717 sed -e "s/^\([<|=>]\)/\1\1\1/" merged-once >vmb &&
1718
1719 # Imitate X2 merge base, overwriting vmb. Note that we
1720 # extend both sets of conflict markers to make them longer
1721 # with the sed command.
1722 cp left merged-twice &&
1723 test_must_fail git merge-file --diff3 \
1724 -L "Temporary merge branch 1" \
1725 -L "merged common ancestors" \
1726 -L "Temporary merge branch 2" \
1727 merged-twice \
1728 vmb \
1729 right &&
1730 sed -e "s/^\([<|=>]\)/\1\1\1/" merged-twice >vmb &&
1731
1732 # Compare :1:content to expected value
1733 git cat-file -p :1:content >actual &&
1734 test_cmp vmb actual &&
1735
1736 # Determine expected content in final outer merge, compare to
1737 # what the merge generated.
1738 cp -f left expect &&
1739 test_must_fail git merge-file --diff3 \
1740 -L "HEAD" -L "merged common ancestors" -L "R3^0" \
1741 expect vmb right &&
1742 test_cmp expect content
1743 )
1744'
1745
1746test_done