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