Merge branch 'jc/calloc-fix'
[git] / t / t6422-merge-rename-corner-cases.sh
1 #!/bin/sh
2
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
5
6 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
7 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
8
9 . ./test-lib.sh
10 . "$TEST_DIRECTORY"/lib-merge.sh
11
12 test_setup_rename_delete_untracked () {
13         test_create_repo rename-delete-untracked &&
14         (
15                 cd rename-delete-untracked &&
16
17                 echo "A pretty inscription" >ring &&
18                 git add ring &&
19                 test_tick &&
20                 git commit -m beginning &&
21
22                 git branch people &&
23                 git checkout -b rename-the-ring &&
24                 git mv ring one-ring-to-rule-them-all &&
25                 test_tick &&
26                 git commit -m fullname &&
27
28                 git checkout people &&
29                 git rm ring &&
30                 echo gollum >owner &&
31                 git add owner &&
32                 test_tick &&
33                 git commit -m track-people-instead-of-objects &&
34                 echo "Myyy PRECIOUSSS" >ring
35         )
36 }
37
38 test_expect_success "Does git preserve Gollum's precious artifact?" '
39         test_setup_rename_delete_untracked &&
40         (
41                 cd rename-delete-untracked &&
42
43                 test_must_fail git merge -s recursive rename-the-ring &&
44
45                 # Make sure git did not delete an untracked file
46                 test_path_is_file ring
47         )
48 '
49
50 # Testcase setup for rename/modify/add-source:
51 #   Commit A: new file: a
52 #   Commit B: modify a slightly
53 #   Commit C: rename a->b, add completely different a
54 #
55 # We should be able to merge B & C cleanly
56
57 test_setup_rename_modify_add_source () {
58         test_create_repo rename-modify-add-source &&
59         (
60                 cd rename-modify-add-source &&
61
62                 printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
63                 git add a &&
64                 git commit -m A &&
65                 git tag A &&
66
67                 git checkout -b B A &&
68                 echo 8 >>a &&
69                 git add a &&
70                 git commit -m B &&
71
72                 git checkout -b C A &&
73                 git mv a b &&
74                 echo something completely different >a &&
75                 git add a &&
76                 git commit -m C
77         )
78 }
79
80 test_expect_failure 'rename/modify/add-source conflict resolvable' '
81         test_setup_rename_modify_add_source &&
82         (
83                 cd rename-modify-add-source &&
84
85                 git checkout B^0 &&
86
87                 git merge -s recursive C^0 &&
88
89                 git rev-parse >expect \
90                         B:a   C:a     &&
91                 git rev-parse >actual \
92                         b     c       &&
93                 test_cmp expect actual
94         )
95 '
96
97 test_setup_break_detection_1 () {
98         test_create_repo break-detection-1 &&
99         (
100                 cd break-detection-1 &&
101
102                 printf "1\n2\n3\n4\n5\n" >a &&
103                 echo foo >b &&
104                 git add a b &&
105                 git commit -m A &&
106                 git tag A &&
107
108                 git checkout -b B A &&
109                 git mv a c &&
110                 echo "Completely different content" >a &&
111                 git add a &&
112                 git commit -m B &&
113
114                 git checkout -b C A &&
115                 echo 6 >>a &&
116                 git add a &&
117                 git commit -m C
118         )
119 }
120
121 test_expect_failure 'conflict caused if rename not detected' '
122         test_setup_break_detection_1 &&
123         (
124                 cd break-detection-1 &&
125
126                 git checkout -q C^0 &&
127                 git merge -s recursive B^0 &&
128
129                 git ls-files -s >out &&
130                 test_line_count = 3 out &&
131                 git ls-files -u >out &&
132                 test_line_count = 0 out &&
133                 git ls-files -o >out &&
134                 test_line_count = 1 out &&
135
136                 test_line_count = 6 c &&
137                 git rev-parse >expect \
138                         B:a   A:b     &&
139                 git rev-parse >actual \
140                         :0:a  :0:b    &&
141                 test_cmp expect actual
142         )
143 '
144
145 test_setup_break_detection_2 () {
146         test_create_repo break-detection-2 &&
147         (
148                 cd break-detection-2 &&
149
150                 printf "1\n2\n3\n4\n5\n" >a &&
151                 echo foo >b &&
152                 git add a b &&
153                 git commit -m A &&
154                 git tag A &&
155
156                 git checkout -b D A &&
157                 echo 7 >>a &&
158                 git add a &&
159                 git mv a c &&
160                 echo "Completely different content" >a &&
161                 git add a &&
162                 git commit -m D &&
163
164                 git checkout -b E A &&
165                 git rm a &&
166                 echo "Completely different content" >>a &&
167                 git add a &&
168                 git commit -m E
169         )
170 }
171
172 test_expect_failure 'missed conflict if rename not detected' '
173         test_setup_break_detection_2 &&
174         (
175                 cd break-detection-2 &&
176
177                 git checkout -q E^0 &&
178                 test_must_fail git merge -s recursive D^0
179         )
180 '
181
182 # Tests for undetected rename/add-source causing a file to erroneously be
183 # deleted (and for mishandled rename/rename(1to1) causing the same issue).
184 #
185 # This test uses a rename/rename(1to1)+add-source conflict (1to1 means the
186 # same file is renamed on both sides to the same thing; it should trigger
187 # the 1to2 logic, which it would do if the add-source didn't cause issues
188 # for git's rename detection):
189 #   Commit A: new file: a
190 #   Commit B: rename a->b
191 #   Commit C: rename a->b, add unrelated a
192
193 test_setup_break_detection_3 () {
194         test_create_repo break-detection-3 &&
195         (
196                 cd break-detection-3 &&
197
198                 printf "1\n2\n3\n4\n5\n" >a &&
199                 git add a &&
200                 git commit -m A &&
201                 git tag A &&
202
203                 git checkout -b B A &&
204                 git mv a b &&
205                 git commit -m B &&
206
207                 git checkout -b C A &&
208                 git mv a b &&
209                 echo foobar >a &&
210                 git add a &&
211                 git commit -m C
212         )
213 }
214
215 test_expect_failure 'detect rename/add-source and preserve all data' '
216         test_setup_break_detection_3 &&
217         (
218                 cd break-detection-3 &&
219
220                 git checkout B^0 &&
221
222                 git merge -s recursive C^0 &&
223
224                 git ls-files -s >out &&
225                 test_line_count = 2 out &&
226                 git ls-files -u >out &&
227                 test_line_count = 2 out &&
228                 git ls-files -o >out &&
229                 test_line_count = 1 out &&
230
231                 test_path_is_file a &&
232                 test_path_is_file b &&
233
234                 git rev-parse >expect \
235                         A:a   C:a     &&
236                 git rev-parse >actual \
237                         :0:b  :0:a    &&
238                 test_cmp expect actual
239         )
240 '
241
242 test_expect_failure 'detect rename/add-source and preserve all data, merge other way' '
243         test_setup_break_detection_3 &&
244         (
245                 cd break-detection-3 &&
246
247                 git checkout C^0 &&
248
249                 git merge -s recursive B^0 &&
250
251                 git ls-files -s >out &&
252                 test_line_count = 2 out &&
253                 git ls-files -u >out &&
254                 test_line_count = 2 out &&
255                 git ls-files -o >out &&
256                 test_line_count = 1 out &&
257
258                 test_path_is_file a &&
259                 test_path_is_file b &&
260
261                 git rev-parse >expect \
262                         A:a   C:a     &&
263                 git rev-parse >actual \
264                         :0:b  :0:a    &&
265                 test_cmp expect actual
266         )
267 '
268
269 test_setup_rename_directory () {
270         test_create_repo rename-directory-$1 &&
271         (
272                 cd rename-directory-$1 &&
273
274                 printf "1\n2\n3\n4\n5\n6\n" >file &&
275                 git add file &&
276                 test_tick &&
277                 git commit -m base &&
278                 git tag base &&
279
280                 git checkout -b right &&
281                 echo 7 >>file &&
282                 mkdir newfile &&
283                 echo junk >newfile/realfile &&
284                 git add file newfile/realfile &&
285                 test_tick &&
286                 git commit -m right &&
287
288                 git checkout -b left-conflict base &&
289                 echo 8 >>file &&
290                 git add file &&
291                 git mv file newfile &&
292                 test_tick &&
293                 git commit -m left &&
294
295                 git checkout -b left-clean base &&
296                 echo 0 >newfile &&
297                 cat file >>newfile &&
298                 git add newfile &&
299                 git rm file &&
300                 test_tick &&
301                 git commit -m left
302         )
303 }
304
305 test_expect_success 'rename/directory conflict + clean content merge' '
306         test_setup_rename_directory 1a &&
307         (
308                 cd rename-directory-1a &&
309
310                 git checkout left-clean^0 &&
311
312                 test_must_fail git merge -s recursive right^0 &&
313
314                 git ls-files -s >out &&
315                 test_line_count = 2 out &&
316                 git ls-files -u >out &&
317                 test_line_count = 1 out &&
318                 git ls-files -o >out &&
319                 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
320                 then
321                         test_line_count = 1 out
322                 else
323                         test_line_count = 2 out
324                 fi &&
325
326                 echo 0 >expect &&
327                 git cat-file -p base:file >>expect &&
328                 echo 7 >>expect &&
329                 test_cmp expect newfile~HEAD &&
330
331                 test_path_is_file newfile/realfile &&
332                 test_path_is_file newfile~HEAD
333         )
334 '
335
336 test_expect_success 'rename/directory conflict + content merge conflict' '
337         test_setup_rename_directory 1b &&
338         (
339                 cd rename-directory-1b &&
340
341                 git reset --hard &&
342                 git clean -fdqx &&
343
344                 git checkout left-conflict^0 &&
345
346                 test_must_fail git merge -s recursive right^0 &&
347
348                 git ls-files -s >out &&
349                 test_line_count = 4 out &&
350                 git ls-files -u >out &&
351                 test_line_count = 3 out &&
352                 git ls-files -o >out &&
353                 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
354                 then
355                         test_line_count = 1 out
356                 else
357                         test_line_count = 2 out
358                 fi &&
359
360                 git cat-file -p left-conflict:newfile >left &&
361                 git cat-file -p base:file    >base &&
362                 git cat-file -p right:file   >right &&
363                 test_must_fail git merge-file \
364                         -L "HEAD:newfile" \
365                         -L "" \
366                         -L "right^0:file" \
367                         left base right &&
368                 test_cmp left newfile~HEAD &&
369
370                 git rev-parse >expect   \
371                         base:file       left-conflict:newfile right:file &&
372                 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
373                 then
374                         git rev-parse >actual \
375                                 :1:newfile~HEAD :2:newfile~HEAD :3:newfile~HEAD
376                 else
377                         git rev-parse >actual \
378                                 :1:newfile      :2:newfile      :3:newfile
379                 fi &&
380                 test_cmp expect actual &&
381
382                 test_path_is_file newfile/realfile &&
383                 test_path_is_file newfile~HEAD
384         )
385 '
386
387 test_setup_rename_directory_2 () {
388         test_create_repo rename-directory-2 &&
389         (
390                 cd rename-directory-2 &&
391
392                 mkdir sub &&
393                 printf "1\n2\n3\n4\n5\n6\n" >sub/file &&
394                 git add sub/file &&
395                 test_tick &&
396                 git commit -m base &&
397                 git tag base &&
398
399                 git checkout -b right &&
400                 echo 7 >>sub/file &&
401                 git add sub/file &&
402                 test_tick &&
403                 git commit -m right &&
404
405                 git checkout -b left base &&
406                 echo 0 >newfile &&
407                 cat sub/file >>newfile &&
408                 git rm sub/file &&
409                 mv newfile sub &&
410                 git add sub &&
411                 test_tick &&
412                 git commit -m left
413         )
414 }
415
416 test_expect_success 'disappearing dir in rename/directory conflict handled' '
417         test_setup_rename_directory_2 &&
418         (
419                 cd rename-directory-2 &&
420
421                 git checkout left^0 &&
422
423                 git merge -s recursive right^0 &&
424
425                 git ls-files -s >out &&
426                 test_line_count = 1 out &&
427                 git ls-files -u >out &&
428                 test_line_count = 0 out &&
429                 git ls-files -o >out &&
430                 test_line_count = 1 out &&
431
432                 echo 0 >expect &&
433                 git cat-file -p base:sub/file >>expect &&
434                 echo 7 >>expect &&
435                 test_cmp expect sub &&
436
437                 test_path_is_file sub
438         )
439 '
440
441 # Test for basic rename/add-dest conflict, with rename needing content merge:
442 #   Commit O: a
443 #   Commit A: rename a->b, modifying b too
444 #   Commit B: modify a, add different b
445
446 test_setup_rename_with_content_merge_and_add () {
447         test_create_repo rename-with-content-merge-and-add-$1 &&
448         (
449                 cd rename-with-content-merge-and-add-$1 &&
450
451                 test_seq 1 5 >a &&
452                 git add a &&
453                 git commit -m O &&
454                 git tag O &&
455
456                 git checkout -b A O &&
457                 git mv a b &&
458                 test_seq 0 5 >b &&
459                 git add b &&
460                 git commit -m A &&
461
462                 git checkout -b B O &&
463                 echo 6 >>a &&
464                 echo hello world >b &&
465                 git add a b &&
466                 git commit -m B
467         )
468 }
469
470 test_expect_success 'handle rename-with-content-merge vs. add' '
471         test_setup_rename_with_content_merge_and_add AB &&
472         (
473                 cd rename-with-content-merge-and-add-AB &&
474
475                 git checkout A^0 &&
476
477                 test_must_fail git merge -s recursive B^0 >out &&
478                 test_i18ngrep "CONFLICT (.*/add)" out &&
479
480                 git ls-files -s >out &&
481                 test_line_count = 2 out &&
482                 git ls-files -u >out &&
483                 test_line_count = 2 out &&
484                 # Also, make sure both unmerged entries are for "b"
485                 git ls-files -u b >out &&
486                 test_line_count = 2 out &&
487                 git ls-files -o >out &&
488                 test_line_count = 1 out &&
489
490                 test_path_is_missing a &&
491                 test_path_is_file b &&
492
493                 test_seq 0 6 >tmp &&
494                 git hash-object tmp >expect &&
495                 git rev-parse B:b >>expect &&
496                 git rev-parse >actual  \
497                         :2:b    :3:b   &&
498                 test_cmp expect actual &&
499
500                 # Test that the two-way merge in b is as expected
501                 git cat-file -p :2:b >>ours &&
502                 git cat-file -p :3:b >>theirs &&
503                 >empty &&
504                 test_must_fail git merge-file \
505                         -L "HEAD" \
506                         -L "" \
507                         -L "B^0" \
508                         ours empty theirs &&
509                 test_cmp ours b
510         )
511 '
512
513 test_expect_success 'handle rename-with-content-merge vs. add, merge other way' '
514         test_setup_rename_with_content_merge_and_add BA &&
515         (
516                 cd rename-with-content-merge-and-add-BA &&
517
518                 git reset --hard &&
519                 git clean -fdx &&
520
521                 git checkout B^0 &&
522
523                 test_must_fail git merge -s recursive A^0 >out &&
524                 test_i18ngrep "CONFLICT (.*/add)" out &&
525
526                 git ls-files -s >out &&
527                 test_line_count = 2 out &&
528                 git ls-files -u >out &&
529                 test_line_count = 2 out &&
530                 # Also, make sure both unmerged entries are for "b"
531                 git ls-files -u b >out &&
532                 test_line_count = 2 out &&
533                 git ls-files -o >out &&
534                 test_line_count = 1 out &&
535
536                 test_path_is_missing a &&
537                 test_path_is_file b &&
538
539                 test_seq 0 6 >tmp &&
540                 git rev-parse B:b >expect &&
541                 git hash-object tmp >>expect &&
542                 git rev-parse >actual  \
543                         :2:b    :3:b   &&
544                 test_cmp expect actual &&
545
546                 # Test that the two-way merge in b is as expected
547                 git cat-file -p :2:b >>ours &&
548                 git cat-file -p :3:b >>theirs &&
549                 >empty &&
550                 test_must_fail git merge-file \
551                         -L "HEAD" \
552                         -L "" \
553                         -L "A^0" \
554                         ours empty theirs &&
555                 test_cmp ours b
556         )
557 '
558
559 # Test for all kinds of things that can go wrong with rename/rename (2to1):
560 #   Commit A: new files: a & b
561 #   Commit B: rename a->c, modify b
562 #   Commit C: rename b->c, modify a
563 #
564 # Merging of B & C should NOT be clean.  Questions:
565 #   * Both a & b should be removed by the merge; are they?
566 #   * The two c's should contain modifications to a & b; do they?
567 #   * The index should contain two files, both for c; does it?
568 #   * The working copy should have two files, both of form c~<unique>; does it?
569 #   * Nothing else should be present.  Is anything?
570
571 test_setup_rename_rename_2to1 () {
572         test_create_repo rename-rename-2to1 &&
573         (
574                 cd rename-rename-2to1 &&
575
576                 printf "1\n2\n3\n4\n5\n" >a &&
577                 printf "5\n4\n3\n2\n1\n" >b &&
578                 git add a b &&
579                 git commit -m A &&
580                 git tag A &&
581
582                 git checkout -b B A &&
583                 git mv a c &&
584                 echo 0 >>b &&
585                 git add b &&
586                 git commit -m B &&
587
588                 git checkout -b C A &&
589                 git mv b c &&
590                 echo 6 >>a &&
591                 git add a &&
592                 git commit -m C
593         )
594 }
595
596 test_expect_success 'handle rename/rename (2to1) conflict correctly' '
597         test_setup_rename_rename_2to1 &&
598         (
599                 cd rename-rename-2to1 &&
600
601                 git checkout B^0 &&
602
603                 test_must_fail git merge -s recursive C^0 >out &&
604                 test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
605
606                 git ls-files -s >out &&
607                 test_line_count = 2 out &&
608                 git ls-files -u >out &&
609                 test_line_count = 2 out &&
610                 git ls-files -u c >out &&
611                 test_line_count = 2 out &&
612                 git ls-files -o >out &&
613                 test_line_count = 1 out &&
614
615                 test_path_is_missing a &&
616                 test_path_is_missing b &&
617
618                 git rev-parse >expect  \
619                         C:a     B:b    &&
620                 git rev-parse >actual  \
621                         :2:c    :3:c   &&
622                 test_cmp expect actual &&
623
624                 # Test that the two-way merge in new_a is as expected
625                 git cat-file -p :2:c >>ours &&
626                 git cat-file -p :3:c >>theirs &&
627                 >empty &&
628                 test_must_fail git merge-file \
629                         -L "HEAD" \
630                         -L "" \
631                         -L "C^0" \
632                         ours empty theirs &&
633                 git hash-object c >actual &&
634                 git hash-object ours >expect &&
635                 test_cmp expect actual
636         )
637 '
638
639 # Testcase setup for simple rename/rename (1to2) conflict:
640 #   Commit A: new file: a
641 #   Commit B: rename a->b
642 #   Commit C: rename a->c
643 test_setup_rename_rename_1to2 () {
644         test_create_repo rename-rename-1to2 &&
645         (
646                 cd rename-rename-1to2 &&
647
648                 echo stuff >a &&
649                 git add a &&
650                 test_tick &&
651                 git commit -m A &&
652                 git tag A &&
653
654                 git checkout -b B A &&
655                 git mv a b &&
656                 test_tick &&
657                 git commit -m B &&
658
659                 git checkout -b C A &&
660                 git mv a c &&
661                 test_tick &&
662                 git commit -m C
663         )
664 }
665
666 test_expect_success 'merge has correct working tree contents' '
667         test_setup_rename_rename_1to2 &&
668         (
669                 cd rename-rename-1to2 &&
670
671                 git checkout C^0 &&
672
673                 test_must_fail git merge -s recursive B^0 &&
674
675                 git ls-files -s >out &&
676                 test_line_count = 3 out &&
677                 git ls-files -u >out &&
678                 test_line_count = 3 out &&
679                 git ls-files -o >out &&
680                 test_line_count = 1 out &&
681
682                 test_path_is_missing a &&
683                 git rev-parse >expect   \
684                         A:a   A:a   A:a \
685                         A:a   A:a       &&
686                 git rev-parse >actual    \
687                         :1:a  :3:b  :2:c &&
688                 git hash-object >>actual \
689                         b     c          &&
690                 test_cmp expect actual
691         )
692 '
693
694 # Testcase setup for rename/rename(1to2)/add-source conflict:
695 #   Commit A: new file: a
696 #   Commit B: rename a->b
697 #   Commit C: rename a->c, add completely different a
698 #
699 # Merging of B & C should NOT be clean; there's a rename/rename conflict
700
701 test_setup_rename_rename_1to2_add_source_1 () {
702         test_create_repo rename-rename-1to2-add-source-1 &&
703         (
704                 cd rename-rename-1to2-add-source-1 &&
705
706                 printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
707                 git add a &&
708                 git commit -m A &&
709                 git tag A &&
710
711                 git checkout -b B A &&
712                 git mv a b &&
713                 git commit -m B &&
714
715                 git checkout -b C A &&
716                 git mv a c &&
717                 echo something completely different >a &&
718                 git add a &&
719                 git commit -m C
720         )
721 }
722
723 test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge' '
724         test_setup_rename_rename_1to2_add_source_1 &&
725         (
726                 cd rename-rename-1to2-add-source-1 &&
727
728                 git checkout B^0 &&
729
730                 test_must_fail git merge -s recursive C^0 &&
731
732                 git ls-files -s >out &&
733                 test_line_count = 4 out &&
734                 git ls-files -o >out &&
735                 test_line_count = 1 out &&
736
737                 git rev-parse >expect         \
738                         C:a   A:a   B:b   C:C &&
739                 git rev-parse >actual          \
740                         :3:a  :1:a  :2:b  :3:c &&
741                 test_cmp expect actual &&
742
743                 test_path_is_file a &&
744                 test_path_is_file b &&
745                 test_path_is_file c
746         )
747 '
748
749 test_setup_rename_rename_1to2_add_source_2 () {
750         test_create_repo rename-rename-1to2-add-source-2 &&
751         (
752                 cd rename-rename-1to2-add-source-2 &&
753
754                 >a &&
755                 git add a &&
756                 test_tick &&
757                 git commit -m base &&
758                 git tag A &&
759
760                 git checkout -b B A &&
761                 git mv a b &&
762                 test_tick &&
763                 git commit -m one &&
764
765                 git checkout -b C A &&
766                 git mv a b &&
767                 echo important-info >a &&
768                 git add a &&
769                 test_tick &&
770                 git commit -m two
771         )
772 }
773
774 test_expect_failure 'rename/rename/add-source still tracks new a file' '
775         test_setup_rename_rename_1to2_add_source_2 &&
776         (
777                 cd rename-rename-1to2-add-source-2 &&
778
779                 git checkout C^0 &&
780                 git merge -s recursive B^0 &&
781
782                 git ls-files -s >out &&
783                 test_line_count = 2 out &&
784                 git ls-files -o >out &&
785                 test_line_count = 1 out &&
786
787                 git rev-parse >expect \
788                         C:a   A:a     &&
789                 git rev-parse >actual \
790                         :0:a  :0:b    &&
791                 test_cmp expect actual
792         )
793 '
794
795 test_setup_rename_rename_1to2_add_dest () {
796         test_create_repo rename-rename-1to2-add-dest &&
797         (
798                 cd rename-rename-1to2-add-dest &&
799
800                 echo stuff >a &&
801                 git add a &&
802                 test_tick &&
803                 git commit -m base &&
804                 git tag A &&
805
806                 git checkout -b B A &&
807                 git mv a b &&
808                 echo precious-data >c &&
809                 git add c &&
810                 test_tick &&
811                 git commit -m one &&
812
813                 git checkout -b C A &&
814                 git mv a c &&
815                 echo important-info >b &&
816                 git add b &&
817                 test_tick &&
818                 git commit -m two
819         )
820 }
821
822 test_expect_success 'rename/rename/add-dest merge still knows about conflicting file versions' '
823         test_setup_rename_rename_1to2_add_dest &&
824         (
825                 cd rename-rename-1to2-add-dest &&
826
827                 git checkout C^0 &&
828                 test_must_fail git merge -s recursive B^0 &&
829
830                 git ls-files -s >out &&
831                 test_line_count = 5 out &&
832                 git ls-files -u b >out &&
833                 test_line_count = 2 out &&
834                 git ls-files -u c >out &&
835                 test_line_count = 2 out &&
836                 git ls-files -o >out &&
837                 test_line_count = 1 out &&
838
839                 git rev-parse >expect               \
840                         A:a   C:b   B:b   C:c   B:c &&
841                 git rev-parse >actual                \
842                         :1:a  :2:b  :3:b  :2:c  :3:c &&
843                 test_cmp expect actual &&
844
845                 # Record some contents for re-doing merges
846                 git cat-file -p A:a >stuff &&
847                 git cat-file -p C:b >important_info &&
848                 git cat-file -p B:c >precious_data &&
849                 >empty &&
850
851                 # Test the merge in b
852                 test_must_fail git merge-file \
853                         -L "HEAD" \
854                         -L "" \
855                         -L "B^0" \
856                         important_info empty stuff &&
857                 test_cmp important_info b &&
858
859                 # Test the merge in c
860                 test_must_fail git merge-file \
861                         -L "HEAD" \
862                         -L "" \
863                         -L "B^0" \
864                         stuff empty precious_data &&
865                 test_cmp stuff c
866         )
867 '
868
869 # Testcase rad, rename/add/delete
870 #   Commit O: foo
871 #   Commit A: rm foo, add different bar
872 #   Commit B: rename foo->bar
873 #   Expected: CONFLICT (rename/add/delete), two-way merged bar
874
875 test_setup_rad () {
876         test_create_repo rad &&
877         (
878                 cd rad &&
879                 echo "original file" >foo &&
880                 git add foo &&
881                 git commit -m "original" &&
882
883                 git branch O &&
884                 git branch A &&
885                 git branch B &&
886
887                 git checkout A &&
888                 git rm foo &&
889                 echo "different file" >bar &&
890                 git add bar &&
891                 git commit -m "Remove foo, add bar" &&
892
893                 git checkout B &&
894                 git mv foo bar &&
895                 git commit -m "rename foo to bar"
896         )
897 }
898
899 test_expect_merge_algorithm failure success 'rad-check: rename/add/delete conflict' '
900         test_setup_rad &&
901         (
902                 cd rad &&
903
904                 git checkout B^0 &&
905                 test_must_fail git merge -s recursive A^0 >out 2>err &&
906
907                 # Instead of requiring the output to contain one combined line
908                 #   CONFLICT (rename/add/delete)
909                 # or perhaps two lines:
910                 #   CONFLICT (rename/add): new file collides with rename target
911                 #   CONFLICT (rename/delete): rename source removed on other side
912                 # and instead of requiring "rename/add" instead of "add/add",
913                 # be flexible in the type of console output message(s) reported
914                 # for this particular case; we will be more stringent about the
915                 # contents of the index and working directory.
916                 test_i18ngrep "CONFLICT (.*/add)" out &&
917                 test_i18ngrep "CONFLICT (rename.*/delete)" out &&
918                 test_must_be_empty err &&
919
920                 git ls-files -s >file_count &&
921                 test_line_count = 2 file_count &&
922                 git ls-files -u >file_count &&
923                 test_line_count = 2 file_count &&
924                 git ls-files -o >file_count &&
925                 test_line_count = 3 file_count &&
926
927                 git rev-parse >actual \
928                         :2:bar :3:bar &&
929                 git rev-parse >expect \
930                         B:bar  A:bar  &&
931
932                 test_path_is_missing foo &&
933                 # bar should have two-way merged contents of the different
934                 # versions of bar; check that content from both sides is
935                 # present.
936                 grep original bar &&
937                 grep different bar
938         )
939 '
940
941 # Testcase rrdd, rename/rename(2to1)/delete/delete
942 #   Commit O: foo, bar
943 #   Commit A: rename foo->baz, rm bar
944 #   Commit B: rename bar->baz, rm foo
945 #   Expected: CONFLICT (rename/rename/delete/delete), two-way merged baz
946
947 test_setup_rrdd () {
948         test_create_repo rrdd &&
949         (
950                 cd rrdd &&
951                 echo foo >foo &&
952                 echo bar >bar &&
953                 git add foo bar &&
954                 git commit -m O &&
955
956                 git branch O &&
957                 git branch A &&
958                 git branch B &&
959
960                 git checkout A &&
961                 git mv foo baz &&
962                 git rm bar &&
963                 git commit -m "Rename foo, remove bar" &&
964
965                 git checkout B &&
966                 git mv bar baz &&
967                 git rm foo &&
968                 git commit -m "Rename bar, remove foo"
969         )
970 }
971
972 test_expect_merge_algorithm failure success 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '
973         test_setup_rrdd &&
974         (
975                 cd rrdd &&
976
977                 git checkout A^0 &&
978                 test_must_fail git merge -s recursive B^0 >out 2>err &&
979
980                 # Instead of requiring the output to contain one combined line
981                 #   CONFLICT (rename/rename/delete/delete)
982                 # or perhaps two lines:
983                 #   CONFLICT (rename/rename): ...
984                 #   CONFLICT (rename/delete): info about pair 1
985                 #   CONFLICT (rename/delete): info about pair 2
986                 # and instead of requiring "rename/rename" instead of "add/add",
987                 # be flexible in the type of console output message(s) reported
988                 # for this particular case; we will be more stringent about the
989                 # contents of the index and working directory.
990                 test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
991                 test_i18ngrep "CONFLICT (rename.*delete)" out &&
992                 test_must_be_empty err &&
993
994                 git ls-files -s >file_count &&
995                 test_line_count = 2 file_count &&
996                 git ls-files -u >file_count &&
997                 test_line_count = 2 file_count &&
998                 git ls-files -o >file_count &&
999                 test_line_count = 3 file_count &&
1000
1001                 git rev-parse >actual \
1002                         :2:baz :3:baz &&
1003                 git rev-parse >expect \
1004                         O:foo  O:bar  &&
1005
1006                 test_path_is_missing foo &&
1007                 test_path_is_missing bar &&
1008                 # baz should have two-way merged contents of the original
1009                 # contents of foo and bar; check that content from both sides
1010                 # is present.
1011                 grep foo baz &&
1012                 grep bar baz
1013         )
1014 '
1015
1016 # Testcase mod6, chains of rename/rename(1to2) and rename/rename(2to1)
1017 #   Commit O: one,      three,       five
1018 #   Commit A: one->two, three->four, five->six
1019 #   Commit B: one->six, three->two,  five->four
1020 #   Expected: six CONFLICT(rename/rename) messages, each path in two of the
1021 #             multi-way merged contents found in two, four, six
1022
1023 test_setup_mod6 () {
1024         test_create_repo mod6 &&
1025         (
1026                 cd mod6 &&
1027                 test_seq 11 19 >one &&
1028                 test_seq 31 39 >three &&
1029                 test_seq 51 59 >five &&
1030                 git add . &&
1031                 test_tick &&
1032                 git commit -m "O" &&
1033
1034                 git branch O &&
1035                 git branch A &&
1036                 git branch B &&
1037
1038                 git checkout A &&
1039                 test_seq 10 19 >one &&
1040                 echo 40        >>three &&
1041                 git add one three &&
1042                 git mv  one   two  &&
1043                 git mv  three four &&
1044                 git mv  five  six  &&
1045                 test_tick &&
1046                 git commit -m "A" &&
1047
1048                 git checkout B &&
1049                 echo 20    >>one       &&
1050                 echo forty >>three     &&
1051                 echo 60    >>five      &&
1052                 git add one three five &&
1053                 git mv  one   six  &&
1054                 git mv  three two  &&
1055                 git mv  five  four &&
1056                 test_tick &&
1057                 git commit -m "B"
1058         )
1059 }
1060
1061 test_expect_merge_algorithm failure success 'mod6-check: chains of rename/rename(1to2) and rename/rename(2to1)' '
1062         test_setup_mod6 &&
1063         (
1064                 cd mod6 &&
1065
1066                 git checkout A^0 &&
1067
1068                 test_must_fail git merge -s recursive B^0 >out 2>err &&
1069
1070                 test_i18ngrep "CONFLICT (rename/rename)" out &&
1071                 test_must_be_empty err &&
1072
1073                 git ls-files -s >file_count &&
1074                 test_line_count = 9 file_count &&
1075                 git ls-files -u >file_count &&
1076                 test_line_count = 9 file_count &&
1077                 git ls-files -o >file_count &&
1078                 test_line_count = 3 file_count &&
1079
1080                 test_seq 10 20 >merged-one &&
1081                 test_seq 51 60 >merged-five &&
1082                 # Determine what the merge of three would give us.
1083                 test_seq 31 39 >three-base &&
1084                 test_seq 31 40 >three-side-A &&
1085                 test_seq 31 39 >three-side-B &&
1086                 echo forty >>three-side-B &&
1087                 test_must_fail git merge-file \
1088                         -L "HEAD:four" \
1089                         -L "" \
1090                         -L "B^0:two" \
1091                         three-side-A three-base three-side-B &&
1092                 sed -e "s/^\([<=>]\)/\1\1/" three-side-A >merged-three &&
1093
1094                 # Verify the index is as expected
1095                 git rev-parse >actual         \
1096                         :2:two       :3:two   \
1097                         :2:four      :3:four  \
1098                         :2:six       :3:six   &&
1099                 git hash-object >expect           \
1100                         merged-one   merged-three \
1101                         merged-three merged-five  \
1102                         merged-five  merged-one   &&
1103                 test_cmp expect actual &&
1104
1105                 git cat-file -p :2:two >expect &&
1106                 git cat-file -p :3:two >other &&
1107                 >empty &&
1108                 test_must_fail git merge-file    \
1109                         -L "HEAD"  -L ""  -L "B^0" \
1110                         expect     empty  other &&
1111                 test_cmp expect two &&
1112
1113                 git cat-file -p :2:four >expect &&
1114                 git cat-file -p :3:four >other &&
1115                 test_must_fail git merge-file    \
1116                         -L "HEAD"  -L ""  -L "B^0" \
1117                         expect     empty  other &&
1118                 test_cmp expect four &&
1119
1120                 git cat-file -p :2:six >expect &&
1121                 git cat-file -p :3:six >other &&
1122                 test_must_fail git merge-file    \
1123                         -L "HEAD"  -L ""  -L "B^0" \
1124                         expect     empty  other &&
1125                 test_cmp expect six
1126         )
1127 '
1128
1129 test_conflicts_with_adds_and_renames() {
1130         sideL=$1
1131         sideR=$2
1132
1133         # Setup:
1134         #          L
1135         #         / \
1136         #     main   ?
1137         #         \ /
1138         #          R
1139         #
1140         # Where:
1141         #   Both L and R have files named 'three' which collide.  Each of
1142         #   the colliding files could have been involved in a rename, in
1143         #   which case there was a file named 'one' or 'two' that was
1144         #   modified on the opposite side of history and renamed into the
1145         #   collision on this side of history.
1146         #
1147         # Questions:
1148         #   1) The index should contain both a stage 2 and stage 3 entry
1149         #      for the colliding file.  Does it?
1150         #   2) When renames are involved, the content merges are clean, so
1151         #      the index should reflect the content merges, not merely the
1152         #      version of the colliding file from the prior commit.  Does
1153         #      it?
1154         #   3) There should be a file in the worktree named 'three'
1155         #      containing the two-way merged contents of the content-merged
1156         #      versions of 'three' from each of the two colliding
1157         #      files.  Is it present?
1158         #   4) There should not be any three~* files in the working
1159         #      tree
1160         test_setup_collision_conflict () {
1161         #test_expect_success "setup simple $sideL/$sideR conflict" '
1162                 test_create_repo simple_${sideL}_${sideR} &&
1163                 (
1164                         cd simple_${sideL}_${sideR} &&
1165
1166                         # Create some related files now
1167                         for i in $(test_seq 1 10)
1168                         do
1169                                 echo Random base content line $i
1170                         done >file_v1 &&
1171                         cp file_v1 file_v2 &&
1172                         echo modification >>file_v2 &&
1173
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 &&
1178
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 &&
1186
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 &&
1202
1203                         git branch L &&
1204                         git branch R &&
1205
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 &&
1221
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
1237                 )
1238         #'
1239         }
1240
1241         test_expect_success "check simple $sideL/$sideR conflict" '
1242                 test_setup_collision_conflict &&
1243                 (
1244                         cd simple_${sideL}_${sideR} &&
1245
1246                         git checkout L^0 &&
1247
1248                         # Merge must fail; there is a conflict
1249                         test_must_fail git merge -s recursive R^0 &&
1250
1251                         # Make sure the index has the right number of entries
1252                         git ls-files -s >out &&
1253                         test_line_count = 3 out &&
1254                         git ls-files -u >out &&
1255                         test_line_count = 2 out &&
1256                         # Ensure we have the correct number of untracked files
1257                         git ls-files -o >out &&
1258                         test_line_count = 1 out &&
1259
1260                         # Nothing should have touched irrelevant_file
1261                         git rev-parse >actual      \
1262                                 :0:irrelevant_file \
1263                                 :2:three           \
1264                                 :3:three           &&
1265                         git rev-parse >expected        \
1266                                 main:irrelevant_file \
1267                                 file_v2                \
1268                                 file_v4                &&
1269                         test_cmp expected actual &&
1270
1271                         # Make sure we have the correct merged contents for
1272                         # three
1273                         git show file_v1 >expected &&
1274                         cat <<-\EOF >>expected &&
1275                         <<<<<<< HEAD
1276                         modification
1277                         =======
1278                         more stuff
1279                         yet more stuff
1280                         >>>>>>> R^0
1281                         EOF
1282
1283                         test_cmp expected three
1284                 )
1285         '
1286 }
1287
1288 test_conflicts_with_adds_and_renames rename rename
1289 test_conflicts_with_adds_and_renames rename add
1290 test_conflicts_with_adds_and_renames add    rename
1291 test_conflicts_with_adds_and_renames add    add
1292
1293 # Setup:
1294 #          L
1295 #         / \
1296 #     main   ?
1297 #         \ /
1298 #          R
1299 #
1300 # Where:
1301 #   main has two files, named 'one' and 'two'.
1302 #   branches L and R both modify 'one', in conflicting ways.
1303 #   branches L and R both modify 'two', in conflicting ways.
1304 #   branch L also renames 'one' to 'three'.
1305 #   branch R also renames 'two' to 'three'.
1306 #
1307 #   So, we have four different conflicting files that all end up at path
1308 #   'three'.
1309 test_setup_nested_conflicts_from_rename_rename () {
1310         test_create_repo nested_conflicts_from_rename_rename &&
1311         (
1312                 cd nested_conflicts_from_rename_rename &&
1313
1314                 # Create some related files now
1315                 for i in $(test_seq 1 10)
1316                 do
1317                         echo Random base content line $i
1318                 done >file_v1 &&
1319
1320                 cp file_v1 file_v2 &&
1321                 cp file_v1 file_v3 &&
1322                 cp file_v1 file_v4 &&
1323                 cp file_v1 file_v5 &&
1324                 cp file_v1 file_v6 &&
1325
1326                 echo one  >>file_v1 &&
1327                 echo uno  >>file_v2 &&
1328                 echo eins >>file_v3 &&
1329
1330                 echo two  >>file_v4 &&
1331                 echo dos  >>file_v5 &&
1332                 echo zwei >>file_v6 &&
1333
1334                 # Setup original commit (or merge-base), consisting of
1335                 # files named "one" and "two".
1336                 mv file_v1 one &&
1337                 mv file_v4 two &&
1338                 git add one two &&
1339                 test_tick && git commit -m english &&
1340
1341                 git branch L &&
1342                 git branch R &&
1343
1344                 # Handle the left side
1345                 git checkout L &&
1346                 git rm one two &&
1347                 mv -f file_v2 three &&
1348                 mv -f file_v5 two &&
1349                 git add two three &&
1350                 test_tick && git commit -m spanish &&
1351
1352                 # Handle the right side
1353                 git checkout R &&
1354                 git rm one two &&
1355                 mv -f file_v3 one &&
1356                 mv -f file_v6 three &&
1357                 git add one three &&
1358                 test_tick && git commit -m german
1359         )
1360 }
1361
1362 test_expect_success 'check nested conflicts from rename/rename(2to1)' '
1363         test_setup_nested_conflicts_from_rename_rename &&
1364         (
1365                 cd nested_conflicts_from_rename_rename &&
1366
1367                 git checkout L^0 &&
1368
1369                 # Merge must fail; there is a conflict
1370                 test_must_fail git merge -s recursive R^0 &&
1371
1372                 # Make sure the index has the right number of entries
1373                 git ls-files -s >out &&
1374                 test_line_count = 2 out &&
1375                 git ls-files -u >out &&
1376                 test_line_count = 2 out &&
1377                 # Ensure we have the correct number of untracked files
1378                 git ls-files -o >out &&
1379                 test_line_count = 1 out &&
1380
1381                 # Compare :2:three to expected values
1382                 git cat-file -p main:one >base &&
1383                 git cat-file -p L:three >ours &&
1384                 git cat-file -p R:one >theirs &&
1385                 test_must_fail git merge-file    \
1386                         -L "HEAD:three"  -L ""  -L "R^0:one" \
1387                         ours             base   theirs &&
1388                 sed -e "s/^\([<=>]\)/\1\1/" ours >L-three &&
1389                 git cat-file -p :2:three >expect &&
1390                 test_cmp expect L-three &&
1391
1392                 # Compare :2:three to expected values
1393                 git cat-file -p main:two >base &&
1394                 git cat-file -p L:two >ours &&
1395                 git cat-file -p R:three >theirs &&
1396                 test_must_fail git merge-file    \
1397                         -L "HEAD:two"  -L ""  -L "R^0:three" \
1398                         ours           base   theirs &&
1399                 sed -e "s/^\([<=>]\)/\1\1/" ours >R-three &&
1400                 git cat-file -p :3:three >expect &&
1401                 test_cmp expect R-three &&
1402
1403                 # Compare three to expected contents
1404                 >empty &&
1405                 test_must_fail git merge-file    \
1406                         -L "HEAD"  -L ""  -L "R^0" \
1407                         L-three    empty  R-three &&
1408                 test_cmp three L-three
1409         )
1410 '
1411
1412 # Testcase rename/rename(1to2) of a binary file
1413 #   Commit O: orig
1414 #   Commit A: orig-A
1415 #   Commit B: orig-B
1416 #   Expected: CONFLICT(rename/rename) message, three unstaged entries in the
1417 #             index, and contents of orig-[AB] at path orig-[AB]
1418 test_setup_rename_rename_1_to_2_binary () {
1419         test_create_repo rename_rename_1_to_2_binary &&
1420         (
1421                 cd rename_rename_1_to_2_binary &&
1422
1423                 echo '* binary' >.gitattributes &&
1424                 git add .gitattributes &&
1425
1426                 test_seq 1 10 >orig &&
1427                 git add orig &&
1428                 git commit -m orig &&
1429
1430                 git branch A &&
1431                 git branch B &&
1432
1433                 git checkout A &&
1434                 git mv orig orig-A &&
1435                 test_seq 1 11 >orig-A &&
1436                 git add orig-A &&
1437                 git commit -m orig-A &&
1438
1439                 git checkout B &&
1440                 git mv orig orig-B &&
1441                 test_seq 0 10 >orig-B &&
1442                 git add orig-B &&
1443                 git commit -m orig-B
1444
1445         )
1446 }
1447
1448 test_expect_success 'rename/rename(1to2) with a binary file' '
1449         test_setup_rename_rename_1_to_2_binary &&
1450         (
1451                 cd rename_rename_1_to_2_binary &&
1452
1453                 git checkout A^0 &&
1454
1455                 test_must_fail git merge -s recursive B^0 &&
1456
1457                 # Make sure the index has the right number of entries
1458                 git ls-files -s >actual &&
1459                 test_line_count = 4 actual &&
1460
1461                 git rev-parse A:orig-A B:orig-B >expect &&
1462                 git hash-object orig-A orig-B >actual &&
1463                 test_cmp expect actual
1464         )
1465 '
1466
1467 test_done