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