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