Start the 2.46 cycle
[git.git] / t / t6422-merge-rename-corner-cases.sh
blob80d7b5eabaf02e555cab3c4e37342a9eb2788f5f
1 #!/bin/sh
3 test_description="recursive merge corner cases w/ renames but not criss-crosses"
4 # t6036 has corner cases that involve both criss-cross merges and renames
6 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
7 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
9 TEST_PASSES_SANITIZE_LEAK=true
10 . ./test-lib.sh
11 . "$TEST_DIRECTORY"/lib-merge.sh
13 test_setup_rename_delete_untracked () {
14 git init rename-delete-untracked &&
16 cd rename-delete-untracked &&
18 echo "A pretty inscription" >ring &&
19 git add ring &&
20 test_tick &&
21 git commit -m beginning &&
23 git branch people &&
24 git checkout -b rename-the-ring &&
25 git mv ring one-ring-to-rule-them-all &&
26 test_tick &&
27 git commit -m fullname &&
29 git checkout people &&
30 git rm ring &&
31 echo gollum >owner &&
32 git add owner &&
33 test_tick &&
34 git commit -m track-people-instead-of-objects &&
35 echo "Myyy PRECIOUSSS" >ring
39 test_expect_success "Does git preserve Gollum's precious artifact?" '
40 test_setup_rename_delete_untracked &&
42 cd rename-delete-untracked &&
44 test_must_fail git merge -s recursive rename-the-ring &&
46 # Make sure git did not delete an untracked file
47 test_path_is_file ring
51 # Testcase setup for rename/modify/add-source:
52 # Commit A: new file: a
53 # Commit B: modify a slightly
54 # Commit C: rename a->b, add completely different a
56 # We should be able to merge B & C cleanly
58 test_setup_rename_modify_add_source () {
59 git init rename-modify-add-source &&
61 cd rename-modify-add-source &&
63 printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
64 git add a &&
65 git commit -m A &&
66 git tag A &&
68 git checkout -b B A &&
69 echo 8 >>a &&
70 git add a &&
71 git commit -m B &&
73 git checkout -b C A &&
74 git mv a b &&
75 echo something completely different >a &&
76 git add a &&
77 git commit -m C
81 test_expect_failure 'rename/modify/add-source conflict resolvable' '
82 test_setup_rename_modify_add_source &&
84 cd rename-modify-add-source &&
86 git checkout B^0 &&
88 git merge -s recursive C^0 &&
90 git rev-parse >expect \
91 B:a C:a &&
92 git rev-parse >actual \
93 b c &&
94 test_cmp expect actual
98 test_setup_break_detection_1 () {
99 git init break-detection-1 &&
101 cd break-detection-1 &&
103 printf "1\n2\n3\n4\n5\n" >a &&
104 echo foo >b &&
105 git add a b &&
106 git commit -m A &&
107 git tag A &&
109 git checkout -b B A &&
110 git mv a c &&
111 echo "Completely different content" >a &&
112 git add a &&
113 git commit -m B &&
115 git checkout -b C A &&
116 echo 6 >>a &&
117 git add a &&
118 git commit -m C
122 test_expect_failure 'conflict caused if rename not detected' '
123 test_setup_break_detection_1 &&
125 cd break-detection-1 &&
127 git checkout -q C^0 &&
128 git merge -s recursive B^0 &&
130 git ls-files -s >out &&
131 test_line_count = 3 out &&
132 git ls-files -u >out &&
133 test_line_count = 0 out &&
134 git ls-files -o >out &&
135 test_line_count = 1 out &&
137 test_line_count = 6 c &&
138 git rev-parse >expect \
139 B:a A:b &&
140 git rev-parse >actual \
141 :0:a :0:b &&
142 test_cmp expect actual
146 test_setup_break_detection_2 () {
147 git init break-detection-2 &&
149 cd break-detection-2 &&
151 printf "1\n2\n3\n4\n5\n" >a &&
152 echo foo >b &&
153 git add a b &&
154 git commit -m A &&
155 git tag A &&
157 git checkout -b D A &&
158 echo 7 >>a &&
159 git add a &&
160 git mv a c &&
161 echo "Completely different content" >a &&
162 git add a &&
163 git commit -m D &&
165 git checkout -b E A &&
166 git rm a &&
167 echo "Completely different content" >>a &&
168 git add a &&
169 git commit -m E
173 test_expect_failure 'missed conflict if rename not detected' '
174 test_setup_break_detection_2 &&
176 cd break-detection-2 &&
178 git checkout -q E^0 &&
179 test_must_fail git merge -s recursive D^0
183 # Tests for undetected rename/add-source causing a file to erroneously be
184 # deleted (and for mishandled rename/rename(1to1) causing the same issue).
186 # This test uses a rename/rename(1to1)+add-source conflict (1to1 means the
187 # same file is renamed on both sides to the same thing; it should trigger
188 # the 1to2 logic, which it would do if the add-source didn't cause issues
189 # for git's rename detection):
190 # Commit A: new file: a
191 # Commit B: rename a->b
192 # Commit C: rename a->b, add unrelated a
194 test_setup_break_detection_3 () {
195 git init break-detection-3 &&
197 cd break-detection-3 &&
199 printf "1\n2\n3\n4\n5\n" >a &&
200 git add a &&
201 git commit -m A &&
202 git tag A &&
204 git checkout -b B A &&
205 git mv a b &&
206 git commit -m B &&
208 git checkout -b C A &&
209 git mv a b &&
210 echo foobar >a &&
211 git add a &&
212 git commit -m C
216 test_expect_failure 'detect rename/add-source and preserve all data' '
217 test_setup_break_detection_3 &&
219 cd break-detection-3 &&
221 git checkout B^0 &&
223 git merge -s recursive C^0 &&
225 git ls-files -s >out &&
226 test_line_count = 2 out &&
227 git ls-files -u >out &&
228 test_line_count = 2 out &&
229 git ls-files -o >out &&
230 test_line_count = 1 out &&
232 test_path_is_file a &&
233 test_path_is_file b &&
235 git rev-parse >expect \
236 A:a C:a &&
237 git rev-parse >actual \
238 :0:b :0:a &&
239 test_cmp expect actual
243 test_expect_failure 'detect rename/add-source and preserve all data, merge other way' '
244 test_setup_break_detection_3 &&
246 cd break-detection-3 &&
248 git checkout C^0 &&
250 git merge -s recursive B^0 &&
252 git ls-files -s >out &&
253 test_line_count = 2 out &&
254 git ls-files -u >out &&
255 test_line_count = 2 out &&
256 git ls-files -o >out &&
257 test_line_count = 1 out &&
259 test_path_is_file a &&
260 test_path_is_file b &&
262 git rev-parse >expect \
263 A:a C:a &&
264 git rev-parse >actual \
265 :0:b :0:a &&
266 test_cmp expect actual
270 test_setup_rename_directory () {
271 git init rename-directory-$1 &&
273 cd rename-directory-$1 &&
275 printf "1\n2\n3\n4\n5\n6\n" >file &&
276 git add file &&
277 test_tick &&
278 git commit -m base &&
279 git tag base &&
281 git checkout -b right &&
282 echo 7 >>file &&
283 mkdir newfile &&
284 echo junk >newfile/realfile &&
285 git add file newfile/realfile &&
286 test_tick &&
287 git commit -m right &&
289 git checkout -b left-conflict base &&
290 echo 8 >>file &&
291 git add file &&
292 git mv file newfile &&
293 test_tick &&
294 git commit -m left &&
296 git checkout -b left-clean base &&
297 echo 0 >newfile &&
298 cat file >>newfile &&
299 git add newfile &&
300 git rm file &&
301 test_tick &&
302 git commit -m left
306 test_expect_success 'rename/directory conflict + clean content merge' '
307 test_setup_rename_directory 1a &&
309 cd rename-directory-1a &&
311 git checkout left-clean^0 &&
313 test_must_fail git merge -s recursive right^0 &&
315 git ls-files -s >out &&
316 test_line_count = 2 out &&
317 git ls-files -u >out &&
318 test_line_count = 1 out &&
319 git ls-files -o >out &&
320 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
321 then
322 test_line_count = 1 out
323 else
324 test_line_count = 2 out
325 fi &&
327 echo 0 >expect &&
328 git cat-file -p base:file >>expect &&
329 echo 7 >>expect &&
330 test_cmp expect newfile~HEAD &&
332 test_path_is_file newfile/realfile &&
333 test_path_is_file newfile~HEAD
337 test_expect_success 'rename/directory conflict + content merge conflict' '
338 test_setup_rename_directory 1b &&
340 cd rename-directory-1b &&
342 git reset --hard &&
343 git clean -fdqx &&
345 git checkout left-conflict^0 &&
347 test_must_fail git merge -s recursive right^0 &&
349 git ls-files -s >out &&
350 test_line_count = 4 out &&
351 git ls-files -u >out &&
352 test_line_count = 3 out &&
353 git ls-files -o >out &&
354 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
355 then
356 test_line_count = 1 out
357 else
358 test_line_count = 2 out
359 fi &&
361 git cat-file -p left-conflict:newfile >left &&
362 git cat-file -p base:file >base &&
363 git cat-file -p right:file >right &&
364 test_must_fail git merge-file \
365 -L "HEAD:newfile" \
366 -L "" \
367 -L "right^0:file" \
368 left base right &&
369 test_cmp left newfile~HEAD &&
371 git rev-parse >expect \
372 base:file left-conflict:newfile right:file &&
373 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
374 then
375 git rev-parse >actual \
376 :1:newfile~HEAD :2:newfile~HEAD :3:newfile~HEAD
377 else
378 git rev-parse >actual \
379 :1:newfile :2:newfile :3:newfile
380 fi &&
381 test_cmp expect actual &&
383 test_path_is_file newfile/realfile &&
384 test_path_is_file newfile~HEAD
388 test_setup_rename_directory_2 () {
389 git init rename-directory-2 &&
391 cd rename-directory-2 &&
393 mkdir sub &&
394 printf "1\n2\n3\n4\n5\n6\n" >sub/file &&
395 git add sub/file &&
396 test_tick &&
397 git commit -m base &&
398 git tag base &&
400 git checkout -b right &&
401 echo 7 >>sub/file &&
402 git add sub/file &&
403 test_tick &&
404 git commit -m right &&
406 git checkout -b left base &&
407 echo 0 >newfile &&
408 cat sub/file >>newfile &&
409 git rm sub/file &&
410 mv newfile sub &&
411 git add sub &&
412 test_tick &&
413 git commit -m left
417 test_expect_success 'disappearing dir in rename/directory conflict handled' '
418 test_setup_rename_directory_2 &&
420 cd rename-directory-2 &&
422 git checkout left^0 &&
424 git merge -s recursive right^0 &&
426 git ls-files -s >out &&
427 test_line_count = 1 out &&
428 git ls-files -u >out &&
429 test_line_count = 0 out &&
430 git ls-files -o >out &&
431 test_line_count = 1 out &&
433 echo 0 >expect &&
434 git cat-file -p base:sub/file >>expect &&
435 echo 7 >>expect &&
436 test_cmp expect sub &&
438 test_path_is_file sub
442 # Test for basic rename/add-dest conflict, with rename needing content merge:
443 # Commit O: a
444 # Commit A: rename a->b, modifying b too
445 # Commit B: modify a, add different b
447 test_setup_rename_with_content_merge_and_add () {
448 git init rename-with-content-merge-and-add-$1 &&
450 cd rename-with-content-merge-and-add-$1 &&
452 test_seq 1 5 >a &&
453 git add a &&
454 git commit -m O &&
455 git tag O &&
457 git checkout -b A O &&
458 git mv a b &&
459 test_seq 0 5 >b &&
460 git add b &&
461 git commit -m A &&
463 git checkout -b B O &&
464 echo 6 >>a &&
465 echo hello world >b &&
466 git add a b &&
467 git commit -m B
471 test_expect_success 'handle rename-with-content-merge vs. add' '
472 test_setup_rename_with_content_merge_and_add AB &&
474 cd rename-with-content-merge-and-add-AB &&
476 git checkout A^0 &&
478 test_must_fail git merge -s recursive B^0 >out &&
479 test_grep "CONFLICT (.*/add)" out &&
481 git ls-files -s >out &&
482 test_line_count = 2 out &&
483 git ls-files -u >out &&
484 test_line_count = 2 out &&
485 # Also, make sure both unmerged entries are for "b"
486 git ls-files -u b >out &&
487 test_line_count = 2 out &&
488 git ls-files -o >out &&
489 test_line_count = 1 out &&
491 test_path_is_missing a &&
492 test_path_is_file b &&
494 test_seq 0 6 >tmp &&
495 git hash-object tmp >expect &&
496 git rev-parse B:b >>expect &&
497 git rev-parse >actual \
498 :2:b :3:b &&
499 test_cmp expect actual &&
501 # Test that the two-way merge in b is as expected
502 git cat-file -p :2:b >>ours &&
503 git cat-file -p :3:b >>theirs &&
504 >empty &&
505 test_must_fail git merge-file \
506 -L "HEAD" \
507 -L "" \
508 -L "B^0" \
509 ours empty theirs &&
510 test_cmp ours b
514 test_expect_success 'handle rename-with-content-merge vs. add, merge other way' '
515 test_setup_rename_with_content_merge_and_add BA &&
517 cd rename-with-content-merge-and-add-BA &&
519 git reset --hard &&
520 git clean -fdx &&
522 git checkout B^0 &&
524 test_must_fail git merge -s recursive A^0 >out &&
525 test_grep "CONFLICT (.*/add)" out &&
527 git ls-files -s >out &&
528 test_line_count = 2 out &&
529 git ls-files -u >out &&
530 test_line_count = 2 out &&
531 # Also, make sure both unmerged entries are for "b"
532 git ls-files -u b >out &&
533 test_line_count = 2 out &&
534 git ls-files -o >out &&
535 test_line_count = 1 out &&
537 test_path_is_missing a &&
538 test_path_is_file b &&
540 test_seq 0 6 >tmp &&
541 git rev-parse B:b >expect &&
542 git hash-object tmp >>expect &&
543 git rev-parse >actual \
544 :2:b :3:b &&
545 test_cmp expect actual &&
547 # Test that the two-way merge in b is as expected
548 git cat-file -p :2:b >>ours &&
549 git cat-file -p :3:b >>theirs &&
550 >empty &&
551 test_must_fail git merge-file \
552 -L "HEAD" \
553 -L "" \
554 -L "A^0" \
555 ours empty theirs &&
556 test_cmp ours b
560 # Test for all kinds of things that can go wrong with rename/rename (2to1):
561 # Commit A: new files: a & b
562 # Commit B: rename a->c, modify b
563 # Commit C: rename b->c, modify a
565 # Merging of B & C should NOT be clean. Questions:
566 # * Both a & b should be removed by the merge; are they?
567 # * The two c's should contain modifications to a & b; do they?
568 # * The index should contain two files, both for c; does it?
569 # * The working copy should have two files, both of form c~<unique>; does it?
570 # * Nothing else should be present. Is anything?
572 test_setup_rename_rename_2to1 () {
573 git init rename-rename-2to1 &&
575 cd rename-rename-2to1 &&
577 printf "1\n2\n3\n4\n5\n" >a &&
578 printf "5\n4\n3\n2\n1\n" >b &&
579 git add a b &&
580 git commit -m A &&
581 git tag A &&
583 git checkout -b B A &&
584 git mv a c &&
585 echo 0 >>b &&
586 git add b &&
587 git commit -m B &&
589 git checkout -b C A &&
590 git mv b c &&
591 echo 6 >>a &&
592 git add a &&
593 git commit -m C
597 test_expect_success 'handle rename/rename (2to1) conflict correctly' '
598 test_setup_rename_rename_2to1 &&
600 cd rename-rename-2to1 &&
602 git checkout B^0 &&
604 test_must_fail git merge -s recursive C^0 >out &&
605 test_grep "CONFLICT (\(.*\)/\1)" out &&
607 git ls-files -s >out &&
608 test_line_count = 2 out &&
609 git ls-files -u >out &&
610 test_line_count = 2 out &&
611 git ls-files -u c >out &&
612 test_line_count = 2 out &&
613 git ls-files -o >out &&
614 test_line_count = 1 out &&
616 test_path_is_missing a &&
617 test_path_is_missing b &&
619 git rev-parse >expect \
620 C:a B:b &&
621 git rev-parse >actual \
622 :2:c :3:c &&
623 test_cmp expect actual &&
625 # Test that the two-way merge in new_a is as expected
626 git cat-file -p :2:c >>ours &&
627 git cat-file -p :3:c >>theirs &&
628 >empty &&
629 test_must_fail git merge-file \
630 -L "HEAD" \
631 -L "" \
632 -L "C^0" \
633 ours empty theirs &&
634 git hash-object c >actual &&
635 git hash-object ours >expect &&
636 test_cmp expect actual
640 # Testcase setup for simple rename/rename (1to2) conflict:
641 # Commit A: new file: a
642 # Commit B: rename a->b
643 # Commit C: rename a->c
644 test_setup_rename_rename_1to2 () {
645 git init rename-rename-1to2 &&
647 cd rename-rename-1to2 &&
649 echo stuff >a &&
650 git add a &&
651 test_tick &&
652 git commit -m A &&
653 git tag A &&
655 git checkout -b B A &&
656 git mv a b &&
657 test_tick &&
658 git commit -m B &&
660 git checkout -b C A &&
661 git mv a c &&
662 test_tick &&
663 git commit -m C
667 test_expect_success 'merge has correct working tree contents' '
668 test_setup_rename_rename_1to2 &&
670 cd rename-rename-1to2 &&
672 git checkout C^0 &&
674 test_must_fail git merge -s recursive B^0 &&
676 git ls-files -s >out &&
677 test_line_count = 3 out &&
678 git ls-files -u >out &&
679 test_line_count = 3 out &&
680 git ls-files -o >out &&
681 test_line_count = 1 out &&
683 test_path_is_missing a &&
684 git rev-parse >expect \
685 A:a A:a A:a \
686 A:a A:a &&
687 git rev-parse >actual \
688 :1:a :3:b :2:c &&
689 git hash-object >>actual \
690 b c &&
691 test_cmp expect actual
695 # Testcase setup for rename/rename(1to2)/add-source conflict:
696 # Commit A: new file: a
697 # Commit B: rename a->b
698 # Commit C: rename a->c, add completely different a
700 # Merging of B & C should NOT be clean; there's a rename/rename conflict
702 test_setup_rename_rename_1to2_add_source_1 () {
703 git init rename-rename-1to2-add-source-1 &&
705 cd rename-rename-1to2-add-source-1 &&
707 printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
708 git add a &&
709 git commit -m A &&
710 git tag A &&
712 git checkout -b B A &&
713 git mv a b &&
714 git commit -m B &&
716 git checkout -b C A &&
717 git mv a c &&
718 echo something completely different >a &&
719 git add a &&
720 git commit -m C
724 test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge' '
725 test_setup_rename_rename_1to2_add_source_1 &&
727 cd rename-rename-1to2-add-source-1 &&
729 git checkout B^0 &&
731 test_must_fail git merge -s recursive C^0 &&
733 git ls-files -s >out &&
734 test_line_count = 4 out &&
735 git ls-files -o >out &&
736 test_line_count = 1 out &&
738 git rev-parse >expect \
739 C:a A:a B:b C:C &&
740 git rev-parse >actual \
741 :3:a :1:a :2:b :3:c &&
742 test_cmp expect actual &&
744 test_path_is_file a &&
745 test_path_is_file b &&
746 test_path_is_file c
750 test_setup_rename_rename_1to2_add_source_2 () {
751 git init rename-rename-1to2-add-source-2 &&
753 cd rename-rename-1to2-add-source-2 &&
755 >a &&
756 git add a &&
757 test_tick &&
758 git commit -m base &&
759 git tag A &&
761 git checkout -b B A &&
762 git mv a b &&
763 test_tick &&
764 git commit -m one &&
766 git checkout -b C A &&
767 git mv a b &&
768 echo important-info >a &&
769 git add a &&
770 test_tick &&
771 git commit -m two
775 test_expect_failure 'rename/rename/add-source still tracks new a file' '
776 test_setup_rename_rename_1to2_add_source_2 &&
778 cd rename-rename-1to2-add-source-2 &&
780 git checkout C^0 &&
781 git merge -s recursive B^0 &&
783 git ls-files -s >out &&
784 test_line_count = 2 out &&
785 git ls-files -o >out &&
786 test_line_count = 1 out &&
788 git rev-parse >expect \
789 C:a A:a &&
790 git rev-parse >actual \
791 :0:a :0:b &&
792 test_cmp expect actual
796 test_setup_rename_rename_1to2_add_dest () {
797 git init rename-rename-1to2-add-dest &&
799 cd rename-rename-1to2-add-dest &&
801 echo stuff >a &&
802 git add a &&
803 test_tick &&
804 git commit -m base &&
805 git tag A &&
807 git checkout -b B A &&
808 git mv a b &&
809 echo precious-data >c &&
810 git add c &&
811 test_tick &&
812 git commit -m one &&
814 git checkout -b C A &&
815 git mv a c &&
816 echo important-info >b &&
817 git add b &&
818 test_tick &&
819 git commit -m two
823 test_expect_success 'rename/rename/add-dest merge still knows about conflicting file versions' '
824 test_setup_rename_rename_1to2_add_dest &&
826 cd rename-rename-1to2-add-dest &&
828 git checkout C^0 &&
829 test_must_fail git merge -s recursive B^0 &&
831 git ls-files -s >out &&
832 test_line_count = 5 out &&
833 git ls-files -u b >out &&
834 test_line_count = 2 out &&
835 git ls-files -u c >out &&
836 test_line_count = 2 out &&
837 git ls-files -o >out &&
838 test_line_count = 1 out &&
840 git rev-parse >expect \
841 A:a C:b B:b C:c B:c &&
842 git rev-parse >actual \
843 :1:a :2:b :3:b :2:c :3:c &&
844 test_cmp expect actual &&
846 # Record some contents for re-doing merges
847 git cat-file -p A:a >stuff &&
848 git cat-file -p C:b >important_info &&
849 git cat-file -p B:c >precious_data &&
850 >empty &&
852 # Test the merge in b
853 test_must_fail git merge-file \
854 -L "HEAD" \
855 -L "" \
856 -L "B^0" \
857 important_info empty stuff &&
858 test_cmp important_info b &&
860 # Test the merge in c
861 test_must_fail git merge-file \
862 -L "HEAD" \
863 -L "" \
864 -L "B^0" \
865 stuff empty precious_data &&
866 test_cmp stuff c
870 # Testcase rad, rename/add/delete
871 # Commit O: foo
872 # Commit A: rm foo, add different bar
873 # Commit B: rename foo->bar
874 # Expected: CONFLICT (rename/add/delete), two-way merged bar
876 test_setup_rad () {
877 git init rad &&
879 cd rad &&
880 echo "original file" >foo &&
881 git add foo &&
882 git commit -m "original" &&
884 git branch O &&
885 git branch A &&
886 git branch B &&
888 git checkout A &&
889 git rm foo &&
890 echo "different file" >bar &&
891 git add bar &&
892 git commit -m "Remove foo, add bar" &&
894 git checkout B &&
895 git mv foo bar &&
896 git commit -m "rename foo to bar"
900 test_expect_merge_algorithm failure success 'rad-check: rename/add/delete conflict' '
901 test_setup_rad &&
903 cd rad &&
905 git checkout B^0 &&
906 test_must_fail git merge -s recursive A^0 >out 2>err &&
908 # Instead of requiring the output to contain one combined line
909 # CONFLICT (rename/add/delete)
910 # or perhaps two lines:
911 # CONFLICT (rename/add): new file collides with rename target
912 # CONFLICT (rename/delete): rename source removed on other side
913 # and instead of requiring "rename/add" instead of "add/add",
914 # be flexible in the type of console output message(s) reported
915 # for this particular case; we will be more stringent about the
916 # contents of the index and working directory.
917 test_grep "CONFLICT (.*/add)" out &&
918 test_grep "CONFLICT (rename.*/delete)" out &&
919 test_must_be_empty err &&
921 git ls-files -s >file_count &&
922 test_line_count = 2 file_count &&
923 git ls-files -u >file_count &&
924 test_line_count = 2 file_count &&
925 git ls-files -o >file_count &&
926 test_line_count = 3 file_count &&
928 git rev-parse >actual \
929 :2:bar :3:bar &&
930 git rev-parse >expect \
931 B:bar A:bar &&
933 test_path_is_missing foo &&
934 # bar should have two-way merged contents of the different
935 # versions of bar; check that content from both sides is
936 # present.
937 grep original bar &&
938 grep different bar
942 # Testcase rrdd, rename/rename(2to1)/delete/delete
943 # Commit O: foo, bar
944 # Commit A: rename foo->baz, rm bar
945 # Commit B: rename bar->baz, rm foo
946 # Expected: CONFLICT (rename/rename/delete/delete), two-way merged baz
948 test_setup_rrdd () {
949 git init rrdd &&
951 cd rrdd &&
952 echo foo >foo &&
953 echo bar >bar &&
954 git add foo bar &&
955 git commit -m O &&
957 git branch O &&
958 git branch A &&
959 git branch B &&
961 git checkout A &&
962 git mv foo baz &&
963 git rm bar &&
964 git commit -m "Rename foo, remove bar" &&
966 git checkout B &&
967 git mv bar baz &&
968 git rm foo &&
969 git commit -m "Rename bar, remove foo"
973 test_expect_merge_algorithm failure success 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '
974 test_setup_rrdd &&
976 cd rrdd &&
978 git checkout A^0 &&
979 test_must_fail git merge -s recursive B^0 >out 2>err &&
981 # Instead of requiring the output to contain one combined line
982 # CONFLICT (rename/rename/delete/delete)
983 # or perhaps two lines:
984 # CONFLICT (rename/rename): ...
985 # CONFLICT (rename/delete): info about pair 1
986 # CONFLICT (rename/delete): info about pair 2
987 # and instead of requiring "rename/rename" instead of "add/add",
988 # be flexible in the type of console output message(s) reported
989 # for this particular case; we will be more stringent about the
990 # contents of the index and working directory.
991 test_grep "CONFLICT (\(.*\)/\1)" out &&
992 test_grep "CONFLICT (rename.*delete)" out &&
993 test_must_be_empty err &&
995 git ls-files -s >file_count &&
996 test_line_count = 2 file_count &&
997 git ls-files -u >file_count &&
998 test_line_count = 2 file_count &&
999 git ls-files -o >file_count &&
1000 test_line_count = 3 file_count &&
1002 git rev-parse >actual \
1003 :2:baz :3:baz &&
1004 git rev-parse >expect \
1005 O:foo O:bar &&
1007 test_path_is_missing foo &&
1008 test_path_is_missing bar &&
1009 # baz should have two-way merged contents of the original
1010 # contents of foo and bar; check that content from both sides
1011 # is present.
1012 grep foo baz &&
1013 grep bar baz
1017 # Testcase mod6, chains of rename/rename(1to2) and rename/rename(2to1)
1018 # Commit O: one, three, five
1019 # Commit A: one->two, three->four, five->six
1020 # Commit B: one->six, three->two, five->four
1021 # Expected: six CONFLICT(rename/rename) messages, each path in two of the
1022 # multi-way merged contents found in two, four, six
1024 test_setup_mod6 () {
1025 git init mod6 &&
1027 cd mod6 &&
1028 test_seq 11 19 >one &&
1029 test_seq 31 39 >three &&
1030 test_seq 51 59 >five &&
1031 git add . &&
1032 test_tick &&
1033 git commit -m "O" &&
1035 git branch O &&
1036 git branch A &&
1037 git branch B &&
1039 git checkout A &&
1040 test_seq 10 19 >one &&
1041 echo 40 >>three &&
1042 git add one three &&
1043 git mv one two &&
1044 git mv three four &&
1045 git mv five six &&
1046 test_tick &&
1047 git commit -m "A" &&
1049 git checkout B &&
1050 echo 20 >>one &&
1051 echo forty >>three &&
1052 echo 60 >>five &&
1053 git add one three five &&
1054 git mv one six &&
1055 git mv three two &&
1056 git mv five four &&
1057 test_tick &&
1058 git commit -m "B"
1062 test_expect_merge_algorithm failure success 'mod6-check: chains of rename/rename(1to2) and rename/rename(2to1)' '
1063 test_setup_mod6 &&
1065 cd mod6 &&
1067 git checkout A^0 &&
1069 test_must_fail git merge -s recursive B^0 >out 2>err &&
1071 test_grep "CONFLICT (rename/rename)" out &&
1072 test_must_be_empty err &&
1074 git ls-files -s >file_count &&
1075 test_line_count = 9 file_count &&
1076 git ls-files -u >file_count &&
1077 test_line_count = 9 file_count &&
1078 git ls-files -o >file_count &&
1079 test_line_count = 3 file_count &&
1081 test_seq 10 20 >merged-one &&
1082 test_seq 51 60 >merged-five &&
1083 # Determine what the merge of three would give us.
1084 test_seq 31 39 >three-base &&
1085 test_seq 31 40 >three-side-A &&
1086 test_seq 31 39 >three-side-B &&
1087 echo forty >>three-side-B &&
1088 test_must_fail git merge-file \
1089 -L "HEAD:four" \
1090 -L "" \
1091 -L "B^0:two" \
1092 three-side-A three-base three-side-B &&
1093 sed -e "s/^\([<=>]\)/\1\1/" three-side-A >merged-three &&
1095 # Verify the index is as expected
1096 git rev-parse >actual \
1097 :2:two :3:two \
1098 :2:four :3:four \
1099 :2:six :3:six &&
1100 git hash-object >expect \
1101 merged-one merged-three \
1102 merged-three merged-five \
1103 merged-five merged-one &&
1104 test_cmp expect actual &&
1106 git cat-file -p :2:two >expect &&
1107 git cat-file -p :3:two >other &&
1108 >empty &&
1109 test_must_fail git merge-file \
1110 -L "HEAD" -L "" -L "B^0" \
1111 expect empty other &&
1112 test_cmp expect two &&
1114 git cat-file -p :2:four >expect &&
1115 git cat-file -p :3:four >other &&
1116 test_must_fail git merge-file \
1117 -L "HEAD" -L "" -L "B^0" \
1118 expect empty other &&
1119 test_cmp expect four &&
1121 git cat-file -p :2:six >expect &&
1122 git cat-file -p :3:six >other &&
1123 test_must_fail git merge-file \
1124 -L "HEAD" -L "" -L "B^0" \
1125 expect empty other &&
1126 test_cmp expect six
1130 test_conflicts_with_adds_and_renames() {
1131 sideL=$1
1132 sideR=$2
1134 # Setup:
1136 # / \
1137 # main ?
1138 # \ /
1141 # Where:
1142 # Both L and R have files named 'three' which collide. Each of
1143 # the colliding files could have been involved in a rename, in
1144 # which case there was a file named 'one' or 'two' that was
1145 # modified on the opposite side of history and renamed into the
1146 # collision on this side of history.
1148 # Questions:
1149 # 1) The index should contain both a stage 2 and stage 3 entry
1150 # for the colliding file. Does it?
1151 # 2) When renames are involved, the content merges are clean, so
1152 # the index should reflect the content merges, not merely the
1153 # version of the colliding file from the prior commit. Does
1154 # it?
1155 # 3) There should be a file in the worktree named 'three'
1156 # containing the two-way merged contents of the content-merged
1157 # versions of 'three' from each of the two colliding
1158 # files. Is it present?
1159 # 4) There should not be any three~* files in the working
1160 # tree
1161 test_setup_collision_conflict () {
1162 git init simple_${sideL}_${sideR} &&
1164 cd simple_${sideL}_${sideR} &&
1166 # Create some related files now
1167 for i in $(test_seq 1 10)
1169 echo Random base content line $i
1170 done >file_v1 &&
1171 cp file_v1 file_v2 &&
1172 echo modification >>file_v2 &&
1174 cp file_v1 file_v3 &&
1175 echo more stuff >>file_v3 &&
1176 cp file_v3 file_v4 &&
1177 echo yet more stuff >>file_v4 &&
1179 # Use a tag to record both these files for simple
1180 # access, and clean out these untracked files
1181 git tag file_v1 $(git hash-object -w file_v1) &&
1182 git tag file_v2 $(git hash-object -w file_v2) &&
1183 git tag file_v3 $(git hash-object -w file_v3) &&
1184 git tag file_v4 $(git hash-object -w file_v4) &&
1185 git clean -f &&
1187 # Setup original commit (or merge-base), consisting of
1188 # files named "one" and "two" if renames were involved.
1189 touch irrelevant_file &&
1190 git add irrelevant_file &&
1191 if [ $sideL = "rename" ]
1192 then
1193 git show file_v1 >one &&
1194 git add one
1195 fi &&
1196 if [ $sideR = "rename" ]
1197 then
1198 git show file_v3 >two &&
1199 git add two
1200 fi &&
1201 test_tick && git commit -m initial &&
1203 git branch L &&
1204 git branch R &&
1206 # Handle the left side
1207 git checkout L &&
1208 if [ $sideL = "rename" ]
1209 then
1210 git mv one three
1211 else
1212 git show file_v2 >three &&
1213 git add three
1214 fi &&
1215 if [ $sideR = "rename" ]
1216 then
1217 git show file_v4 >two &&
1218 git add two
1219 fi &&
1220 test_tick && git commit -m L &&
1222 # Handle the right side
1223 git checkout R &&
1224 if [ $sideL = "rename" ]
1225 then
1226 git show file_v2 >one &&
1227 git add one
1228 fi &&
1229 if [ $sideR = "rename" ]
1230 then
1231 git mv two three
1232 else
1233 git show file_v4 >three &&
1234 git add three
1235 fi &&
1236 test_tick && git commit -m R
1240 test_expect_success "check simple $sideL/$sideR conflict" '
1241 test_setup_collision_conflict &&
1243 cd simple_${sideL}_${sideR} &&
1245 git checkout L^0 &&
1247 # Merge must fail; there is a conflict
1248 test_must_fail git merge -s recursive R^0 &&
1250 # Make sure the index has the right number of entries
1251 git ls-files -s >out &&
1252 test_line_count = 3 out &&
1253 git ls-files -u >out &&
1254 test_line_count = 2 out &&
1255 # Ensure we have the correct number of untracked files
1256 git ls-files -o >out &&
1257 test_line_count = 1 out &&
1259 # Nothing should have touched irrelevant_file
1260 git rev-parse >actual \
1261 :0:irrelevant_file \
1262 :2:three \
1263 :3:three &&
1264 git rev-parse >expected \
1265 main:irrelevant_file \
1266 file_v2 \
1267 file_v4 &&
1268 test_cmp expected actual &&
1270 # Make sure we have the correct merged contents for
1271 # three
1272 git show file_v1 >expected &&
1273 cat <<-\EOF >>expected &&
1274 <<<<<<< HEAD
1275 modification
1276 =======
1277 more stuff
1278 yet more stuff
1279 >>>>>>> R^0
1282 test_cmp expected three
1287 test_conflicts_with_adds_and_renames rename rename
1288 test_conflicts_with_adds_and_renames rename add
1289 test_conflicts_with_adds_and_renames add rename
1290 test_conflicts_with_adds_and_renames add add
1292 # Setup:
1294 # / \
1295 # main ?
1296 # \ /
1299 # Where:
1300 # main has two files, named 'one' and 'two'.
1301 # branches L and R both modify 'one', in conflicting ways.
1302 # branches L and R both modify 'two', in conflicting ways.
1303 # branch L also renames 'one' to 'three'.
1304 # branch R also renames 'two' to 'three'.
1306 # So, we have four different conflicting files that all end up at path
1307 # 'three'.
1308 test_setup_nested_conflicts_from_rename_rename () {
1309 git init nested_conflicts_from_rename_rename &&
1311 cd nested_conflicts_from_rename_rename &&
1313 # Create some related files now
1314 for i in $(test_seq 1 10)
1316 echo Random base content line $i
1317 done >file_v1 &&
1319 cp file_v1 file_v2 &&
1320 cp file_v1 file_v3 &&
1321 cp file_v1 file_v4 &&
1322 cp file_v1 file_v5 &&
1323 cp file_v1 file_v6 &&
1325 echo one >>file_v1 &&
1326 echo uno >>file_v2 &&
1327 echo eins >>file_v3 &&
1329 echo two >>file_v4 &&
1330 echo dos >>file_v5 &&
1331 echo zwei >>file_v6 &&
1333 # Setup original commit (or merge-base), consisting of
1334 # files named "one" and "two".
1335 mv file_v1 one &&
1336 mv file_v4 two &&
1337 git add one two &&
1338 test_tick && git commit -m english &&
1340 git branch L &&
1341 git branch R &&
1343 # Handle the left side
1344 git checkout L &&
1345 git rm one two &&
1346 mv -f file_v2 three &&
1347 mv -f file_v5 two &&
1348 git add two three &&
1349 test_tick && git commit -m spanish &&
1351 # Handle the right side
1352 git checkout R &&
1353 git rm one two &&
1354 mv -f file_v3 one &&
1355 mv -f file_v6 three &&
1356 git add one three &&
1357 test_tick && git commit -m german
1361 test_expect_success 'check nested conflicts from rename/rename(2to1)' '
1362 test_setup_nested_conflicts_from_rename_rename &&
1364 cd nested_conflicts_from_rename_rename &&
1366 git checkout L^0 &&
1368 # Merge must fail; there is a conflict
1369 test_must_fail git merge -s recursive R^0 &&
1371 # Make sure the index has the right number of entries
1372 git ls-files -s >out &&
1373 test_line_count = 2 out &&
1374 git ls-files -u >out &&
1375 test_line_count = 2 out &&
1376 # Ensure we have the correct number of untracked files
1377 git ls-files -o >out &&
1378 test_line_count = 1 out &&
1380 # Compare :2:three to expected values
1381 git cat-file -p main:one >base &&
1382 git cat-file -p L:three >ours &&
1383 git cat-file -p R:one >theirs &&
1384 test_must_fail git merge-file \
1385 -L "HEAD:three" -L "" -L "R^0:one" \
1386 ours base theirs &&
1387 sed -e "s/^\([<=>]\)/\1\1/" ours >L-three &&
1388 git cat-file -p :2:three >expect &&
1389 test_cmp expect L-three &&
1391 # Compare :2:three to expected values
1392 git cat-file -p main:two >base &&
1393 git cat-file -p L:two >ours &&
1394 git cat-file -p R:three >theirs &&
1395 test_must_fail git merge-file \
1396 -L "HEAD:two" -L "" -L "R^0:three" \
1397 ours base theirs &&
1398 sed -e "s/^\([<=>]\)/\1\1/" ours >R-three &&
1399 git cat-file -p :3:three >expect &&
1400 test_cmp expect R-three &&
1402 # Compare three to expected contents
1403 >empty &&
1404 test_must_fail git merge-file \
1405 -L "HEAD" -L "" -L "R^0" \
1406 L-three empty R-three &&
1407 test_cmp three L-three
1411 # Testcase rename/rename(1to2) of a binary file
1412 # Commit O: orig
1413 # Commit A: orig-A
1414 # Commit B: orig-B
1415 # Expected: CONFLICT(rename/rename) message, three unstaged entries in the
1416 # index, and contents of orig-[AB] at path orig-[AB]
1417 test_setup_rename_rename_1_to_2_binary () {
1418 git init rename_rename_1_to_2_binary &&
1420 cd rename_rename_1_to_2_binary &&
1422 echo '* binary' >.gitattributes &&
1423 git add .gitattributes &&
1425 test_seq 1 10 >orig &&
1426 git add orig &&
1427 git commit -m orig &&
1429 git branch A &&
1430 git branch B &&
1432 git checkout A &&
1433 git mv orig orig-A &&
1434 test_seq 1 11 >orig-A &&
1435 git add orig-A &&
1436 git commit -m orig-A &&
1438 git checkout B &&
1439 git mv orig orig-B &&
1440 test_seq 0 10 >orig-B &&
1441 git add orig-B &&
1442 git commit -m orig-B
1447 test_expect_success 'rename/rename(1to2) with a binary file' '
1448 test_setup_rename_rename_1_to_2_binary &&
1450 cd rename_rename_1_to_2_binary &&
1452 git checkout A^0 &&
1454 test_must_fail git merge -s recursive B^0 &&
1456 # Make sure the index has the right number of entries
1457 git ls-files -s >actual &&
1458 test_line_count = 4 actual &&
1460 git rev-parse A:orig-A B:orig-B >expect &&
1461 git hash-object orig-A orig-B >actual &&
1462 test_cmp expect actual
1466 test_done