t/: new helper for tests that pass with ort but fail with recursive
[git] / t / t6423-merge-rename-directories.sh
1 #!/bin/sh
2
3 test_description="recursive merge with directory renames"
4 # includes checking of many corner cases, with a similar methodology to:
5 #   t6042: corner cases with renames but not criss-cross merges
6 #   t6036: corner cases with both renames and criss-cross merges
7 #
8 # The setup for all of them, pictorially, is:
9 #
10 #      A
11 #      o
12 #     / \
13 #  O o   ?
14 #     \ /
15 #      o
16 #      B
17 #
18 # To help make it easier to follow the flow of tests, they have been
19 # divided into sections and each test will start with a quick explanation
20 # of what commits O, A, and B contain.
21 #
22 # Notation:
23 #    z/{b,c}   means  files z/b and z/c both exist
24 #    x/d_1     means  file x/d exists with content d1.  (Purpose of the
25 #                     underscore notation is to differentiate different
26 #                     files that might be renamed into each other's paths.)
27
28 . ./test-lib.sh
29 . "$TEST_DIRECTORY"/lib-merge.sh
30
31
32 ###########################################################################
33 # SECTION 1: Basic cases we should be able to handle
34 ###########################################################################
35
36 # Testcase 1a, Basic directory rename.
37 #   Commit O: z/{b,c}
38 #   Commit A: y/{b,c}
39 #   Commit B: z/{b,c,d,e/f}
40 #   Expected: y/{b,c,d,e/f}
41
42 test_setup_1a () {
43         test_create_repo 1a &&
44         (
45                 cd 1a &&
46
47                 mkdir z &&
48                 echo b >z/b &&
49                 echo c >z/c &&
50                 git add z &&
51                 test_tick &&
52                 git commit -m "O" &&
53
54                 git branch O &&
55                 git branch A &&
56                 git branch B &&
57
58                 git checkout A &&
59                 git mv z y &&
60                 test_tick &&
61                 git commit -m "A" &&
62
63                 git checkout B &&
64                 echo d >z/d &&
65                 mkdir z/e &&
66                 echo f >z/e/f &&
67                 git add z/d z/e/f &&
68                 test_tick &&
69                 git commit -m "B"
70         )
71 }
72
73 test_expect_success '1a: Simple directory rename detection' '
74         test_setup_1a &&
75         (
76                 cd 1a &&
77
78                 git checkout A^0 &&
79
80                 git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
81
82                 git ls-files -s >out &&
83                 test_line_count = 4 out &&
84
85                 git rev-parse >actual \
86                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e/f &&
87                 git rev-parse >expect \
88                         O:z/b    O:z/c    B:z/d    B:z/e/f &&
89                 test_cmp expect actual &&
90
91                 git hash-object y/d >actual &&
92                 git rev-parse B:z/d >expect &&
93                 test_cmp expect actual &&
94
95                 test_must_fail git rev-parse HEAD:z/d &&
96                 test_must_fail git rev-parse HEAD:z/e/f &&
97                 test_path_is_missing z/d &&
98                 test_path_is_missing z/e/f
99         )
100 '
101
102 # Testcase 1b, Merge a directory with another
103 #   Commit O: z/{b,c},   y/d
104 #   Commit A: z/{b,c,e}, y/d
105 #   Commit B: y/{b,c,d}
106 #   Expected: y/{b,c,d,e}
107
108 test_setup_1b () {
109         test_create_repo 1b &&
110         (
111                 cd 1b &&
112
113                 mkdir z &&
114                 echo b >z/b &&
115                 echo c >z/c &&
116                 mkdir y &&
117                 echo d >y/d &&
118                 git add z y &&
119                 test_tick &&
120                 git commit -m "O" &&
121
122                 git branch O &&
123                 git branch A &&
124                 git branch B &&
125
126                 git checkout A &&
127                 echo e >z/e &&
128                 git add z/e &&
129                 test_tick &&
130                 git commit -m "A" &&
131
132                 git checkout B &&
133                 git mv z/b y &&
134                 git mv z/c y &&
135                 rmdir z &&
136                 test_tick &&
137                 git commit -m "B"
138         )
139 }
140
141 test_expect_success '1b: Merge a directory with another' '
142         test_setup_1b &&
143         (
144                 cd 1b &&
145
146                 git checkout A^0 &&
147
148                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
149
150                 git ls-files -s >out &&
151                 test_line_count = 4 out &&
152
153                 git rev-parse >actual \
154                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e &&
155                 git rev-parse >expect \
156                         O:z/b    O:z/c    O:y/d    A:z/e &&
157                 test_cmp expect actual &&
158                 test_must_fail git rev-parse HEAD:z/e
159         )
160 '
161
162 # Testcase 1c, Transitive renaming
163 #   (Related to testcases 3a and 6d -- when should a transitive rename apply?)
164 #   (Related to testcases 9c and 9d -- can transitivity repeat?)
165 #   (Related to testcase 12b -- joint-transitivity?)
166 #   Commit O: z/{b,c},   x/d
167 #   Commit A: y/{b,c},   x/d
168 #   Commit B: z/{b,c,d}
169 #   Expected: y/{b,c,d}  (because x/d -> z/d -> y/d)
170
171 test_setup_1c () {
172         test_create_repo 1c &&
173         (
174                 cd 1c &&
175
176                 mkdir z &&
177                 echo b >z/b &&
178                 echo c >z/c &&
179                 mkdir x &&
180                 echo d >x/d &&
181                 git add z x &&
182                 test_tick &&
183                 git commit -m "O" &&
184
185                 git branch O &&
186                 git branch A &&
187                 git branch B &&
188
189                 git checkout A &&
190                 git mv z y &&
191                 test_tick &&
192                 git commit -m "A" &&
193
194                 git checkout B &&
195                 git mv x/d z/d &&
196                 test_tick &&
197                 git commit -m "B"
198         )
199 }
200
201 test_expect_success '1c: Transitive renaming' '
202         test_setup_1c &&
203         (
204                 cd 1c &&
205
206                 git checkout A^0 &&
207
208                 git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
209
210                 git ls-files -s >out &&
211                 test_line_count = 3 out &&
212
213                 git rev-parse >actual \
214                         HEAD:y/b HEAD:y/c HEAD:y/d &&
215                 git rev-parse >expect \
216                         O:z/b    O:z/c    O:x/d &&
217                 test_cmp expect actual &&
218                 test_must_fail git rev-parse HEAD:x/d &&
219                 test_must_fail git rev-parse HEAD:z/d &&
220                 test_path_is_missing z/d
221         )
222 '
223
224 # Testcase 1d, Directory renames (merging two directories into one new one)
225 #              cause a rename/rename(2to1) conflict
226 #   (Related to testcases 1c and 7b)
227 #   Commit O. z/{b,c},        y/{d,e}
228 #   Commit A. x/{b,c},        y/{d,e,m,wham_1}
229 #   Commit B. z/{b,c,n,wham_2}, x/{d,e}
230 #   Expected: x/{b,c,d,e,m,n}, CONFLICT:(y/wham_1 & z/wham_2 -> x/wham)
231 #   Note: y/m & z/n should definitely move into x.  By the same token, both
232 #         y/wham_1 & z/wham_2 should too...giving us a conflict.
233
234 test_setup_1d () {
235         test_create_repo 1d &&
236         (
237                 cd 1d &&
238
239                 mkdir z &&
240                 echo b >z/b &&
241                 echo c >z/c &&
242                 mkdir y &&
243                 echo d >y/d &&
244                 echo e >y/e &&
245                 git add z y &&
246                 test_tick &&
247                 git commit -m "O" &&
248
249                 git branch O &&
250                 git branch A &&
251                 git branch B &&
252
253                 git checkout A &&
254                 git mv z x &&
255                 echo m >y/m &&
256                 echo wham1 >y/wham &&
257                 git add y &&
258                 test_tick &&
259                 git commit -m "A" &&
260
261                 git checkout B &&
262                 git mv y x &&
263                 echo n >z/n &&
264                 echo wham2 >z/wham &&
265                 git add z &&
266                 test_tick &&
267                 git commit -m "B"
268         )
269 }
270
271 test_expect_success '1d: Directory renames cause a rename/rename(2to1) conflict' '
272         test_setup_1d &&
273         (
274                 cd 1d &&
275
276                 git checkout A^0 &&
277
278                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
279                 test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
280
281                 git ls-files -s >out &&
282                 test_line_count = 8 out &&
283                 git ls-files -u >out &&
284                 test_line_count = 2 out &&
285                 git ls-files -o >out &&
286                 test_line_count = 1 out &&
287
288                 git rev-parse >actual \
289                         :0:x/b :0:x/c :0:x/d :0:x/e :0:x/m :0:x/n &&
290                 git rev-parse >expect \
291                          O:z/b  O:z/c  O:y/d  O:y/e  A:y/m  B:z/n &&
292                 test_cmp expect actual &&
293
294                 test_must_fail git rev-parse :0:x/wham &&
295                 git rev-parse >actual \
296                         :2:x/wham :3:x/wham &&
297                 git rev-parse >expect \
298                          A:y/wham  B:z/wham &&
299                 test_cmp expect actual &&
300
301                 # Test that the two-way merge in x/wham is as expected
302                 git cat-file -p :2:x/wham >expect &&
303                 git cat-file -p :3:x/wham >other &&
304                 >empty &&
305                 test_must_fail git merge-file \
306                         -L "HEAD" \
307                         -L "" \
308                         -L "B^0" \
309                         expect empty other &&
310                 test_cmp expect x/wham
311         )
312 '
313
314 # Testcase 1e, Renamed directory, with all filenames being renamed too
315 #   (Related to testcases 9f & 9g)
316 #   Commit O: z/{oldb,oldc}
317 #   Commit A: y/{newb,newc}
318 #   Commit B: z/{oldb,oldc,d}
319 #   Expected: y/{newb,newc,d}
320
321 test_setup_1e () {
322         test_create_repo 1e &&
323         (
324                 cd 1e &&
325
326                 mkdir z &&
327                 echo b >z/oldb &&
328                 echo c >z/oldc &&
329                 git add z &&
330                 test_tick &&
331                 git commit -m "O" &&
332
333                 git branch O &&
334                 git branch A &&
335                 git branch B &&
336
337                 git checkout A &&
338                 mkdir y &&
339                 git mv z/oldb y/newb &&
340                 git mv z/oldc y/newc &&
341                 test_tick &&
342                 git commit -m "A" &&
343
344                 git checkout B &&
345                 echo d >z/d &&
346                 git add z/d &&
347                 test_tick &&
348                 git commit -m "B"
349         )
350 }
351
352 test_expect_success '1e: Renamed directory, with all files being renamed too' '
353         test_setup_1e &&
354         (
355                 cd 1e &&
356
357                 git checkout A^0 &&
358
359                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
360
361                 git ls-files -s >out &&
362                 test_line_count = 3 out &&
363
364                 git rev-parse >actual \
365                         HEAD:y/newb HEAD:y/newc HEAD:y/d &&
366                 git rev-parse >expect \
367                         O:z/oldb    O:z/oldc    B:z/d &&
368                 test_cmp expect actual &&
369                 test_must_fail git rev-parse HEAD:z/d
370         )
371 '
372
373 # Testcase 1f, Split a directory into two other directories
374 #   (Related to testcases 3a, all of section 2, and all of section 4)
375 #   Commit O: z/{b,c,d,e,f}
376 #   Commit A: z/{b,c,d,e,f,g}
377 #   Commit B: y/{b,c}, x/{d,e,f}
378 #   Expected: y/{b,c}, x/{d,e,f,g}
379
380 test_setup_1f () {
381         test_create_repo 1f &&
382         (
383                 cd 1f &&
384
385                 mkdir z &&
386                 echo b >z/b &&
387                 echo c >z/c &&
388                 echo d >z/d &&
389                 echo e >z/e &&
390                 echo f >z/f &&
391                 git add z &&
392                 test_tick &&
393                 git commit -m "O" &&
394
395                 git branch O &&
396                 git branch A &&
397                 git branch B &&
398
399                 git checkout A &&
400                 echo g >z/g &&
401                 git add z/g &&
402                 test_tick &&
403                 git commit -m "A" &&
404
405                 git checkout B &&
406                 mkdir y &&
407                 mkdir x &&
408                 git mv z/b y/ &&
409                 git mv z/c y/ &&
410                 git mv z/d x/ &&
411                 git mv z/e x/ &&
412                 git mv z/f x/ &&
413                 rmdir z &&
414                 test_tick &&
415                 git commit -m "B"
416         )
417 }
418
419 test_expect_success '1f: Split a directory into two other directories' '
420         test_setup_1f &&
421         (
422                 cd 1f &&
423
424                 git checkout A^0 &&
425
426                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
427
428                 git ls-files -s >out &&
429                 test_line_count = 6 out &&
430
431                 git rev-parse >actual \
432                         HEAD:y/b HEAD:y/c HEAD:x/d HEAD:x/e HEAD:x/f HEAD:x/g &&
433                 git rev-parse >expect \
434                         O:z/b    O:z/c    O:z/d    O:z/e    O:z/f    A:z/g &&
435                 test_cmp expect actual &&
436                 test_path_is_missing z/g &&
437                 test_must_fail git rev-parse HEAD:z/g
438         )
439 '
440
441 ###########################################################################
442 # Rules suggested by testcases in section 1:
443 #
444 #   We should still detect the directory rename even if it wasn't just
445 #   the directory renamed, but the files within it. (see 1b)
446 #
447 #   If renames split a directory into two or more others, the directory
448 #   with the most renames, "wins" (see 1c).  However, see the testcases
449 #   in section 2, plus testcases 3a and 4a.
450 ###########################################################################
451
452
453 ###########################################################################
454 # SECTION 2: Split into multiple directories, with equal number of paths
455 #
456 # Explore the splitting-a-directory rules a bit; what happens in the
457 # edge cases?
458 #
459 # Note that there is a closely related case of a directory not being
460 # split on either side of history, but being renamed differently on
461 # each side.  See testcase 8e for that.
462 ###########################################################################
463
464 # Testcase 2a, Directory split into two on one side, with equal numbers of paths
465 #   Commit O: z/{b,c}
466 #   Commit A: y/b, w/c
467 #   Commit B: z/{b,c,d}
468 #   Expected: y/b, w/c, z/d, with warning about z/ -> (y/ vs. w/) conflict
469 test_setup_2a () {
470         test_create_repo 2a &&
471         (
472                 cd 2a &&
473
474                 mkdir z &&
475                 echo b >z/b &&
476                 echo c >z/c &&
477                 git add z &&
478                 test_tick &&
479                 git commit -m "O" &&
480
481                 git branch O &&
482                 git branch A &&
483                 git branch B &&
484
485                 git checkout A &&
486                 mkdir y &&
487                 mkdir w &&
488                 git mv z/b y/ &&
489                 git mv z/c w/ &&
490                 test_tick &&
491                 git commit -m "A" &&
492
493                 git checkout B &&
494                 echo d >z/d &&
495                 git add z/d &&
496                 test_tick &&
497                 git commit -m "B"
498         )
499 }
500
501 test_expect_success '2a: Directory split into two on one side, with equal numbers of paths' '
502         test_setup_2a &&
503         (
504                 cd 2a &&
505
506                 git checkout A^0 &&
507
508                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
509                 test_i18ngrep "CONFLICT.*directory rename split" out &&
510
511                 git ls-files -s >out &&
512                 test_line_count = 3 out &&
513                 git ls-files -u >out &&
514                 test_line_count = 0 out &&
515                 git ls-files -o >out &&
516                 test_line_count = 1 out &&
517
518                 git rev-parse >actual \
519                         :0:y/b :0:w/c :0:z/d &&
520                 git rev-parse >expect \
521                          O:z/b  O:z/c  B:z/d &&
522                 test_cmp expect actual
523         )
524 '
525
526 # Testcase 2b, Directory split into two on one side, with equal numbers of paths
527 #   Commit O: z/{b,c}
528 #   Commit A: y/b, w/c
529 #   Commit B: z/{b,c}, x/d
530 #   Expected: y/b, w/c, x/d; No warning about z/ -> (y/ vs. w/) conflict
531 test_setup_2b () {
532         test_create_repo 2b &&
533         (
534                 cd 2b &&
535
536                 mkdir z &&
537                 echo b >z/b &&
538                 echo c >z/c &&
539                 git add z &&
540                 test_tick &&
541                 git commit -m "O" &&
542
543                 git branch O &&
544                 git branch A &&
545                 git branch B &&
546
547                 git checkout A &&
548                 mkdir y &&
549                 mkdir w &&
550                 git mv z/b y/ &&
551                 git mv z/c w/ &&
552                 test_tick &&
553                 git commit -m "A" &&
554
555                 git checkout B &&
556                 mkdir x &&
557                 echo d >x/d &&
558                 git add x/d &&
559                 test_tick &&
560                 git commit -m "B"
561         )
562 }
563
564 test_expect_success '2b: Directory split into two on one side, with equal numbers of paths' '
565         test_setup_2b &&
566         (
567                 cd 2b &&
568
569                 git checkout A^0 &&
570
571                 git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
572
573                 git ls-files -s >out &&
574                 test_line_count = 3 out &&
575                 git ls-files -u >out &&
576                 test_line_count = 0 out &&
577                 git ls-files -o >out &&
578                 test_line_count = 1 out &&
579
580                 git rev-parse >actual \
581                         :0:y/b :0:w/c :0:x/d &&
582                 git rev-parse >expect \
583                          O:z/b  O:z/c  B:x/d &&
584                 test_cmp expect actual &&
585                 test_i18ngrep ! "CONFLICT.*directory rename split" out
586         )
587 '
588
589 ###########################################################################
590 # Rules suggested by section 2:
591 #
592 #   None; the rule was already covered in section 1.  These testcases are
593 #   here just to make sure the conflict resolution and necessary warning
594 #   messages are handled correctly.
595 ###########################################################################
596
597
598 ###########################################################################
599 # SECTION 3: Path in question is the source path for some rename already
600 #
601 # Combining cases from Section 1 and trying to handle them could lead to
602 # directory renaming detection being over-applied.  So, this section
603 # provides some good testcases to check that the implementation doesn't go
604 # too far.
605 ###########################################################################
606
607 # Testcase 3a, Avoid implicit rename if involved as source on other side
608 #   (Related to testcases 1c, 1f, and 9h)
609 #   Commit O: z/{b,c,d}
610 #   Commit A: z/{b,c,d} (no change)
611 #   Commit B: y/{b,c}, x/d
612 #   Expected: y/{b,c}, x/d
613 test_setup_3a () {
614         test_create_repo 3a &&
615         (
616                 cd 3a &&
617
618                 mkdir z &&
619                 echo b >z/b &&
620                 echo c >z/c &&
621                 echo d >z/d &&
622                 git add z &&
623                 test_tick &&
624                 git commit -m "O" &&
625
626                 git branch O &&
627                 git branch A &&
628                 git branch B &&
629
630                 git checkout A &&
631                 test_tick &&
632                 git commit --allow-empty -m "A" &&
633
634                 git checkout B &&
635                 mkdir y &&
636                 mkdir x &&
637                 git mv z/b y/ &&
638                 git mv z/c y/ &&
639                 git mv z/d x/ &&
640                 rmdir z &&
641                 test_tick &&
642                 git commit -m "B"
643         )
644 }
645
646 test_expect_success '3a: Avoid implicit rename if involved as source on other side' '
647         test_setup_3a &&
648         (
649                 cd 3a &&
650
651                 git checkout A^0 &&
652
653                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
654
655                 git ls-files -s >out &&
656                 test_line_count = 3 out &&
657
658                 git rev-parse >actual \
659                         HEAD:y/b HEAD:y/c HEAD:x/d &&
660                 git rev-parse >expect \
661                         O:z/b    O:z/c    O:z/d &&
662                 test_cmp expect actual
663         )
664 '
665
666 # Testcase 3b, Avoid implicit rename if involved as source on other side
667 #   (Related to testcases 5c and 7c, also kind of 1e and 1f)
668 #   Commit O: z/{b,c,d}
669 #   Commit A: y/{b,c}, x/d
670 #   Commit B: z/{b,c}, w/d
671 #   Expected: y/{b,c}, CONFLICT:(z/d -> x/d vs. w/d)
672 #   NOTE: We're particularly checking that since z/d is already involved as
673 #         a source in a file rename on the same side of history, that we don't
674 #         get it involved in directory rename detection.  If it were, we might
675 #         end up with CONFLICT:(z/d -> y/d vs. x/d vs. w/d), i.e. a
676 #         rename/rename/rename(1to3) conflict, which is just weird.
677 test_setup_3b () {
678         test_create_repo 3b &&
679         (
680                 cd 3b &&
681
682                 mkdir z &&
683                 echo b >z/b &&
684                 echo c >z/c &&
685                 echo d >z/d &&
686                 git add z &&
687                 test_tick &&
688                 git commit -m "O" &&
689
690                 git branch O &&
691                 git branch A &&
692                 git branch B &&
693
694                 git checkout A &&
695                 mkdir y &&
696                 mkdir x &&
697                 git mv z/b y/ &&
698                 git mv z/c y/ &&
699                 git mv z/d x/ &&
700                 rmdir z &&
701                 test_tick &&
702                 git commit -m "A" &&
703
704                 git checkout B &&
705                 mkdir w &&
706                 git mv z/d w/ &&
707                 test_tick &&
708                 git commit -m "B"
709         )
710 }
711
712 test_expect_success '3b: Avoid implicit rename if involved as source on current side' '
713         test_setup_3b &&
714         (
715                 cd 3b &&
716
717                 git checkout A^0 &&
718
719                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
720                 test_i18ngrep CONFLICT.*rename/rename.*z/d.*x/d.*w/d out &&
721                 test_i18ngrep ! CONFLICT.*rename/rename.*y/d out &&
722
723                 git ls-files -s >out &&
724                 test_line_count = 5 out &&
725                 git ls-files -u >out &&
726                 test_line_count = 3 out &&
727                 git ls-files -o >out &&
728                 test_line_count = 1 out &&
729
730                 git rev-parse >actual \
731                         :0:y/b :0:y/c :1:z/d :2:x/d :3:w/d &&
732                 git rev-parse >expect \
733                          O:z/b  O:z/c  O:z/d  O:z/d  O:z/d &&
734                 test_cmp expect actual &&
735
736                 test_path_is_missing z/d &&
737                 git hash-object >actual \
738                         x/d   w/d &&
739                 git rev-parse >expect \
740                         O:z/d O:z/d &&
741                 test_cmp expect actual
742         )
743 '
744
745 ###########################################################################
746 # Rules suggested by section 3:
747 #
748 #   Avoid directory-rename-detection for a path, if that path is the source
749 #   of a rename on either side of a merge.
750 ###########################################################################
751
752
753 ###########################################################################
754 # SECTION 4: Partially renamed directory; still exists on both sides of merge
755 #
756 # What if we were to attempt to do directory rename detection when someone
757 # "mostly" moved a directory but still left some files around, or,
758 # equivalently, fully renamed a directory in one commit and then recreated
759 # that directory in a later commit adding some new files and then tried to
760 # merge?
761 #
762 # It's hard to divine user intent in these cases, because you can make an
763 # argument that, depending on the intermediate history of the side being
764 # merged, that some users will want files in that directory to
765 # automatically be detected and renamed, while users with a different
766 # intermediate history wouldn't want that rename to happen.
767 #
768 # I think that it is best to simply not have directory rename detection
769 # apply to such cases.  My reasoning for this is four-fold: (1) it's
770 # easiest for users in general to figure out what happened if we don't
771 # apply directory rename detection in any such case, (2) it's an easy rule
772 # to explain ["We don't do directory rename detection if the directory
773 # still exists on both sides of the merge"], (3) we can get some hairy
774 # edge/corner cases that would be really confusing and possibly not even
775 # representable in the index if we were to even try, and [related to 3] (4)
776 # attempting to resolve this issue of divining user intent by examining
777 # intermediate history goes against the spirit of three-way merges and is a
778 # path towards crazy corner cases that are far more complex than what we're
779 # already dealing with.
780 #
781 # Note that the wording of the rule ("We don't do directory rename
782 # detection if the directory still exists on both sides of the merge.")
783 # also excludes "renaming" of a directory into a subdirectory of itself
784 # (e.g. /some/dir/* -> /some/dir/subdir/*).  It may be possible to carve
785 # out an exception for "renaming"-beneath-itself cases without opening
786 # weird edge/corner cases for other partial directory renames, but for now
787 # we are keeping the rule simple.
788 #
789 # This section contains a test for a partially-renamed-directory case.
790 ###########################################################################
791
792 # Testcase 4a, Directory split, with original directory still present
793 #   (Related to testcase 1f)
794 #   Commit O: z/{b,c,d,e}
795 #   Commit A: y/{b,c,d}, z/e
796 #   Commit B: z/{b,c,d,e,f}
797 #   Expected: y/{b,c,d}, z/{e,f}
798 #   NOTE: Even though most files from z moved to y, we don't want f to follow.
799
800 test_setup_4a () {
801         test_create_repo 4a &&
802         (
803                 cd 4a &&
804
805                 mkdir z &&
806                 echo b >z/b &&
807                 echo c >z/c &&
808                 echo d >z/d &&
809                 echo e >z/e &&
810                 git add z &&
811                 test_tick &&
812                 git commit -m "O" &&
813
814                 git branch O &&
815                 git branch A &&
816                 git branch B &&
817
818                 git checkout A &&
819                 mkdir y &&
820                 git mv z/b y/ &&
821                 git mv z/c y/ &&
822                 git mv z/d y/ &&
823                 test_tick &&
824                 git commit -m "A" &&
825
826                 git checkout B &&
827                 echo f >z/f &&
828                 git add z/f &&
829                 test_tick &&
830                 git commit -m "B"
831         )
832 }
833
834 test_expect_success '4a: Directory split, with original directory still present' '
835         test_setup_4a &&
836         (
837                 cd 4a &&
838
839                 git checkout A^0 &&
840
841                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
842
843                 git ls-files -s >out &&
844                 test_line_count = 5 out &&
845                 git ls-files -u >out &&
846                 test_line_count = 0 out &&
847                 git ls-files -o >out &&
848                 test_line_count = 1 out &&
849
850                 git rev-parse >actual \
851                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/e HEAD:z/f &&
852                 git rev-parse >expect \
853                         O:z/b    O:z/c    O:z/d    O:z/e    B:z/f &&
854                 test_cmp expect actual
855         )
856 '
857
858 ###########################################################################
859 # Rules suggested by section 4:
860 #
861 #   Directory-rename-detection should be turned off for any directories (as
862 #   a source for renames) that exist on both sides of the merge.  (The "as
863 #   a source for renames" clarification is due to cases like 1c where
864 #   the target directory exists on both sides and we do want the rename
865 #   detection.)  But, sadly, see testcase 8b.
866 ###########################################################################
867
868
869 ###########################################################################
870 # SECTION 5: Files/directories in the way of subset of to-be-renamed paths
871 #
872 # Implicitly renaming files due to a detected directory rename could run
873 # into problems if there are files or directories in the way of the paths
874 # we want to rename.  Explore such cases in this section.
875 ###########################################################################
876
877 # Testcase 5a, Merge directories, other side adds files to original and target
878 #   Commit O: z/{b,c},       y/d
879 #   Commit A: z/{b,c,e_1,f}, y/{d,e_2}
880 #   Commit B: y/{b,c,d}
881 #   Expected: z/e_1, y/{b,c,d,e_2,f} + CONFLICT warning
882 #   NOTE: While directory rename detection is active here causing z/f to
883 #         become y/f, we did not apply this for z/e_1 because that would
884 #         give us an add/add conflict for y/e_1 vs y/e_2.  This problem with
885 #         this add/add, is that both versions of y/e are from the same side
886 #         of history, giving us no way to represent this conflict in the
887 #         index.
888
889 test_setup_5a () {
890         test_create_repo 5a &&
891         (
892                 cd 5a &&
893
894                 mkdir z &&
895                 echo b >z/b &&
896                 echo c >z/c &&
897                 mkdir y &&
898                 echo d >y/d &&
899                 git add z y &&
900                 test_tick &&
901                 git commit -m "O" &&
902
903                 git branch O &&
904                 git branch A &&
905                 git branch B &&
906
907                 git checkout A &&
908                 echo e1 >z/e &&
909                 echo f >z/f &&
910                 echo e2 >y/e &&
911                 git add z/e z/f y/e &&
912                 test_tick &&
913                 git commit -m "A" &&
914
915                 git checkout B &&
916                 git mv z/b y/ &&
917                 git mv z/c y/ &&
918                 rmdir z &&
919                 test_tick &&
920                 git commit -m "B"
921         )
922 }
923
924 test_expect_success '5a: Merge directories, other side adds files to original and target' '
925         test_setup_5a &&
926         (
927                 cd 5a &&
928
929                 git checkout A^0 &&
930
931                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
932                 test_i18ngrep "CONFLICT.*implicit dir rename" out &&
933
934                 git ls-files -s >out &&
935                 test_line_count = 6 out &&
936                 git ls-files -u >out &&
937                 test_line_count = 0 out &&
938                 git ls-files -o >out &&
939                 test_line_count = 1 out &&
940
941                 git rev-parse >actual \
942                         :0:y/b :0:y/c :0:y/d :0:y/e :0:z/e :0:y/f &&
943                 git rev-parse >expect \
944                          O:z/b  O:z/c  O:y/d  A:y/e  A:z/e  A:z/f &&
945                 test_cmp expect actual
946         )
947 '
948
949 # Testcase 5b, Rename/delete in order to get add/add/add conflict
950 #   (Related to testcase 8d; these may appear slightly inconsistent to users;
951 #    Also related to testcases 7d and 7e)
952 #   Commit O: z/{b,c,d_1}
953 #   Commit A: y/{b,c,d_2}
954 #   Commit B: z/{b,c,d_1,e}, y/d_3
955 #   Expected: y/{b,c,e}, CONFLICT(add/add: y/d_2 vs. y/d_3)
956 #   NOTE: If z/d_1 in commit B were to be involved in dir rename detection, as
957 #         we normally would since z/ is being renamed to y/, then this would be
958 #         a rename/delete (z/d_1 -> y/d_1 vs. deleted) AND an add/add/add
959 #         conflict of y/d_1 vs. y/d_2 vs. y/d_3.  Add/add/add is not
960 #         representable in the index, so the existence of y/d_3 needs to
961 #         cause us to bail on directory rename detection for that path, falling
962 #         back to git behavior without the directory rename detection.
963
964 test_setup_5b () {
965         test_create_repo 5b &&
966         (
967                 cd 5b &&
968
969                 mkdir z &&
970                 echo b >z/b &&
971                 echo c >z/c &&
972                 echo d1 >z/d &&
973                 git add z &&
974                 test_tick &&
975                 git commit -m "O" &&
976
977                 git branch O &&
978                 git branch A &&
979                 git branch B &&
980
981                 git checkout A &&
982                 git rm z/d &&
983                 git mv z y &&
984                 echo d2 >y/d &&
985                 git add y/d &&
986                 test_tick &&
987                 git commit -m "A" &&
988
989                 git checkout B &&
990                 mkdir y &&
991                 echo d3 >y/d &&
992                 echo e >z/e &&
993                 git add y/d z/e &&
994                 test_tick &&
995                 git commit -m "B"
996         )
997 }
998
999 test_expect_success '5b: Rename/delete in order to get add/add/add conflict' '
1000         test_setup_5b &&
1001         (
1002                 cd 5b &&
1003
1004                 git checkout A^0 &&
1005
1006                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1007                 test_i18ngrep "CONFLICT (add/add).* y/d" out &&
1008
1009                 git ls-files -s >out &&
1010                 test_line_count = 5 out &&
1011                 git ls-files -u >out &&
1012                 test_line_count = 2 out &&
1013                 git ls-files -o >out &&
1014                 test_line_count = 1 out &&
1015
1016                 git rev-parse >actual \
1017                         :0:y/b :0:y/c :0:y/e :2:y/d :3:y/d &&
1018                 git rev-parse >expect \
1019                          O:z/b  O:z/c  B:z/e  A:y/d  B:y/d &&
1020                 test_cmp expect actual &&
1021
1022                 test_must_fail git rev-parse :1:y/d &&
1023                 test_path_is_file y/d
1024         )
1025 '
1026
1027 # Testcase 5c, Transitive rename would cause rename/rename/rename/add/add/add
1028 #   (Directory rename detection would result in transitive rename vs.
1029 #    rename/rename(1to2) and turn it into a rename/rename(1to3).  Further,
1030 #    rename paths conflict with separate adds on the other side)
1031 #   (Related to testcases 3b and 7c)
1032 #   Commit O: z/{b,c}, x/d_1
1033 #   Commit A: y/{b,c,d_2}, w/d_1
1034 #   Commit B: z/{b,c,d_1,e}, w/d_3, y/d_4
1035 #   Expected: A mess, but only a rename/rename(1to2)/add/add mess.  Use the
1036 #             presence of y/d_4 in B to avoid doing transitive rename of
1037 #             x/d_1 -> z/d_1 -> y/d_1, so that the only paths we have at
1038 #             y/d are y/d_2 and y/d_4.  We still do the move from z/e to y/e,
1039 #             though, because it doesn't have anything in the way.
1040
1041 test_setup_5c () {
1042         test_create_repo 5c &&
1043         (
1044                 cd 5c &&
1045
1046                 mkdir z &&
1047                 echo b >z/b &&
1048                 echo c >z/c &&
1049                 mkdir x &&
1050                 echo d1 >x/d &&
1051                 git add z x &&
1052                 test_tick &&
1053                 git commit -m "O" &&
1054
1055                 git branch O &&
1056                 git branch A &&
1057                 git branch B &&
1058
1059                 git checkout A &&
1060                 git mv z y &&
1061                 echo d2 >y/d &&
1062                 git add y/d &&
1063                 git mv x w &&
1064                 test_tick &&
1065                 git commit -m "A" &&
1066
1067                 git checkout B &&
1068                 git mv x/d z/ &&
1069                 mkdir w &&
1070                 mkdir y &&
1071                 echo d3 >w/d &&
1072                 echo d4 >y/d &&
1073                 echo e >z/e &&
1074                 git add w/ y/ z/e &&
1075                 test_tick &&
1076                 git commit -m "B"
1077         )
1078 }
1079
1080 test_expect_success '5c: Transitive rename would cause rename/rename/rename/add/add/add' '
1081         test_setup_5c &&
1082         (
1083                 cd 5c &&
1084
1085                 git checkout A^0 &&
1086
1087                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1088                 test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*z/d" out &&
1089                 test_i18ngrep "CONFLICT (add/add).* y/d" out &&
1090
1091                 git ls-files -s >out &&
1092                 test_line_count = 9 out &&
1093                 git ls-files -u >out &&
1094                 test_line_count = 6 out &&
1095                 git ls-files -o >out &&
1096                 test_line_count = 1 out &&
1097
1098                 git rev-parse >actual \
1099                         :0:y/b :0:y/c :0:y/e &&
1100                 git rev-parse >expect \
1101                          O:z/b  O:z/c  B:z/e &&
1102                 test_cmp expect actual &&
1103
1104                 test_must_fail git rev-parse :1:y/d &&
1105                 git rev-parse >actual \
1106                         :2:w/d :3:w/d :1:x/d :2:y/d :3:y/d :3:z/d &&
1107                 git rev-parse >expect \
1108                          O:x/d  B:w/d  O:x/d  A:y/d  B:y/d  O:x/d &&
1109                 test_cmp expect actual &&
1110
1111                 git hash-object >actual \
1112                         z/d &&
1113                 git rev-parse >expect \
1114                         O:x/d &&
1115                 test_cmp expect actual &&
1116                 test_path_is_missing x/d &&
1117                 test_path_is_file y/d &&
1118                 grep -q "<<<<" y/d  # conflict markers should be present
1119         )
1120 '
1121
1122 # Testcase 5d, Directory/file/file conflict due to directory rename
1123 #   Commit O: z/{b,c}
1124 #   Commit A: y/{b,c,d_1}
1125 #   Commit B: z/{b,c,d_2,f}, y/d/e
1126 #   Expected: y/{b,c,d/e,f}, z/d_2, CONFLICT(file/directory), y/d_1~HEAD
1127 #   Note: The fact that y/d/ exists in B makes us bail on directory rename
1128 #         detection for z/d_2, but that doesn't prevent us from applying the
1129 #         directory rename detection for z/f -> y/f.
1130
1131 test_setup_5d () {
1132         test_create_repo 5d &&
1133         (
1134                 cd 5d &&
1135
1136                 mkdir z &&
1137                 echo b >z/b &&
1138                 echo c >z/c &&
1139                 git add z &&
1140                 test_tick &&
1141                 git commit -m "O" &&
1142
1143                 git branch O &&
1144                 git branch A &&
1145                 git branch B &&
1146
1147                 git checkout A &&
1148                 git mv z y &&
1149                 echo d1 >y/d &&
1150                 git add y/d &&
1151                 test_tick &&
1152                 git commit -m "A" &&
1153
1154                 git checkout B &&
1155                 mkdir -p y/d &&
1156                 echo e >y/d/e &&
1157                 echo d2 >z/d &&
1158                 echo f >z/f &&
1159                 git add y/d/e z/d z/f &&
1160                 test_tick &&
1161                 git commit -m "B"
1162         )
1163 }
1164
1165 test_expect_success '5d: Directory/file/file conflict due to directory rename' '
1166         test_setup_5d &&
1167         (
1168                 cd 5d &&
1169
1170                 git checkout A^0 &&
1171
1172                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1173                 test_i18ngrep "CONFLICT (file/directory).*y/d" out &&
1174
1175                 git ls-files -s >out &&
1176                 test_line_count = 6 out &&
1177                 git ls-files -u >out &&
1178                 test_line_count = 1 out &&
1179                 git ls-files -o >out &&
1180                 test_line_count = 2 out &&
1181
1182                 git rev-parse >actual \
1183                         :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d :0:y/d/e &&
1184                 git rev-parse >expect \
1185                          O:z/b  O:z/c  B:z/d  B:z/f  A:y/d  B:y/d/e &&
1186                 test_cmp expect actual &&
1187
1188                 git hash-object y/d~HEAD >actual &&
1189                 git rev-parse A:y/d >expect &&
1190                 test_cmp expect actual
1191         )
1192 '
1193
1194 ###########################################################################
1195 # Rules suggested by section 5:
1196 #
1197 #   If a subset of to-be-renamed files have a file or directory in the way,
1198 #   "turn off" the directory rename for those specific sub-paths, falling
1199 #   back to old handling.  But, sadly, see testcases 8a and 8b.
1200 ###########################################################################
1201
1202
1203 ###########################################################################
1204 # SECTION 6: Same side of the merge was the one that did the rename
1205 #
1206 # It may sound obvious that you only want to apply implicit directory
1207 # renames to directories if the _other_ side of history did the renaming.
1208 # If you did make an implementation that didn't explicitly enforce this
1209 # rule, the majority of cases that would fall under this section would
1210 # also be solved by following the rules from the above sections.  But
1211 # there are still a few that stick out, so this section covers them just
1212 # to make sure we also get them right.
1213 ###########################################################################
1214
1215 # Testcase 6a, Tricky rename/delete
1216 #   Commit O: z/{b,c,d}
1217 #   Commit A: z/b
1218 #   Commit B: y/{b,c}, z/d
1219 #   Expected: y/b, CONFLICT(rename/delete, z/c -> y/c vs. NULL)
1220 #   Note: We're just checking here that the rename of z/b and z/c to put
1221 #         them under y/ doesn't accidentally catch z/d and make it look like
1222 #         it is also involved in a rename/delete conflict.
1223
1224 test_setup_6a () {
1225         test_create_repo 6a &&
1226         (
1227                 cd 6a &&
1228
1229                 mkdir z &&
1230                 echo b >z/b &&
1231                 echo c >z/c &&
1232                 echo d >z/d &&
1233                 git add z &&
1234                 test_tick &&
1235                 git commit -m "O" &&
1236
1237                 git branch O &&
1238                 git branch A &&
1239                 git branch B &&
1240
1241                 git checkout A &&
1242                 git rm z/c &&
1243                 git rm z/d &&
1244                 test_tick &&
1245                 git commit -m "A" &&
1246
1247                 git checkout B &&
1248                 mkdir y &&
1249                 git mv z/b y/ &&
1250                 git mv z/c y/ &&
1251                 test_tick &&
1252                 git commit -m "B"
1253         )
1254 }
1255
1256 test_expect_success '6a: Tricky rename/delete' '
1257         test_setup_6a &&
1258         (
1259                 cd 6a &&
1260
1261                 git checkout A^0 &&
1262
1263                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1264                 test_i18ngrep "CONFLICT (rename/delete).*z/c.*y/c" out &&
1265
1266                 git ls-files -s >out &&
1267                 test_line_count = 2 out &&
1268                 git ls-files -u >out &&
1269                 test_line_count = 1 out &&
1270                 git ls-files -o >out &&
1271                 test_line_count = 1 out &&
1272
1273                 git rev-parse >actual \
1274                         :0:y/b :3:y/c &&
1275                 git rev-parse >expect \
1276                          O:z/b  O:z/c &&
1277                 test_cmp expect actual
1278         )
1279 '
1280
1281 # Testcase 6b1, Same rename done on both sides
1282 #   (Related to testcase 6b2 and 8e)
1283 #   Commit O: z/{b,c,d,e}
1284 #   Commit A: y/{b,c,d}, x/e
1285 #   Commit B: y/{b,c,d}, z/{e,f}
1286 #   Expected: y/{b,c,d,f}, x/e
1287 #   Note: Directory rename detection says A renamed z/ -> y/ (3 paths renamed
1288 #         to y/ and only 1 renamed to x/), therefore the new file 'z/f' in B
1289 #         should be moved to 'y/f'.
1290 #
1291 #         This is a bit of an edge case where any behavior might surprise users,
1292 #         whether that is treating A as renaming z/ -> y/, treating A as renaming
1293 #         z/ -> x/, or treating A as not doing any directory rename.  However, I
1294 #         think this answer is the least confusing and most consistent with the
1295 #         rules elsewhere.
1296 #
1297 #         A note about z/ -> x/, since it may not be clear how that could come
1298 #         about: If we were to ignore files renamed by both sides
1299 #         (i.e. z/{b,c,d}), as directory rename detection did in git-2.18 thru
1300 #         at least git-2.28, then we would note there are no renames from z/ to
1301 #         y/ and one rename from z/ to x/ and thus come to the conclusion that
1302 #         A renamed z/ -> x/.  This seems more confusing for end users than a
1303 #         rename of z/ to y/, it makes directory rename detection behavior
1304 #         harder for them to predict.  As such, we modified the rule, changed
1305 #         the behavior on testcases 6b2 and 8e, and introduced this 6b1 testcase.
1306
1307 test_setup_6b1 () {
1308         test_create_repo 6b1 &&
1309         (
1310                 cd 6b1 &&
1311
1312                 mkdir z &&
1313                 echo b >z/b &&
1314                 echo c >z/c &&
1315                 echo d >z/d &&
1316                 echo e >z/e &&
1317                 git add z &&
1318                 test_tick &&
1319                 git commit -m "O" &&
1320
1321                 git branch O &&
1322                 git branch A &&
1323                 git branch B &&
1324
1325                 git checkout A &&
1326                 git mv z y &&
1327                 mkdir x &&
1328                 git mv y/e x/e &&
1329                 test_tick &&
1330                 git commit -m "A" &&
1331
1332                 git checkout B &&
1333                 git mv z y &&
1334                 mkdir z &&
1335                 git mv y/e z/e &&
1336                 echo f >z/f &&
1337                 git add z/f &&
1338                 test_tick &&
1339                 git commit -m "B"
1340         )
1341 }
1342
1343 test_expect_merge_algorithm failure success '6b1: Same renames done on both sides, plus another rename' '
1344         test_setup_6b1 &&
1345         (
1346                 cd 6b1 &&
1347
1348                 git checkout A^0 &&
1349
1350                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
1351
1352                 git ls-files -s >out &&
1353                 test_line_count = 5 out &&
1354                 git ls-files -u >out &&
1355                 test_line_count = 0 out &&
1356                 git ls-files -o >out &&
1357                 test_line_count = 1 out &&
1358
1359                 git rev-parse >actual \
1360                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:x/e HEAD:y/f &&
1361                 git rev-parse >expect \
1362                         O:z/b    O:z/c    O:z/d    O:z/e    B:z/f &&
1363                 test_cmp expect actual
1364         )
1365 '
1366
1367 # Testcase 6b2, Same rename done on both sides
1368 #   (Related to testcases 6c and 8e)
1369 #   Commit O: z/{b,c}
1370 #   Commit A: y/{b,c}
1371 #   Commit B: y/{b,c}, z/d
1372 #   Expected: y/{b,c,d}
1373 #   Alternate: y/{b,c}, z/d
1374 #   Note: Directory rename detection says A renamed z/ -> y/, therefore the new
1375 #         file 'z/d' in B should be moved to 'y/d'.
1376 #
1377 #         We could potentially ignore the renames of z/{b,c} on side A since
1378 #         those were renamed on both sides.  However, it's a bit of a corner
1379 #         case because what if there was also a z/e that side A moved to x/e
1380 #         and side B left alone?  If we used the "ignore renames done on both
1381 #         sides" logic, then we'd compute that A renamed z/ -> x/, and move
1382 #         z/d to x/d.  That seems more surprising and uglier than allowing
1383 #         the z/ -> y/ rename.
1384
1385 test_setup_6b2 () {
1386         test_create_repo 6b2 &&
1387         (
1388                 cd 6b2 &&
1389
1390                 mkdir z &&
1391                 echo b >z/b &&
1392                 echo c >z/c &&
1393                 git add z &&
1394                 test_tick &&
1395                 git commit -m "O" &&
1396
1397                 git branch O &&
1398                 git branch A &&
1399                 git branch B &&
1400
1401                 git checkout A &&
1402                 git mv z y &&
1403                 test_tick &&
1404                 git commit -m "A" &&
1405
1406                 git checkout B &&
1407                 git mv z y &&
1408                 mkdir z &&
1409                 echo d >z/d &&
1410                 git add z/d &&
1411                 test_tick &&
1412                 git commit -m "B"
1413         )
1414 }
1415
1416 test_expect_merge_algorithm failure success '6b2: Same rename done on both sides' '
1417         test_setup_6b2 &&
1418         (
1419                 cd 6b2 &&
1420
1421                 git checkout A^0 &&
1422
1423                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
1424
1425                 git ls-files -s >out &&
1426                 test_line_count = 3 out &&
1427                 git ls-files -u >out &&
1428                 test_line_count = 0 out &&
1429                 git ls-files -o >out &&
1430                 test_line_count = 1 out &&
1431
1432                 git rev-parse >actual \
1433                         HEAD:y/b HEAD:y/c HEAD:y/d &&
1434                 git rev-parse >expect \
1435                         O:z/b    O:z/c    B:z/d &&
1436                 test_cmp expect actual
1437         )
1438 '
1439
1440 # Testcase 6c, Rename only done on same side
1441 #   (Related to testcases 6b1, 6b2, and 8e)
1442 #   Commit O: z/{b,c}
1443 #   Commit A: z/{b,c} (no change)
1444 #   Commit B: y/{b,c}, z/d
1445 #   Expected: y/{b,c}, z/d
1446 #   NOTE: Seems obvious, but just checking that the implementation doesn't
1447 #         "accidentally detect a rename" and give us y/{b,c,d}.
1448
1449 test_setup_6c () {
1450         test_create_repo 6c &&
1451         (
1452                 cd 6c &&
1453
1454                 mkdir z &&
1455                 echo b >z/b &&
1456                 echo c >z/c &&
1457                 git add z &&
1458                 test_tick &&
1459                 git commit -m "O" &&
1460
1461                 git branch O &&
1462                 git branch A &&
1463                 git branch B &&
1464
1465                 git checkout A &&
1466                 test_tick &&
1467                 git commit --allow-empty -m "A" &&
1468
1469                 git checkout B &&
1470                 git mv z y &&
1471                 mkdir z &&
1472                 echo d >z/d &&
1473                 git add z/d &&
1474                 test_tick &&
1475                 git commit -m "B"
1476         )
1477 }
1478
1479 test_expect_success '6c: Rename only done on same side' '
1480         test_setup_6c &&
1481         (
1482                 cd 6c &&
1483
1484                 git checkout A^0 &&
1485
1486                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
1487
1488                 git ls-files -s >out &&
1489                 test_line_count = 3 out &&
1490                 git ls-files -u >out &&
1491                 test_line_count = 0 out &&
1492                 git ls-files -o >out &&
1493                 test_line_count = 1 out &&
1494
1495                 git rev-parse >actual \
1496                         HEAD:y/b HEAD:y/c HEAD:z/d &&
1497                 git rev-parse >expect \
1498                         O:z/b    O:z/c    B:z/d &&
1499                 test_cmp expect actual
1500         )
1501 '
1502
1503 # Testcase 6d, We don't always want transitive renaming
1504 #   (Related to testcase 1c)
1505 #   Commit O: z/{b,c}, x/d
1506 #   Commit A: z/{b,c}, x/d (no change)
1507 #   Commit B: y/{b,c}, z/d
1508 #   Expected: y/{b,c}, z/d
1509 #   NOTE: Again, this seems obvious but just checking that the implementation
1510 #         doesn't "accidentally detect a rename" and give us y/{b,c,d}.
1511
1512 test_setup_6d () {
1513         test_create_repo 6d &&
1514         (
1515                 cd 6d &&
1516
1517                 mkdir z &&
1518                 echo b >z/b &&
1519                 echo c >z/c &&
1520                 mkdir x &&
1521                 echo d >x/d &&
1522                 git add z x &&
1523                 test_tick &&
1524                 git commit -m "O" &&
1525
1526                 git branch O &&
1527                 git branch A &&
1528                 git branch B &&
1529
1530                 git checkout A &&
1531                 test_tick &&
1532                 git commit --allow-empty -m "A" &&
1533
1534                 git checkout B &&
1535                 git mv z y &&
1536                 git mv x z &&
1537                 test_tick &&
1538                 git commit -m "B"
1539         )
1540 }
1541
1542 test_expect_success '6d: We do not always want transitive renaming' '
1543         test_setup_6d &&
1544         (
1545                 cd 6d &&
1546
1547                 git checkout A^0 &&
1548
1549                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
1550
1551                 git ls-files -s >out &&
1552                 test_line_count = 3 out &&
1553                 git ls-files -u >out &&
1554                 test_line_count = 0 out &&
1555                 git ls-files -o >out &&
1556                 test_line_count = 1 out &&
1557
1558                 git rev-parse >actual \
1559                         HEAD:y/b HEAD:y/c HEAD:z/d &&
1560                 git rev-parse >expect \
1561                         O:z/b    O:z/c    O:x/d &&
1562                 test_cmp expect actual
1563         )
1564 '
1565
1566 # Testcase 6e, Add/add from one-side
1567 #   Commit O: z/{b,c}
1568 #   Commit A: z/{b,c} (no change)
1569 #   Commit B: y/{b,c,d_1}, z/d_2
1570 #   Expected: y/{b,c,d_1}, z/d_2
1571 #   NOTE: Again, this seems obvious but just checking that the implementation
1572 #         doesn't "accidentally detect a rename" and give us y/{b,c} +
1573 #         add/add conflict on y/d_1 vs y/d_2.
1574
1575 test_setup_6e () {
1576         test_create_repo 6e &&
1577         (
1578                 cd 6e &&
1579
1580                 mkdir z &&
1581                 echo b >z/b &&
1582                 echo c >z/c &&
1583                 git add z &&
1584                 test_tick &&
1585                 git commit -m "O" &&
1586
1587                 git branch O &&
1588                 git branch A &&
1589                 git branch B &&
1590
1591                 git checkout A &&
1592                 test_tick &&
1593                 git commit --allow-empty -m "A" &&
1594
1595                 git checkout B &&
1596                 git mv z y &&
1597                 echo d1 > y/d &&
1598                 mkdir z &&
1599                 echo d2 > z/d &&
1600                 git add y/d z/d &&
1601                 test_tick &&
1602                 git commit -m "B"
1603         )
1604 }
1605
1606 test_expect_success '6e: Add/add from one side' '
1607         test_setup_6e &&
1608         (
1609                 cd 6e &&
1610
1611                 git checkout A^0 &&
1612
1613                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
1614
1615                 git ls-files -s >out &&
1616                 test_line_count = 4 out &&
1617                 git ls-files -u >out &&
1618                 test_line_count = 0 out &&
1619                 git ls-files -o >out &&
1620                 test_line_count = 1 out &&
1621
1622                 git rev-parse >actual \
1623                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/d &&
1624                 git rev-parse >expect \
1625                         O:z/b    O:z/c    B:y/d    B:z/d &&
1626                 test_cmp expect actual
1627         )
1628 '
1629
1630 ###########################################################################
1631 # Rules suggested by section 6:
1632 #
1633 #   Only apply implicit directory renames to directories if the other
1634 #   side of history is the one doing the renaming.
1635 ###########################################################################
1636
1637
1638 ###########################################################################
1639 # SECTION 7: More involved Edge/Corner cases
1640 #
1641 # The ruleset we have generated in the above sections seems to provide
1642 # well-defined merges.  But can we find edge/corner cases that either (a)
1643 # are harder for users to understand, or (b) have a resolution that is
1644 # non-intuitive or suboptimal?
1645 #
1646 # The testcases in this section dive into cases that I've tried to craft in
1647 # a way to find some that might be surprising to users or difficult for
1648 # them to understand (the next section will look at non-intuitive or
1649 # suboptimal merge results).  Some of the testcases are similar to ones
1650 # from past sections, but have been simplified to try to highlight error
1651 # messages using a "modified" path (due to the directory rename).  Are
1652 # users okay with these?
1653 #
1654 # In my opinion, testcases that are difficult to understand from this
1655 # section is due to difficulty in the testcase rather than the directory
1656 # renaming (similar to how t6042 and t6036 have difficult resolutions due
1657 # to the problem setup itself being complex).  And I don't think the
1658 # error messages are a problem.
1659 #
1660 # On the other hand, the testcases in section 8 worry me slightly more...
1661 ###########################################################################
1662
1663 # Testcase 7a, rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file
1664 #   Commit O: z/{b,c}
1665 #   Commit A: y/{b,c}
1666 #   Commit B: w/b, x/c, z/d
1667 #   Expected: y/d, CONFLICT(rename/rename for both z/b and z/c)
1668 #   NOTE: There's a rename of z/ here, y/ has more renames, so z/d -> y/d.
1669
1670 test_setup_7a () {
1671         test_create_repo 7a &&
1672         (
1673                 cd 7a &&
1674
1675                 mkdir z &&
1676                 echo b >z/b &&
1677                 echo c >z/c &&
1678                 git add z &&
1679                 test_tick &&
1680                 git commit -m "O" &&
1681
1682                 git branch O &&
1683                 git branch A &&
1684                 git branch B &&
1685
1686                 git checkout A &&
1687                 git mv z y &&
1688                 test_tick &&
1689                 git commit -m "A" &&
1690
1691                 git checkout B &&
1692                 mkdir w &&
1693                 mkdir x &&
1694                 git mv z/b w/ &&
1695                 git mv z/c x/ &&
1696                 echo d > z/d &&
1697                 git add z/d &&
1698                 test_tick &&
1699                 git commit -m "B"
1700         )
1701 }
1702
1703 test_expect_success '7a: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file' '
1704         test_setup_7a &&
1705         (
1706                 cd 7a &&
1707
1708                 git checkout A^0 &&
1709
1710                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1711                 test_i18ngrep "CONFLICT (rename/rename).*z/b.*y/b.*w/b" out &&
1712                 test_i18ngrep "CONFLICT (rename/rename).*z/c.*y/c.*x/c" out &&
1713
1714                 git ls-files -s >out &&
1715                 test_line_count = 7 out &&
1716                 git ls-files -u >out &&
1717                 test_line_count = 6 out &&
1718                 git ls-files -o >out &&
1719                 test_line_count = 1 out &&
1720
1721                 git rev-parse >actual \
1722                         :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:x/c :0:y/d &&
1723                 git rev-parse >expect \
1724                          O:z/b  O:z/b  O:z/b  O:z/c  O:z/c  O:z/c  B:z/d &&
1725                 test_cmp expect actual &&
1726
1727                 git hash-object >actual \
1728                         y/b   w/b   y/c   x/c &&
1729                 git rev-parse >expect \
1730                         O:z/b O:z/b O:z/c O:z/c &&
1731                 test_cmp expect actual
1732         )
1733 '
1734
1735 # Testcase 7b, rename/rename(2to1), but only due to transitive rename
1736 #   (Related to testcase 1d)
1737 #   Commit O: z/{b,c},     x/d_1, w/d_2
1738 #   Commit A: y/{b,c,d_2}, x/d_1
1739 #   Commit B: z/{b,c,d_1},        w/d_2
1740 #   Expected: y/{b,c}, CONFLICT(rename/rename(2to1): x/d_1, w/d_2 -> y_d)
1741
1742 test_setup_7b () {
1743         test_create_repo 7b &&
1744         (
1745                 cd 7b &&
1746
1747                 mkdir z &&
1748                 mkdir x &&
1749                 mkdir w &&
1750                 echo b >z/b &&
1751                 echo c >z/c &&
1752                 echo d1 > x/d &&
1753                 echo d2 > w/d &&
1754                 git add z x w &&
1755                 test_tick &&
1756                 git commit -m "O" &&
1757
1758                 git branch O &&
1759                 git branch A &&
1760                 git branch B &&
1761
1762                 git checkout A &&
1763                 git mv z y &&
1764                 git mv w/d y/ &&
1765                 test_tick &&
1766                 git commit -m "A" &&
1767
1768                 git checkout B &&
1769                 git mv x/d z/ &&
1770                 rmdir x &&
1771                 test_tick &&
1772                 git commit -m "B"
1773         )
1774 }
1775
1776 test_expect_success '7b: rename/rename(2to1), but only due to transitive rename' '
1777         test_setup_7b &&
1778         (
1779                 cd 7b &&
1780
1781                 git checkout A^0 &&
1782
1783                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1784                 test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
1785
1786                 git ls-files -s >out &&
1787                 test_line_count = 4 out &&
1788                 git ls-files -u >out &&
1789                 test_line_count = 2 out &&
1790                 git ls-files -o >out &&
1791                 test_line_count = 1 out &&
1792
1793                 git rev-parse >actual \
1794                         :0:y/b :0:y/c :2:y/d :3:y/d &&
1795                 git rev-parse >expect \
1796                          O:z/b  O:z/c  O:w/d  O:x/d &&
1797                 test_cmp expect actual &&
1798
1799                 # Test that the two-way merge in y/d is as expected
1800                 git cat-file -p :2:y/d >expect &&
1801                 git cat-file -p :3:y/d >other &&
1802                 >empty &&
1803                 test_must_fail git merge-file \
1804                         -L "HEAD" \
1805                         -L "" \
1806                         -L "B^0" \
1807                         expect empty other &&
1808                 test_cmp expect y/d
1809         )
1810 '
1811
1812 # Testcase 7c, rename/rename(1to...2or3); transitive rename may add complexity
1813 #   (Related to testcases 3b and 5c)
1814 #   Commit O: z/{b,c}, x/d
1815 #   Commit A: y/{b,c}, w/d
1816 #   Commit B: z/{b,c,d}
1817 #   Expected: y/{b,c}, CONFLICT(x/d -> w/d vs. y/d)
1818 #   NOTE: z/ was renamed to y/ so we do want to report
1819 #         neither CONFLICT(x/d -> w/d vs. z/d)
1820 #         nor CONFLiCT x/d -> w/d vs. y/d vs. z/d)
1821
1822 test_setup_7c () {
1823         test_create_repo 7c &&
1824         (
1825                 cd 7c &&
1826
1827                 mkdir z &&
1828                 echo b >z/b &&
1829                 echo c >z/c &&
1830                 mkdir x &&
1831                 echo d >x/d &&
1832                 git add z x &&
1833                 test_tick &&
1834                 git commit -m "O" &&
1835
1836                 git branch O &&
1837                 git branch A &&
1838                 git branch B &&
1839
1840                 git checkout A &&
1841                 git mv z y &&
1842                 git mv x w &&
1843                 test_tick &&
1844                 git commit -m "A" &&
1845
1846                 git checkout B &&
1847                 git mv x/d z/ &&
1848                 rmdir x &&
1849                 test_tick &&
1850                 git commit -m "B"
1851         )
1852 }
1853
1854 test_expect_success '7c: rename/rename(1to...2or3); transitive rename may add complexity' '
1855         test_setup_7c &&
1856         (
1857                 cd 7c &&
1858
1859                 git checkout A^0 &&
1860
1861                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1862                 test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*y/d" out &&
1863
1864                 git ls-files -s >out &&
1865                 test_line_count = 5 out &&
1866                 git ls-files -u >out &&
1867                 test_line_count = 3 out &&
1868                 git ls-files -o >out &&
1869                 test_line_count = 1 out &&
1870
1871                 git rev-parse >actual \
1872                         :0:y/b :0:y/c :1:x/d :2:w/d :3:y/d &&
1873                 git rev-parse >expect \
1874                          O:z/b  O:z/c  O:x/d  O:x/d  O:x/d &&
1875                 test_cmp expect actual
1876         )
1877 '
1878
1879 # Testcase 7d, transitive rename involved in rename/delete; how is it reported?
1880 #   (Related somewhat to testcases 5b and 8d)
1881 #   Commit O: z/{b,c}, x/d
1882 #   Commit A: y/{b,c}
1883 #   Commit B: z/{b,c,d}
1884 #   Expected: y/{b,c}, CONFLICT(delete x/d vs rename to y/d)
1885 #   NOTE: z->y so NOT CONFLICT(delete x/d vs rename to z/d)
1886
1887 test_setup_7d () {
1888         test_create_repo 7d &&
1889         (
1890                 cd 7d &&
1891
1892                 mkdir z &&
1893                 echo b >z/b &&
1894                 echo c >z/c &&
1895                 mkdir x &&
1896                 echo d >x/d &&
1897                 git add z x &&
1898                 test_tick &&
1899                 git commit -m "O" &&
1900
1901                 git branch O &&
1902                 git branch A &&
1903                 git branch B &&
1904
1905                 git checkout A &&
1906                 git mv z y &&
1907                 git rm -rf x &&
1908                 test_tick &&
1909                 git commit -m "A" &&
1910
1911                 git checkout B &&
1912                 git mv x/d z/ &&
1913                 rmdir x &&
1914                 test_tick &&
1915                 git commit -m "B"
1916         )
1917 }
1918
1919 test_expect_success '7d: transitive rename involved in rename/delete; how is it reported?' '
1920         test_setup_7d &&
1921         (
1922                 cd 7d &&
1923
1924                 git checkout A^0 &&
1925
1926                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1927                 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1928
1929                 git ls-files -s >out &&
1930                 test_line_count = 3 out &&
1931                 git ls-files -u >out &&
1932                 test_line_count = 1 out &&
1933                 git ls-files -o >out &&
1934                 test_line_count = 1 out &&
1935
1936                 git rev-parse >actual \
1937                         :0:y/b :0:y/c :3:y/d &&
1938                 git rev-parse >expect \
1939                          O:z/b  O:z/c  O:x/d &&
1940                 test_cmp expect actual
1941         )
1942 '
1943
1944 # Testcase 7e, transitive rename in rename/delete AND dirs in the way
1945 #   (Very similar to 'both rename source and destination involved in D/F conflict' from t6022-merge-rename.sh)
1946 #   (Also related to testcases 9c and 9d)
1947 #   Commit O: z/{b,c},     x/d_1
1948 #   Commit A: y/{b,c,d/g}, x/d/f
1949 #   Commit B: z/{b,c,d_1}
1950 #   Expected: rename/delete(x/d_1->y/d_1 vs. None) + D/F conflict on y/d
1951 #             y/{b,c,d/g}, y/d_1~B^0, x/d/f
1952
1953 #   NOTE: The main path of interest here is d_1 and where it ends up, but
1954 #         this is actually a case that has two potential directory renames
1955 #         involved and D/F conflict(s), so it makes sense to walk through
1956 #         each step.
1957 #
1958 #         Commit A renames z/ -> y/.  Thus everything that B adds to z/
1959 #         should be instead moved to y/.  This gives us the D/F conflict on
1960 #         y/d because x/d_1 -> z/d_1 -> y/d_1 conflicts with y/d/g.
1961 #
1962 #         Further, commit B renames x/ -> z/, thus everything A adds to x/
1963 #         should instead be moved to z/...BUT we removed z/ and renamed it
1964 #         to y/, so maybe everything should move not from x/ to z/, but
1965 #         from x/ to z/ to y/.  Doing so might make sense from the logic so
1966 #         far, but note that commit A had both an x/ and a y/; it did the
1967 #         renaming of z/ to y/ and created x/d/f and it clearly made these
1968 #         things separate, so it doesn't make much sense to push these
1969 #         together.  Doing so is what I'd call a doubly transitive rename;
1970 #         see testcases 9c and 9d for further discussion of this issue and
1971 #         how it's resolved.
1972
1973 test_setup_7e () {
1974         test_create_repo 7e &&
1975         (
1976                 cd 7e &&
1977
1978                 mkdir z &&
1979                 echo b >z/b &&
1980                 echo c >z/c &&
1981                 mkdir x &&
1982                 echo d1 >x/d &&
1983                 git add z x &&
1984                 test_tick &&
1985                 git commit -m "O" &&
1986
1987                 git branch O &&
1988                 git branch A &&
1989                 git branch B &&
1990
1991                 git checkout A &&
1992                 git mv z y &&
1993                 git rm x/d &&
1994                 mkdir -p x/d &&
1995                 mkdir -p y/d &&
1996                 echo f >x/d/f &&
1997                 echo g >y/d/g &&
1998                 git add x/d/f y/d/g &&
1999                 test_tick &&
2000                 git commit -m "A" &&
2001
2002                 git checkout B &&
2003                 git mv x/d z/ &&
2004                 rmdir x &&
2005                 test_tick &&
2006                 git commit -m "B"
2007         )
2008 }
2009
2010 test_expect_success '7e: transitive rename in rename/delete AND dirs in the way' '
2011         test_setup_7e &&
2012         (
2013                 cd 7e &&
2014
2015                 git checkout A^0 &&
2016
2017                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2018                 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
2019
2020                 git ls-files -s >out &&
2021                 test_line_count = 5 out &&
2022                 git ls-files -u >out &&
2023                 test_line_count = 1 out &&
2024                 git ls-files -o >out &&
2025                 test_line_count = 2 out &&
2026
2027                 git rev-parse >actual \
2028                         :0:x/d/f :0:y/d/g :0:y/b :0:y/c :3:y/d &&
2029                 git rev-parse >expect \
2030                          A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d &&
2031                 test_cmp expect actual &&
2032
2033                 git hash-object y/d~B^0 >actual &&
2034                 git rev-parse O:x/d >expect &&
2035                 test_cmp expect actual
2036         )
2037 '
2038
2039 ###########################################################################
2040 # SECTION 8: Suboptimal merges
2041 #
2042 # As alluded to in the last section, the ruleset we have built up for
2043 # detecting directory renames unfortunately has some special cases where it
2044 # results in slightly suboptimal or non-intuitive behavior.  This section
2045 # explores these cases.
2046 #
2047 # To be fair, we already had non-intuitive or suboptimal behavior for most
2048 # of these cases in git before introducing implicit directory rename
2049 # detection, but it'd be nice if there was a modified ruleset out there
2050 # that handled these cases a bit better.
2051 ###########################################################################
2052
2053 # Testcase 8a, Dual-directory rename, one into the others' way
2054 #   Commit O. x/{a,b},   y/{c,d}
2055 #   Commit A. x/{a,b,e}, y/{c,d,f}
2056 #   Commit B. y/{a,b},   z/{c,d}
2057 #
2058 # Possible Resolutions:
2059 #   w/o dir-rename detection: y/{a,b,f},   z/{c,d},   x/e
2060 #   Currently expected:       y/{a,b,e,f}, z/{c,d}
2061 #   Optimal:                  y/{a,b,e},   z/{c,d,f}
2062 #
2063 # Note: Both x and y got renamed and it'd be nice to detect both, and we do
2064 # better with directory rename detection than git did without, but the
2065 # simple rule from section 5 prevents me from handling this as optimally as
2066 # we potentially could.
2067
2068 test_setup_8a () {
2069         test_create_repo 8a &&
2070         (
2071                 cd 8a &&
2072
2073                 mkdir x &&
2074                 mkdir y &&
2075                 echo a >x/a &&
2076                 echo b >x/b &&
2077                 echo c >y/c &&
2078                 echo d >y/d &&
2079                 git add x y &&
2080                 test_tick &&
2081                 git commit -m "O" &&
2082
2083                 git branch O &&
2084                 git branch A &&
2085                 git branch B &&
2086
2087                 git checkout A &&
2088                 echo e >x/e &&
2089                 echo f >y/f &&
2090                 git add x/e y/f &&
2091                 test_tick &&
2092                 git commit -m "A" &&
2093
2094                 git checkout B &&
2095                 git mv y z &&
2096                 git mv x y &&
2097                 test_tick &&
2098                 git commit -m "B"
2099         )
2100 }
2101
2102 test_expect_success '8a: Dual-directory rename, one into the others way' '
2103         test_setup_8a &&
2104         (
2105                 cd 8a &&
2106
2107                 git checkout A^0 &&
2108
2109                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2110
2111                 git ls-files -s >out &&
2112                 test_line_count = 6 out &&
2113                 git ls-files -u >out &&
2114                 test_line_count = 0 out &&
2115                 git ls-files -o >out &&
2116                 test_line_count = 1 out &&
2117
2118                 git rev-parse >actual \
2119                         HEAD:y/a HEAD:y/b HEAD:y/e HEAD:y/f HEAD:z/c HEAD:z/d &&
2120                 git rev-parse >expect \
2121                         O:x/a    O:x/b    A:x/e    A:y/f    O:y/c    O:y/d &&
2122                 test_cmp expect actual
2123         )
2124 '
2125
2126 # Testcase 8b, Dual-directory rename, one into the others' way, with conflicting filenames
2127 #   Commit O. x/{a_1,b_1},     y/{a_2,b_2}
2128 #   Commit A. x/{a_1,b_1,e_1}, y/{a_2,b_2,e_2}
2129 #   Commit B. y/{a_1,b_1},     z/{a_2,b_2}
2130 #
2131 #   w/o dir-rename detection: y/{a_1,b_1,e_2}, z/{a_2,b_2}, x/e_1
2132 #   Currently expected:       <same>
2133 #   Scary:                    y/{a_1,b_1},     z/{a_2,b_2}, CONFLICT(add/add, e_1 vs. e_2)
2134 #   Optimal:                  y/{a_1,b_1,e_1}, z/{a_2,b_2,e_2}
2135 #
2136 # Note: Very similar to 8a, except instead of 'e' and 'f' in directories x and
2137 # y, both are named 'e'.  Without directory rename detection, neither file
2138 # moves directories.  Implement directory rename detection suboptimally, and
2139 # you get an add/add conflict, but both files were added in commit A, so this
2140 # is an add/add conflict where one side of history added both files --
2141 # something we can't represent in the index.  Obviously, we'd prefer the last
2142 # resolution, but our previous rules are too coarse to allow it.  Using both
2143 # the rules from section 4 and section 5 save us from the Scary resolution,
2144 # making us fall back to pre-directory-rename-detection behavior for both
2145 # e_1 and e_2.
2146
2147 test_setup_8b () {
2148         test_create_repo 8b &&
2149         (
2150                 cd 8b &&
2151
2152                 mkdir x &&
2153                 mkdir y &&
2154                 echo a1 >x/a &&
2155                 echo b1 >x/b &&
2156                 echo a2 >y/a &&
2157                 echo b2 >y/b &&
2158                 git add x y &&
2159                 test_tick &&
2160                 git commit -m "O" &&
2161
2162                 git branch O &&
2163                 git branch A &&
2164                 git branch B &&
2165
2166                 git checkout A &&
2167                 echo e1 >x/e &&
2168                 echo e2 >y/e &&
2169                 git add x/e y/e &&
2170                 test_tick &&
2171                 git commit -m "A" &&
2172
2173                 git checkout B &&
2174                 git mv y z &&
2175                 git mv x y &&
2176                 test_tick &&
2177                 git commit -m "B"
2178         )
2179 }
2180
2181 test_expect_success '8b: Dual-directory rename, one into the others way, with conflicting filenames' '
2182         test_setup_8b &&
2183         (
2184                 cd 8b &&
2185
2186                 git checkout A^0 &&
2187
2188                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2189
2190                 git ls-files -s >out &&
2191                 test_line_count = 6 out &&
2192                 git ls-files -u >out &&
2193                 test_line_count = 0 out &&
2194                 git ls-files -o >out &&
2195                 test_line_count = 1 out &&
2196
2197                 git rev-parse >actual \
2198                         HEAD:y/a HEAD:y/b HEAD:z/a HEAD:z/b HEAD:x/e HEAD:y/e &&
2199                 git rev-parse >expect \
2200                         O:x/a    O:x/b    O:y/a    O:y/b    A:x/e    A:y/e &&
2201                 test_cmp expect actual
2202         )
2203 '
2204
2205 # Testcase 8c, modify/delete or rename+modify/delete?
2206 #   (Related to testcases 5b, 8d, and 9h)
2207 #   Commit O: z/{b,c,d}
2208 #   Commit A: y/{b,c}
2209 #   Commit B: z/{b,c,d_modified,e}
2210 #   Expected: y/{b,c,e}, CONFLICT(modify/delete: on z/d)
2211 #
2212 #   Note: It could easily be argued that the correct resolution here is
2213 #         y/{b,c,e}, CONFLICT(rename/delete: z/d -> y/d vs deleted)
2214 #         and that the modified version of d should be present in y/ after
2215 #         the merge, just marked as conflicted.  Indeed, I previously did
2216 #         argue that.  But applying directory renames to the side of
2217 #         history where a file is merely modified results in spurious
2218 #         rename/rename(1to2) conflicts -- see testcase 9h.  See also
2219 #         notes in 8d.
2220
2221 test_setup_8c () {
2222         test_create_repo 8c &&
2223         (
2224                 cd 8c &&
2225
2226                 mkdir z &&
2227                 echo b >z/b &&
2228                 echo c >z/c &&
2229                 test_seq 1 10 >z/d &&
2230                 git add z &&
2231                 test_tick &&
2232                 git commit -m "O" &&
2233
2234                 git branch O &&
2235                 git branch A &&
2236                 git branch B &&
2237
2238                 git checkout A &&
2239                 git rm z/d &&
2240                 git mv z y &&
2241                 test_tick &&
2242                 git commit -m "A" &&
2243
2244                 git checkout B &&
2245                 echo 11 >z/d &&
2246                 test_chmod +x z/d &&
2247                 echo e >z/e &&
2248                 git add z/d z/e &&
2249                 test_tick &&
2250                 git commit -m "B"
2251         )
2252 }
2253
2254 test_expect_success '8c: modify/delete or rename+modify/delete' '
2255         test_setup_8c &&
2256         (
2257                 cd 8c &&
2258
2259                 git checkout A^0 &&
2260
2261                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2262                 test_i18ngrep "CONFLICT (modify/delete).* z/d" out &&
2263
2264                 git ls-files -s >out &&
2265                 test_line_count = 5 out &&
2266                 git ls-files -u >out &&
2267                 test_line_count = 2 out &&
2268                 git ls-files -o >out &&
2269                 test_line_count = 1 out &&
2270
2271                 git rev-parse >actual \
2272                         :0:y/b :0:y/c :0:y/e :1:z/d :3:z/d &&
2273                 git rev-parse >expect \
2274                          O:z/b  O:z/c  B:z/e  O:z/d  B:z/d &&
2275                 test_cmp expect actual &&
2276
2277                 test_must_fail git rev-parse :2:z/d &&
2278                 git ls-files -s z/d | grep ^100755 &&
2279                 test_path_is_file z/d &&
2280                 test_path_is_missing y/d
2281         )
2282 '
2283
2284 # Testcase 8d, rename/delete...or not?
2285 #   (Related to testcase 5b; these may appear slightly inconsistent to users;
2286 #    Also related to testcases 7d and 7e)
2287 #   Commit O: z/{b,c,d}
2288 #   Commit A: y/{b,c}
2289 #   Commit B: z/{b,c,d,e}
2290 #   Expected: y/{b,c,e}
2291 #
2292 #   Note: It would also be somewhat reasonable to resolve this as
2293 #             y/{b,c,e}, CONFLICT(rename/delete: x/d -> y/d or deleted)
2294 #
2295 #   In this case, I'm leaning towards: commit A was the one that deleted z/d
2296 #   and it did the rename of z to y, so the two "conflicts" (rename vs.
2297 #   delete) are both coming from commit A, which is illogical.  Conflicts
2298 #   during merging are supposed to be about opposite sides doing things
2299 #   differently.
2300
2301 test_setup_8d () {
2302         test_create_repo 8d &&
2303         (
2304                 cd 8d &&
2305
2306                 mkdir z &&
2307                 echo b >z/b &&
2308                 echo c >z/c &&
2309                 test_seq 1 10 >z/d &&
2310                 git add z &&
2311                 test_tick &&
2312                 git commit -m "O" &&
2313
2314                 git branch O &&
2315                 git branch A &&
2316                 git branch B &&
2317
2318                 git checkout A &&
2319                 git rm z/d &&
2320                 git mv z y &&
2321                 test_tick &&
2322                 git commit -m "A" &&
2323
2324                 git checkout B &&
2325                 echo e >z/e &&
2326                 git add z/e &&
2327                 test_tick &&
2328                 git commit -m "B"
2329         )
2330 }
2331
2332 test_expect_success '8d: rename/delete...or not?' '
2333         test_setup_8d &&
2334         (
2335                 cd 8d &&
2336
2337                 git checkout A^0 &&
2338
2339                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2340
2341                 git ls-files -s >out &&
2342                 test_line_count = 3 out &&
2343
2344                 git rev-parse >actual \
2345                         HEAD:y/b HEAD:y/c HEAD:y/e &&
2346                 git rev-parse >expect \
2347                         O:z/b    O:z/c    B:z/e &&
2348                 test_cmp expect actual
2349         )
2350 '
2351
2352 # Testcase 8e, Both sides rename, one side adds to original directory
2353 #   Commit O: z/{b,c}
2354 #   Commit A: y/{b,c}
2355 #   Commit B: w/{b,c}, z/d
2356 #
2357 # Possible Resolutions:
2358 #   if z not considered renamed: z/d, CONFLICT(z/b -> y/b vs. w/b),
2359 #                                     CONFLICT(z/c -> y/c vs. w/c)
2360 #   if z->y rename considered:   y/d, CONFLICT(z/b -> y/b vs. w/b),
2361 #                                     CONFLICT(z/c -> y/c vs. w/c)
2362 #   Optimal:                     ??
2363 #
2364 # Notes: In commit A, directory z got renamed to y.  In commit B, directory z
2365 #        did NOT get renamed; the directory is still present; instead it is
2366 #        considered to have just renamed a subset of paths in directory z
2367 #        elsewhere.  This is much like testcase 6b2 (where commit B moves all
2368 #        the original paths out of z/ but opted to keep d within z/).
2369 #
2370 #        It was not clear in the past what should be done with this testcase;
2371 #        in fact, I noted that I "just picked one" previously.  However,
2372 #        following the new logic for testcase 6b2, we should take the rename
2373 #        and move z/d to y/d.
2374 #
2375 #        6b1, 6b2, and this case are definitely somewhat fuzzy in terms of
2376 #        whether they are optimal for end users, but (a) the default for
2377 #        directory rename detection is to mark these all as conflicts
2378 #        anyway, (b) it feels like this is less prone to higher order corner
2379 #        case confusion, and (c) the current algorithm requires less global
2380 #        knowledge (i.e. less coupling in the algorithm between renames done
2381 #        on both sides) which thus means users are better able to predict
2382 #        the behavior, and predict it without computing as many details.
2383
2384 test_setup_8e () {
2385         test_create_repo 8e &&
2386         (
2387                 cd 8e &&
2388
2389                 mkdir z &&
2390                 echo b >z/b &&
2391                 echo c >z/c &&
2392                 git add z &&
2393                 test_tick &&
2394                 git commit -m "O" &&
2395
2396                 git branch O &&
2397                 git branch A &&
2398                 git branch B &&
2399
2400                 git checkout A &&
2401                 git mv z y &&
2402                 test_tick &&
2403                 git commit -m "A" &&
2404
2405                 git checkout B &&
2406                 git mv z w &&
2407                 mkdir z &&
2408                 echo d >z/d &&
2409                 git add z/d &&
2410                 test_tick &&
2411                 git commit -m "B"
2412         )
2413 }
2414
2415 test_expect_success '8e: Both sides rename, one side adds to original directory' '
2416         test_setup_8e &&
2417         (
2418                 cd 8e &&
2419
2420                 git checkout A^0 &&
2421
2422                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
2423                 test_i18ngrep CONFLICT.*rename/rename.*z/c.*y/c.*w/c out &&
2424                 test_i18ngrep CONFLICT.*rename/rename.*z/b.*y/b.*w/b out &&
2425
2426                 git ls-files -s >out &&
2427                 test_line_count = 7 out &&
2428                 git ls-files -u >out &&
2429                 test_line_count = 6 out &&
2430                 git ls-files -o >out &&
2431                 test_line_count = 2 out &&
2432
2433                 git rev-parse >actual \
2434                         :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:w/c :0:y/d &&
2435                 git rev-parse >expect \
2436                          O:z/b  O:z/b  O:z/b  O:z/c  O:z/c  O:z/c  B:z/d &&
2437                 test_cmp expect actual &&
2438
2439                 git hash-object >actual \
2440                         y/b   w/b   y/c   w/c &&
2441                 git rev-parse >expect \
2442                         O:z/b O:z/b O:z/c O:z/c &&
2443                 test_cmp expect actual &&
2444
2445                 test_path_is_missing z/b &&
2446                 test_path_is_missing z/c
2447         )
2448 '
2449
2450 ###########################################################################
2451 # SECTION 9: Other testcases
2452 #
2453 # This section consists of miscellaneous testcases I thought of during
2454 # the implementation which round out the testing.
2455 ###########################################################################
2456
2457 # Testcase 9a, Inner renamed directory within outer renamed directory
2458 #   (Related to testcase 1f)
2459 #   Commit O: z/{b,c,d/{e,f,g}}
2460 #   Commit A: y/{b,c}, x/w/{e,f,g}
2461 #   Commit B: z/{b,c,d/{e,f,g,h},i}
2462 #   Expected: y/{b,c,i}, x/w/{e,f,g,h}
2463 #   NOTE: The only reason this one is interesting is because when a directory
2464 #         is split into multiple other directories, we determine by the weight
2465 #         of which one had the most paths going to it.  A naive implementation
2466 #         of that could take the new file in commit B at z/i to x/w/i or x/i.
2467
2468 test_setup_9a () {
2469         test_create_repo 9a &&
2470         (
2471                 cd 9a &&
2472
2473                 mkdir -p z/d &&
2474                 echo b >z/b &&
2475                 echo c >z/c &&
2476                 echo e >z/d/e &&
2477                 echo f >z/d/f &&
2478                 echo g >z/d/g &&
2479                 git add z &&
2480                 test_tick &&
2481                 git commit -m "O" &&
2482
2483                 git branch O &&
2484                 git branch A &&
2485                 git branch B &&
2486
2487                 git checkout A &&
2488                 mkdir x &&
2489                 git mv z/d x/w &&
2490                 git mv z y &&
2491                 test_tick &&
2492                 git commit -m "A" &&
2493
2494                 git checkout B &&
2495                 echo h >z/d/h &&
2496                 echo i >z/i &&
2497                 git add z &&
2498                 test_tick &&
2499                 git commit -m "B"
2500         )
2501 }
2502
2503 test_expect_success '9a: Inner renamed directory within outer renamed directory' '
2504         test_setup_9a &&
2505         (
2506                 cd 9a &&
2507
2508                 git checkout A^0 &&
2509
2510                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2511
2512                 git ls-files -s >out &&
2513                 test_line_count = 7 out &&
2514                 git ls-files -u >out &&
2515                 test_line_count = 0 out &&
2516                 git ls-files -o >out &&
2517                 test_line_count = 1 out &&
2518
2519                 git rev-parse >actual \
2520                         HEAD:y/b HEAD:y/c HEAD:y/i &&
2521                 git rev-parse >expect \
2522                         O:z/b    O:z/c    B:z/i &&
2523                 test_cmp expect actual &&
2524
2525                 git rev-parse >actual \
2526                         HEAD:x/w/e HEAD:x/w/f HEAD:x/w/g HEAD:x/w/h &&
2527                 git rev-parse >expect \
2528                         O:z/d/e    O:z/d/f    O:z/d/g    B:z/d/h &&
2529                 test_cmp expect actual
2530         )
2531 '
2532
2533 # Testcase 9b, Transitive rename with content merge
2534 #   (Related to testcase 1c)
2535 #   Commit O: z/{b,c},   x/d_1
2536 #   Commit A: y/{b,c},   x/d_2
2537 #   Commit B: z/{b,c,d_3}
2538 #   Expected: y/{b,c,d_merged}
2539
2540 test_setup_9b () {
2541         test_create_repo 9b &&
2542         (
2543                 cd 9b &&
2544
2545                 mkdir z &&
2546                 echo b >z/b &&
2547                 echo c >z/c &&
2548                 mkdir x &&
2549                 test_seq 1 10 >x/d &&
2550                 git add z x &&
2551                 test_tick &&
2552                 git commit -m "O" &&
2553
2554                 git branch O &&
2555                 git branch A &&
2556                 git branch B &&
2557
2558                 git checkout A &&
2559                 git mv z y &&
2560                 test_seq 1 11 >x/d &&
2561                 git add x/d &&
2562                 test_tick &&
2563                 git commit -m "A" &&
2564
2565                 git checkout B &&
2566                 test_seq 0 10 >x/d &&
2567                 git mv x/d z/d &&
2568                 git add z/d &&
2569                 test_tick &&
2570                 git commit -m "B"
2571         )
2572 }
2573
2574 test_expect_success '9b: Transitive rename with content merge' '
2575         test_setup_9b &&
2576         (
2577                 cd 9b &&
2578
2579                 git checkout A^0 &&
2580
2581                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2582
2583                 git ls-files -s >out &&
2584                 test_line_count = 3 out &&
2585
2586                 test_seq 0 11 >expected &&
2587                 test_cmp expected y/d &&
2588                 git add expected &&
2589                 git rev-parse >actual \
2590                         HEAD:y/b HEAD:y/c HEAD:y/d &&
2591                 git rev-parse >expect \
2592                         O:z/b    O:z/c    :0:expected &&
2593                 test_cmp expect actual &&
2594                 test_must_fail git rev-parse HEAD:x/d &&
2595                 test_must_fail git rev-parse HEAD:z/d &&
2596                 test_path_is_missing z/d &&
2597
2598                 test $(git rev-parse HEAD:y/d) != $(git rev-parse O:x/d) &&
2599                 test $(git rev-parse HEAD:y/d) != $(git rev-parse A:x/d) &&
2600                 test $(git rev-parse HEAD:y/d) != $(git rev-parse B:z/d)
2601         )
2602 '
2603
2604 # Testcase 9c, Doubly transitive rename?
2605 #   (Related to testcase 1c, 7e, and 9d)
2606 #   Commit O: z/{b,c},     x/{d,e},    w/f
2607 #   Commit A: y/{b,c},     x/{d,e,f,g}
2608 #   Commit B: z/{b,c,d,e},             w/f
2609 #   Expected: y/{b,c,d,e}, x/{f,g}
2610 #
2611 #   NOTE: x/f and x/g may be slightly confusing here.  The rename from w/f to
2612 #         x/f is clear.  Let's look beyond that.  Here's the logic:
2613 #            Commit B renamed x/ -> z/
2614 #            Commit A renamed z/ -> y/
2615 #         So, we could possibly further rename x/f to z/f to y/f, a doubly
2616 #         transient rename.  However, where does it end?  We can chain these
2617 #         indefinitely (see testcase 9d).  What if there is a D/F conflict
2618 #         at z/f/ or y/f/?  Or just another file conflict at one of those
2619 #         paths?  In the case of an N-long chain of transient renamings,
2620 #         where do we "abort" the rename at?  Can the user make sense of
2621 #         the resulting conflict and resolve it?
2622 #
2623 #         To avoid this confusion I use the simple rule that if the other side
2624 #         of history did a directory rename to a path that your side renamed
2625 #         away, then ignore that particular rename from the other side of
2626 #         history for any implicit directory renames.
2627
2628 test_setup_9c () {
2629         test_create_repo 9c &&
2630         (
2631                 cd 9c &&
2632
2633                 mkdir z &&
2634                 echo b >z/b &&
2635                 echo c >z/c &&
2636                 mkdir x &&
2637                 echo d >x/d &&
2638                 echo e >x/e &&
2639                 mkdir w &&
2640                 echo f >w/f &&
2641                 git add z x w &&
2642                 test_tick &&
2643                 git commit -m "O" &&
2644
2645                 git branch O &&
2646                 git branch A &&
2647                 git branch B &&
2648
2649                 git checkout A &&
2650                 git mv z y &&
2651                 git mv w/f x/ &&
2652                 echo g >x/g &&
2653                 git add x/g &&
2654                 test_tick &&
2655                 git commit -m "A" &&
2656
2657                 git checkout B &&
2658                 git mv x/d z/d &&
2659                 git mv x/e z/e &&
2660                 test_tick &&
2661                 git commit -m "B"
2662         )
2663 }
2664
2665 test_expect_success '9c: Doubly transitive rename?' '
2666         test_setup_9c &&
2667         (
2668                 cd 9c &&
2669
2670                 git checkout A^0 &&
2671
2672                 git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2673                 test_i18ngrep "WARNING: Avoiding applying x -> z rename to x/f" out &&
2674
2675                 git ls-files -s >out &&
2676                 test_line_count = 6 out &&
2677                 git ls-files -o >out &&
2678                 test_line_count = 1 out &&
2679
2680                 git rev-parse >actual \
2681                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e HEAD:x/f HEAD:x/g &&
2682                 git rev-parse >expect \
2683                         O:z/b    O:z/c    O:x/d    O:x/e    O:w/f    A:x/g &&
2684                 test_cmp expect actual
2685         )
2686 '
2687
2688 # Testcase 9d, N-fold transitive rename?
2689 #   (Related to testcase 9c...and 1c and 7e)
2690 #   Commit O: z/a, y/b, x/c, w/d, v/e, u/f
2691 #   Commit A:  y/{a,b},  w/{c,d},  u/{e,f}
2692 #   Commit B: z/{a,t}, x/{b,c}, v/{d,e}, u/f
2693 #   Expected: <see NOTE first>
2694 #
2695 #   NOTE: z/ -> y/ (in commit A)
2696 #         y/ -> x/ (in commit B)
2697 #         x/ -> w/ (in commit A)
2698 #         w/ -> v/ (in commit B)
2699 #         v/ -> u/ (in commit A)
2700 #         So, if we add a file to z, say z/t, where should it end up?  In u?
2701 #         What if there's another file or directory named 't' in one of the
2702 #         intervening directories and/or in u itself?  Also, shouldn't the
2703 #         same logic that places 't' in u/ also move ALL other files to u/?
2704 #         What if there are file or directory conflicts in any of them?  If
2705 #         we attempted to do N-way (N-fold? N-ary? N-uple?) transitive renames
2706 #         like this, would the user have any hope of understanding any
2707 #         conflicts or how their working tree ended up?  I think not, so I'm
2708 #         ruling out N-ary transitive renames for N>1.
2709 #
2710 #   Therefore our expected result is:
2711 #     z/t, y/a, x/b, w/c, u/d, u/e, u/f
2712 #   The reason that v/d DOES get transitively renamed to u/d is that u/ isn't
2713 #   renamed somewhere.  A slightly sub-optimal result, but it uses fairly
2714 #   simple rules that are consistent with what we need for all the other
2715 #   testcases and simplifies things for the user.
2716
2717 test_setup_9d () {
2718         test_create_repo 9d &&
2719         (
2720                 cd 9d &&
2721
2722                 mkdir z y x w v u &&
2723                 echo a >z/a &&
2724                 echo b >y/b &&
2725                 echo c >x/c &&
2726                 echo d >w/d &&
2727                 echo e >v/e &&
2728                 echo f >u/f &&
2729                 git add z y x w v u &&
2730                 test_tick &&
2731                 git commit -m "O" &&
2732
2733                 git branch O &&
2734                 git branch A &&
2735                 git branch B &&
2736
2737                 git checkout A &&
2738                 git mv z/a y/ &&
2739                 git mv x/c w/ &&
2740                 git mv v/e u/ &&
2741                 test_tick &&
2742                 git commit -m "A" &&
2743
2744                 git checkout B &&
2745                 echo t >z/t &&
2746                 git mv y/b x/ &&
2747                 git mv w/d v/ &&
2748                 git add z/t &&
2749                 test_tick &&
2750                 git commit -m "B"
2751         )
2752 }
2753
2754 test_expect_success '9d: N-way transitive rename?' '
2755         test_setup_9d &&
2756         (
2757                 cd 9d &&
2758
2759                 git checkout A^0 &&
2760
2761                 git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2762                 test_i18ngrep "WARNING: Avoiding applying z -> y rename to z/t" out &&
2763                 test_i18ngrep "WARNING: Avoiding applying y -> x rename to y/a" out &&
2764                 test_i18ngrep "WARNING: Avoiding applying x -> w rename to x/b" out &&
2765                 test_i18ngrep "WARNING: Avoiding applying w -> v rename to w/c" out &&
2766
2767                 git ls-files -s >out &&
2768                 test_line_count = 7 out &&
2769                 git ls-files -o >out &&
2770                 test_line_count = 1 out &&
2771
2772                 git rev-parse >actual \
2773                         HEAD:z/t \
2774                         HEAD:y/a HEAD:x/b HEAD:w/c \
2775                         HEAD:u/d HEAD:u/e HEAD:u/f &&
2776                 git rev-parse >expect \
2777                         B:z/t    \
2778                         O:z/a    O:y/b    O:x/c    \
2779                         O:w/d    O:v/e    A:u/f &&
2780                 test_cmp expect actual
2781         )
2782 '
2783
2784 # Testcase 9e, N-to-1 whammo
2785 #   (Related to testcase 9c...and 1c and 7e)
2786 #   Commit O: dir1/{a,b}, dir2/{d,e}, dir3/{g,h}, dirN/{j,k}
2787 #   Commit A: dir1/{a,b,c,yo}, dir2/{d,e,f,yo}, dir3/{g,h,i,yo}, dirN/{j,k,l,yo}
2788 #   Commit B: combined/{a,b,d,e,g,h,j,k}
2789 #   Expected: combined/{a,b,c,d,e,f,g,h,i,j,k,l}, CONFLICT(Nto1) warnings,
2790 #             dir1/yo, dir2/yo, dir3/yo, dirN/yo
2791
2792 test_setup_9e () {
2793         test_create_repo 9e &&
2794         (
2795                 cd 9e &&
2796
2797                 mkdir dir1 dir2 dir3 dirN &&
2798                 echo a >dir1/a &&
2799                 echo b >dir1/b &&
2800                 echo d >dir2/d &&
2801                 echo e >dir2/e &&
2802                 echo g >dir3/g &&
2803                 echo h >dir3/h &&
2804                 echo j >dirN/j &&
2805                 echo k >dirN/k &&
2806                 git add dir* &&
2807                 test_tick &&
2808                 git commit -m "O" &&
2809
2810                 git branch O &&
2811                 git branch A &&
2812                 git branch B &&
2813
2814                 git checkout A &&
2815                 echo c  >dir1/c &&
2816                 echo yo >dir1/yo &&
2817                 echo f  >dir2/f &&
2818                 echo yo >dir2/yo &&
2819                 echo i  >dir3/i &&
2820                 echo yo >dir3/yo &&
2821                 echo l  >dirN/l &&
2822                 echo yo >dirN/yo &&
2823                 git add dir* &&
2824                 test_tick &&
2825                 git commit -m "A" &&
2826
2827                 git checkout B &&
2828                 git mv dir1 combined &&
2829                 git mv dir2/* combined/ &&
2830                 git mv dir3/* combined/ &&
2831                 git mv dirN/* combined/ &&
2832                 test_tick &&
2833                 git commit -m "B"
2834         )
2835 }
2836
2837 test_expect_success C_LOCALE_OUTPUT '9e: N-to-1 whammo' '
2838         test_setup_9e &&
2839         (
2840                 cd 9e &&
2841
2842                 git checkout A^0 &&
2843
2844                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2845                 grep "CONFLICT (implicit dir rename): Cannot map more than one path to combined/yo" out >error_line &&
2846                 grep -q dir1/yo error_line &&
2847                 grep -q dir2/yo error_line &&
2848                 grep -q dir3/yo error_line &&
2849                 grep -q dirN/yo error_line &&
2850
2851                 git ls-files -s >out &&
2852                 test_line_count = 16 out &&
2853                 git ls-files -u >out &&
2854                 test_line_count = 0 out &&
2855                 git ls-files -o >out &&
2856                 test_line_count = 2 out &&
2857
2858                 git rev-parse >actual \
2859                         :0:combined/a :0:combined/b :0:combined/c \
2860                         :0:combined/d :0:combined/e :0:combined/f \
2861                         :0:combined/g :0:combined/h :0:combined/i \
2862                         :0:combined/j :0:combined/k :0:combined/l &&
2863                 git rev-parse >expect \
2864                          O:dir1/a      O:dir1/b      A:dir1/c \
2865                          O:dir2/d      O:dir2/e      A:dir2/f \
2866                          O:dir3/g      O:dir3/h      A:dir3/i \
2867                          O:dirN/j      O:dirN/k      A:dirN/l &&
2868                 test_cmp expect actual &&
2869
2870                 git rev-parse >actual \
2871                         :0:dir1/yo :0:dir2/yo :0:dir3/yo :0:dirN/yo &&
2872                 git rev-parse >expect \
2873                          A:dir1/yo  A:dir2/yo  A:dir3/yo  A:dirN/yo &&
2874                 test_cmp expect actual
2875         )
2876 '
2877
2878 # Testcase 9f, Renamed directory that only contained immediate subdirs
2879 #   (Related to testcases 1e & 9g)
2880 #   Commit O: goal/{a,b}/$more_files
2881 #   Commit A: priority/{a,b}/$more_files
2882 #   Commit B: goal/{a,b}/$more_files, goal/c
2883 #   Expected: priority/{a,b}/$more_files, priority/c
2884
2885 test_setup_9f () {
2886         test_create_repo 9f &&
2887         (
2888                 cd 9f &&
2889
2890                 mkdir -p goal/a &&
2891                 mkdir -p goal/b &&
2892                 echo foo >goal/a/foo &&
2893                 echo bar >goal/b/bar &&
2894                 echo baz >goal/b/baz &&
2895                 git add goal &&
2896                 test_tick &&
2897                 git commit -m "O" &&
2898
2899                 git branch O &&
2900                 git branch A &&
2901                 git branch B &&
2902
2903                 git checkout A &&
2904                 git mv goal/ priority &&
2905                 test_tick &&
2906                 git commit -m "A" &&
2907
2908                 git checkout B &&
2909                 echo c >goal/c &&
2910                 git add goal/c &&
2911                 test_tick &&
2912                 git commit -m "B"
2913         )
2914 }
2915
2916 test_expect_success '9f: Renamed directory that only contained immediate subdirs' '
2917         test_setup_9f &&
2918         (
2919                 cd 9f &&
2920
2921                 git checkout A^0 &&
2922
2923                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2924
2925                 git ls-files -s >out &&
2926                 test_line_count = 4 out &&
2927
2928                 git rev-parse >actual \
2929                         HEAD:priority/a/foo \
2930                         HEAD:priority/b/bar \
2931                         HEAD:priority/b/baz \
2932                         HEAD:priority/c &&
2933                 git rev-parse >expect \
2934                         O:goal/a/foo \
2935                         O:goal/b/bar \
2936                         O:goal/b/baz \
2937                         B:goal/c &&
2938                 test_cmp expect actual &&
2939                 test_must_fail git rev-parse HEAD:goal/c
2940         )
2941 '
2942
2943 # Testcase 9g, Renamed directory that only contained immediate subdirs, immediate subdirs renamed
2944 #   (Related to testcases 1e & 9f)
2945 #   Commit O: goal/{a,b}/$more_files
2946 #   Commit A: priority/{alpha,bravo}/$more_files
2947 #   Commit B: goal/{a,b}/$more_files, goal/c
2948 #   Expected: priority/{alpha,bravo}/$more_files, priority/c
2949 # We currently fail this test because the directory renames we detect are
2950 #   goal/a/ -> priority/alpha/
2951 #   goal/b/ -> priority/bravo/
2952 # We do not detect
2953 #   goal/   -> priority/
2954 # because of no files found within goal/, and the fact that "a" != "alpha"
2955 # and "b" != "bravo".  But I'm not sure it's really a failure given that
2956 # viewpoint...
2957
2958 test_setup_9g () {
2959         test_create_repo 9g &&
2960         (
2961                 cd 9g &&
2962
2963                 mkdir -p goal/a &&
2964                 mkdir -p goal/b &&
2965                 echo foo >goal/a/foo &&
2966                 echo bar >goal/b/bar &&
2967                 echo baz >goal/b/baz &&
2968                 git add goal &&
2969                 test_tick &&
2970                 git commit -m "O" &&
2971
2972                 git branch O &&
2973                 git branch A &&
2974                 git branch B &&
2975
2976                 git checkout A &&
2977                 mkdir priority &&
2978                 git mv goal/a/ priority/alpha &&
2979                 git mv goal/b/ priority/beta &&
2980                 rmdir goal/ &&
2981                 test_tick &&
2982                 git commit -m "A" &&
2983
2984                 git checkout B &&
2985                 echo c >goal/c &&
2986                 git add goal/c &&
2987                 test_tick &&
2988                 git commit -m "B"
2989         )
2990 }
2991
2992 test_expect_failure '9g: Renamed directory that only contained immediate subdirs, immediate subdirs renamed' '
2993         test_setup_9g &&
2994         (
2995                 cd 9g &&
2996
2997                 git checkout A^0 &&
2998
2999                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
3000
3001                 git ls-files -s >out &&
3002                 test_line_count = 4 out &&
3003
3004                 git rev-parse >actual \
3005                         HEAD:priority/alpha/foo \
3006                         HEAD:priority/beta/bar  \
3007                         HEAD:priority/beta/baz  \
3008                         HEAD:priority/c &&
3009                 git rev-parse >expect \
3010                         O:goal/a/foo \
3011                         O:goal/b/bar \
3012                         O:goal/b/baz \
3013                         B:goal/c &&
3014                 test_cmp expect actual &&
3015                 test_must_fail git rev-parse HEAD:goal/c
3016         )
3017 '
3018
3019 # Testcase 9h, Avoid implicit rename if involved as source on other side
3020 #   (Extremely closely related to testcase 3a)
3021 #   Commit O: z/{b,c,d_1}
3022 #   Commit A: z/{b,c,d_2}
3023 #   Commit B: y/{b,c}, x/d_1
3024 #   Expected: y/{b,c}, x/d_2
3025 #   NOTE: If we applied the z/ -> y/ rename to z/d, then we'd end up with
3026 #         a rename/rename(1to2) conflict (z/d -> y/d vs. x/d)
3027 test_setup_9h () {
3028         test_create_repo 9h &&
3029         (
3030                 cd 9h &&
3031
3032                 mkdir z &&
3033                 echo b >z/b &&
3034                 echo c >z/c &&
3035                 printf "1\n2\n3\n4\n5\n6\n7\n8\nd\n" >z/d &&
3036                 git add z &&
3037                 test_tick &&
3038                 git commit -m "O" &&
3039
3040                 git branch O &&
3041                 git branch A &&
3042                 git branch B &&
3043
3044                 git checkout A &&
3045                 test_tick &&
3046                 echo more >>z/d &&
3047                 git add z/d &&
3048                 git commit -m "A" &&
3049
3050                 git checkout B &&
3051                 mkdir y &&
3052                 mkdir x &&
3053                 git mv z/b y/ &&
3054                 git mv z/c y/ &&
3055                 git mv z/d x/ &&
3056                 rmdir z &&
3057                 test_tick &&
3058                 git commit -m "B"
3059         )
3060 }
3061
3062 test_expect_success '9h: Avoid dir rename on merely modified path' '
3063         test_setup_9h &&
3064         (
3065                 cd 9h &&
3066
3067                 git checkout A^0 &&
3068
3069                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
3070
3071                 git ls-files -s >out &&
3072                 test_line_count = 3 out &&
3073
3074                 git rev-parse >actual \
3075                         HEAD:y/b HEAD:y/c HEAD:x/d &&
3076                 git rev-parse >expect \
3077                         O:z/b    O:z/c    A:z/d &&
3078                 test_cmp expect actual
3079         )
3080 '
3081
3082 ###########################################################################
3083 # Rules suggested by section 9:
3084 #
3085 #   If the other side of history did a directory rename to a path that your
3086 #   side renamed away, then ignore that particular rename from the other
3087 #   side of history for any implicit directory renames.
3088 ###########################################################################
3089
3090 ###########################################################################
3091 # SECTION 10: Handling untracked files
3092 #
3093 # unpack_trees(), upon which the recursive merge algorithm is based, aborts
3094 # the operation if untracked or dirty files would be deleted or overwritten
3095 # by the merge.  Unfortunately, unpack_trees() does not understand renames,
3096 # and if it doesn't abort, then it muddies up the working directory before
3097 # we even get to the point of detecting renames, so we need some special
3098 # handling, at least in the case of directory renames.
3099 ###########################################################################
3100
3101 # Testcase 10a, Overwrite untracked: normal rename/delete
3102 #   Commit O: z/{b,c_1}
3103 #   Commit A: z/b + untracked z/c + untracked z/d
3104 #   Commit B: z/{b,d_1}
3105 #   Expected: Aborted Merge +
3106 #       ERROR_MSG(untracked working tree files would be overwritten by merge)
3107
3108 test_setup_10a () {
3109         test_create_repo 10a &&
3110         (
3111                 cd 10a &&
3112
3113                 mkdir z &&
3114                 echo b >z/b &&
3115                 echo c >z/c &&
3116                 git add z &&
3117                 test_tick &&
3118                 git commit -m "O" &&
3119
3120                 git branch O &&
3121                 git branch A &&
3122                 git branch B &&
3123
3124                 git checkout A &&
3125                 git rm z/c &&
3126                 test_tick &&
3127                 git commit -m "A" &&
3128
3129                 git checkout B &&
3130                 git mv z/c z/d &&
3131                 test_tick &&
3132                 git commit -m "B"
3133         )
3134 }
3135
3136 test_expect_success '10a: Overwrite untracked with normal rename/delete' '
3137         test_setup_10a &&
3138         (
3139                 cd 10a &&
3140
3141                 git checkout A^0 &&
3142                 echo very >z/c &&
3143                 echo important >z/d &&
3144
3145                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3146                 test_i18ngrep "The following untracked working tree files would be overwritten by merge" err &&
3147
3148                 git ls-files -s >out &&
3149                 test_line_count = 1 out &&
3150                 git ls-files -o >out &&
3151                 test_line_count = 4 out &&
3152
3153                 echo very >expect &&
3154                 test_cmp expect z/c &&
3155
3156                 echo important >expect &&
3157                 test_cmp expect z/d &&
3158
3159                 git rev-parse HEAD:z/b >actual &&
3160                 git rev-parse O:z/b >expect &&
3161                 test_cmp expect actual
3162         )
3163 '
3164
3165 # Testcase 10b, Overwrite untracked: dir rename + delete
3166 #   Commit O: z/{b,c_1}
3167 #   Commit A: y/b + untracked y/{c,d,e}
3168 #   Commit B: z/{b,d_1,e}
3169 #   Expected: Failed Merge; y/b + untracked y/c + untracked y/d on disk +
3170 #             z/c_1 -> z/d_1 rename recorded at stage 3 for y/d +
3171 #       ERROR_MSG(refusing to lose untracked file at 'y/d')
3172
3173 test_setup_10b () {
3174         test_create_repo 10b &&
3175         (
3176                 cd 10b &&
3177
3178                 mkdir z &&
3179                 echo b >z/b &&
3180                 echo c >z/c &&
3181                 git add z &&
3182                 test_tick &&
3183                 git commit -m "O" &&
3184
3185                 git branch O &&
3186                 git branch A &&
3187                 git branch B &&
3188
3189                 git checkout A &&
3190                 git rm z/c &&
3191                 git mv z/ y/ &&
3192                 test_tick &&
3193                 git commit -m "A" &&
3194
3195                 git checkout B &&
3196                 git mv z/c z/d &&
3197                 echo e >z/e &&
3198                 git add z/e &&
3199                 test_tick &&
3200                 git commit -m "B"
3201         )
3202 }
3203
3204 test_expect_success '10b: Overwrite untracked with dir rename + delete' '
3205         test_setup_10b &&
3206         (
3207                 cd 10b &&
3208
3209                 git checkout A^0 &&
3210                 echo very >y/c &&
3211                 echo important >y/d &&
3212                 echo contents >y/e &&
3213
3214                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3215                 test_i18ngrep "CONFLICT (rename/delete).*Version B\^0 of y/d left in tree at y/d~B\^0" out &&
3216                 test_i18ngrep "Error: Refusing to lose untracked file at y/e; writing to y/e~B\^0 instead" out &&
3217
3218                 git ls-files -s >out &&
3219                 test_line_count = 3 out &&
3220                 git ls-files -u >out &&
3221                 test_line_count = 2 out &&
3222                 git ls-files -o >out &&
3223                 test_line_count = 5 out &&
3224
3225                 git rev-parse >actual \
3226                         :0:y/b :3:y/d :3:y/e &&
3227                 git rev-parse >expect \
3228                         O:z/b  O:z/c  B:z/e &&
3229                 test_cmp expect actual &&
3230
3231                 echo very >expect &&
3232                 test_cmp expect y/c &&
3233
3234                 echo important >expect &&
3235                 test_cmp expect y/d &&
3236
3237                 echo contents >expect &&
3238                 test_cmp expect y/e
3239         )
3240 '
3241
3242 # Testcase 10c, Overwrite untracked: dir rename/rename(1to2)
3243 #   Commit O: z/{a,b}, x/{c,d}
3244 #   Commit A: y/{a,b}, w/c, x/d + different untracked y/c
3245 #   Commit B: z/{a,b,c}, x/d
3246 #   Expected: Failed Merge; y/{a,b} + x/d + untracked y/c +
3247 #             CONFLICT(rename/rename) x/c -> w/c vs y/c +
3248 #             y/c~B^0 +
3249 #             ERROR_MSG(Refusing to lose untracked file at y/c)
3250
3251 test_setup_10c () {
3252         test_create_repo 10c_$1 &&
3253         (
3254                 cd 10c_$1 &&
3255
3256                 mkdir z x &&
3257                 echo a >z/a &&
3258                 echo b >z/b &&
3259                 echo c >x/c &&
3260                 echo d >x/d &&
3261                 git add z x &&
3262                 test_tick &&
3263                 git commit -m "O" &&
3264
3265                 git branch O &&
3266                 git branch A &&
3267                 git branch B &&
3268
3269                 git checkout A &&
3270                 mkdir w &&
3271                 git mv x/c w/c &&
3272                 git mv z/ y/ &&
3273                 test_tick &&
3274                 git commit -m "A" &&
3275
3276                 git checkout B &&
3277                 git mv x/c z/ &&
3278                 test_tick &&
3279                 git commit -m "B"
3280         )
3281 }
3282
3283 test_expect_success '10c1: Overwrite untracked with dir rename/rename(1to2)' '
3284         test_setup_10c 1 &&
3285         (
3286                 cd 10c_1 &&
3287
3288                 git checkout A^0 &&
3289                 echo important >y/c &&
3290
3291                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3292                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3293                 test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~B\^0 instead" out &&
3294
3295                 git ls-files -s >out &&
3296                 test_line_count = 6 out &&
3297                 git ls-files -u >out &&
3298                 test_line_count = 3 out &&
3299                 git ls-files -o >out &&
3300                 test_line_count = 3 out &&
3301
3302                 git rev-parse >actual \
3303                         :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :3:y/c &&
3304                 git rev-parse >expect \
3305                          O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&
3306                 test_cmp expect actual &&
3307
3308                 git hash-object y/c~B^0 >actual &&
3309                 git rev-parse O:x/c >expect &&
3310                 test_cmp expect actual &&
3311
3312                 echo important >expect &&
3313                 test_cmp expect y/c
3314         )
3315 '
3316
3317 test_expect_success '10c2: Overwrite untracked with dir rename/rename(1to2), other direction' '
3318         test_setup_10c 2 &&
3319         (
3320                 cd 10c_2 &&
3321
3322                 git reset --hard &&
3323                 git clean -fdqx &&
3324
3325                 git checkout B^0 &&
3326                 mkdir y &&
3327                 echo important >y/c &&
3328
3329                 test_must_fail git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
3330                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3331                 test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~HEAD instead" out &&
3332
3333                 git ls-files -s >out &&
3334                 test_line_count = 6 out &&
3335                 git ls-files -u >out &&
3336                 test_line_count = 3 out &&
3337                 git ls-files -o >out &&
3338                 test_line_count = 3 out &&
3339
3340                 git rev-parse >actual \
3341                         :0:y/a :0:y/b :0:x/d :1:x/c :3:w/c :2:y/c &&
3342                 git rev-parse >expect \
3343                          O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&
3344                 test_cmp expect actual &&
3345
3346                 git hash-object y/c~HEAD >actual &&
3347                 git rev-parse O:x/c >expect &&
3348                 test_cmp expect actual &&
3349
3350                 echo important >expect &&
3351                 test_cmp expect y/c
3352         )
3353 '
3354
3355 # Testcase 10d, Delete untracked w/ dir rename/rename(2to1)
3356 #   Commit O: z/{a,b,c_1},        x/{d,e,f_2}
3357 #   Commit A: y/{a,b},            x/{d,e,f_2,wham_1} + untracked y/wham
3358 #   Commit B: z/{a,b,c_1,wham_2}, y/{d,e}
3359 #   Expected: Failed Merge; y/{a,b,d,e} + untracked y/{wham,wham~merged}+
3360 #             CONFLICT(rename/rename) z/c_1 vs x/f_2 -> y/wham
3361 #             ERROR_MSG(Refusing to lose untracked file at y/wham)
3362
3363 test_setup_10d () {
3364         test_create_repo 10d &&
3365         (
3366                 cd 10d &&
3367
3368                 mkdir z x &&
3369                 echo a >z/a &&
3370                 echo b >z/b &&
3371                 echo c >z/c &&
3372                 echo d >x/d &&
3373                 echo e >x/e &&
3374                 echo f >x/f &&
3375                 git add z x &&
3376                 test_tick &&
3377                 git commit -m "O" &&
3378
3379                 git branch O &&
3380                 git branch A &&
3381                 git branch B &&
3382
3383                 git checkout A &&
3384                 git mv z/c x/wham &&
3385                 git mv z/ y/ &&
3386                 test_tick &&
3387                 git commit -m "A" &&
3388
3389                 git checkout B &&
3390                 git mv x/f z/wham &&
3391                 git mv x/ y/ &&
3392                 test_tick &&
3393                 git commit -m "B"
3394         )
3395 }
3396
3397 test_expect_success '10d: Delete untracked with dir rename/rename(2to1)' '
3398         test_setup_10d &&
3399         (
3400                 cd 10d &&
3401
3402                 git checkout A^0 &&
3403                 echo important >y/wham &&
3404
3405                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3406                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3407                 test_i18ngrep "Refusing to lose untracked file at y/wham" out &&
3408
3409                 git ls-files -s >out &&
3410                 test_line_count = 6 out &&
3411                 git ls-files -u >out &&
3412                 test_line_count = 2 out &&
3413                 git ls-files -o >out &&
3414                 test_line_count = 3 out &&
3415
3416                 git rev-parse >actual \
3417                         :0:y/a :0:y/b :0:y/d :0:y/e :2:y/wham :3:y/wham &&
3418                 git rev-parse >expect \
3419                          O:z/a  O:z/b  O:x/d  O:x/e  O:z/c     O:x/f &&
3420                 test_cmp expect actual &&
3421
3422                 test_must_fail git rev-parse :1:y/wham &&
3423
3424                 echo important >expect &&
3425                 test_cmp expect y/wham &&
3426
3427                 # Test that the two-way merge in y/wham~merged is as expected
3428                 git cat-file -p :2:y/wham >expect &&
3429                 git cat-file -p :3:y/wham >other &&
3430                 >empty &&
3431                 test_must_fail git merge-file \
3432                         -L "HEAD" \
3433                         -L "" \
3434                         -L "B^0" \
3435                         expect empty other &&
3436                 test_cmp expect y/wham~merged
3437         )
3438 '
3439
3440 # Testcase 10e, Does git complain about untracked file that's not in the way?
3441 #   Commit O: z/{a,b}
3442 #   Commit A: y/{a,b} + untracked z/c
3443 #   Commit B: z/{a,b,c}
3444 #   Expected: y/{a,b,c} + untracked z/c
3445
3446 test_setup_10e () {
3447         test_create_repo 10e &&
3448         (
3449                 cd 10e &&
3450
3451                 mkdir z &&
3452                 echo a >z/a &&
3453                 echo b >z/b &&
3454                 git add z &&
3455                 test_tick &&
3456                 git commit -m "O" &&
3457
3458                 git branch O &&
3459                 git branch A &&
3460                 git branch B &&
3461
3462                 git checkout A &&
3463                 git mv z/ y/ &&
3464                 test_tick &&
3465                 git commit -m "A" &&
3466
3467                 git checkout B &&
3468                 echo c >z/c &&
3469                 git add z/c &&
3470                 test_tick &&
3471                 git commit -m "B"
3472         )
3473 }
3474
3475 test_expect_merge_algorithm failure success '10e: Does git complain about untracked file that is not really in the way?' '
3476         test_setup_10e &&
3477         (
3478                 cd 10e &&
3479
3480                 git checkout A^0 &&
3481                 mkdir z &&
3482                 echo random >z/c &&
3483
3484                 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3485                 test_i18ngrep ! "following untracked working tree files would be overwritten by merge" err &&
3486
3487                 git ls-files -s >out &&
3488                 test_line_count = 3 out &&
3489                 git ls-files -u >out &&
3490                 test_line_count = 0 out &&
3491                 git ls-files -o >out &&
3492                 test_line_count = 3 out &&
3493
3494                 git rev-parse >actual \
3495                         :0:y/a :0:y/b :0:y/c &&
3496                 git rev-parse >expect \
3497                          O:z/a  O:z/b  B:z/c &&
3498                 test_cmp expect actual &&
3499
3500                 echo random >expect &&
3501                 test_cmp expect z/c
3502         )
3503 '
3504
3505 ###########################################################################
3506 # SECTION 11: Handling dirty (not up-to-date) files
3507 #
3508 # unpack_trees(), upon which the recursive merge algorithm is based, aborts
3509 # the operation if untracked or dirty files would be deleted or overwritten
3510 # by the merge.  Unfortunately, unpack_trees() does not understand renames,
3511 # and if it doesn't abort, then it muddies up the working directory before
3512 # we even get to the point of detecting renames, so we need some special
3513 # handling.  This was true even of normal renames, but there are additional
3514 # codepaths that need special handling with directory renames.  Add
3515 # testcases for both renamed-by-directory-rename-detection and standard
3516 # rename cases.
3517 ###########################################################################
3518
3519 # Testcase 11a, Avoid losing dirty contents with simple rename
3520 #   Commit O: z/{a,b_v1},
3521 #   Commit A: z/{a,c_v1}, and z/c_v1 has uncommitted mods
3522 #   Commit B: z/{a,b_v2}
3523 #   Expected: ERROR_MSG(Refusing to lose dirty file at z/c) +
3524 #             z/a, staged version of z/c has sha1sum matching B:z/b_v2,
3525 #             z/c~HEAD with contents of B:z/b_v2,
3526 #             z/c with uncommitted mods on top of A:z/c_v1
3527
3528 test_setup_11a () {
3529         test_create_repo 11a &&
3530         (
3531                 cd 11a &&
3532
3533                 mkdir z &&
3534                 echo a >z/a &&
3535                 test_seq 1 10 >z/b &&
3536                 git add z &&
3537                 test_tick &&
3538                 git commit -m "O" &&
3539
3540                 git branch O &&
3541                 git branch A &&
3542                 git branch B &&
3543
3544                 git checkout A &&
3545                 git mv z/b z/c &&
3546                 test_tick &&
3547                 git commit -m "A" &&
3548
3549                 git checkout B &&
3550                 echo 11 >>z/b &&
3551                 git add z/b &&
3552                 test_tick &&
3553                 git commit -m "B"
3554         )
3555 }
3556
3557 test_expect_success '11a: Avoid losing dirty contents with simple rename' '
3558         test_setup_11a &&
3559         (
3560                 cd 11a &&
3561
3562                 git checkout A^0 &&
3563                 echo stuff >>z/c &&
3564
3565                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3566                 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3567
3568                 test_seq 1 10 >expected &&
3569                 echo stuff >>expected &&
3570                 test_cmp expected z/c &&
3571
3572                 git ls-files -s >out &&
3573                 test_line_count = 2 out &&
3574                 git ls-files -u >out &&
3575                 test_line_count = 1 out &&
3576                 git ls-files -o >out &&
3577                 test_line_count = 4 out &&
3578
3579                 git rev-parse >actual \
3580                         :0:z/a :2:z/c &&
3581                 git rev-parse >expect \
3582                          O:z/a  B:z/b &&
3583                 test_cmp expect actual &&
3584
3585                 git hash-object z/c~HEAD >actual &&
3586                 git rev-parse B:z/b >expect &&
3587                 test_cmp expect actual
3588         )
3589 '
3590
3591 # Testcase 11b, Avoid losing dirty file involved in directory rename
3592 #   Commit O: z/a,         x/{b,c_v1}
3593 #   Commit A: z/{a,c_v1},  x/b,       and z/c_v1 has uncommitted mods
3594 #   Commit B: y/a,         x/{b,c_v2}
3595 #   Expected: y/{a,c_v2}, x/b, z/c_v1 with uncommitted mods untracked,
3596 #             ERROR_MSG(Refusing to lose dirty file at z/c)
3597
3598
3599 test_setup_11b () {
3600         test_create_repo 11b &&
3601         (
3602                 cd 11b &&
3603
3604                 mkdir z x &&
3605                 echo a >z/a &&
3606                 echo b >x/b &&
3607                 test_seq 1 10 >x/c &&
3608                 git add z x &&
3609                 test_tick &&
3610                 git commit -m "O" &&
3611
3612                 git branch O &&
3613                 git branch A &&
3614                 git branch B &&
3615
3616                 git checkout A &&
3617                 git mv x/c z/c &&
3618                 test_tick &&
3619                 git commit -m "A" &&
3620
3621                 git checkout B &&
3622                 git mv z y &&
3623                 echo 11 >>x/c &&
3624                 git add x/c &&
3625                 test_tick &&
3626                 git commit -m "B"
3627         )
3628 }
3629
3630 test_expect_success '11b: Avoid losing dirty file involved in directory rename' '
3631         test_setup_11b &&
3632         (
3633                 cd 11b &&
3634
3635                 git checkout A^0 &&
3636                 echo stuff >>z/c &&
3637
3638                 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3639                 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3640
3641                 grep -q stuff z/c &&
3642                 test_seq 1 10 >expected &&
3643                 echo stuff >>expected &&
3644                 test_cmp expected z/c &&
3645
3646                 git ls-files -s >out &&
3647                 test_line_count = 3 out &&
3648                 git ls-files -u >out &&
3649                 test_line_count = 0 out &&
3650                 git ls-files -m >out &&
3651                 test_line_count = 0 out &&
3652                 git ls-files -o >out &&
3653                 test_line_count = 4 out &&
3654
3655                 git rev-parse >actual \
3656                         :0:x/b :0:y/a :0:y/c &&
3657                 git rev-parse >expect \
3658                          O:x/b  O:z/a  B:x/c &&
3659                 test_cmp expect actual &&
3660
3661                 git hash-object y/c >actual &&
3662                 git rev-parse B:x/c >expect &&
3663                 test_cmp expect actual
3664         )
3665 '
3666
3667 # Testcase 11c, Avoid losing not-up-to-date with rename + D/F conflict
3668 #   Commit O: y/a,         x/{b,c_v1}
3669 #   Commit A: y/{a,c_v1},  x/b,       and y/c_v1 has uncommitted mods
3670 #   Commit B: y/{a,c/d},   x/{b,c_v2}
3671 #   Expected: Abort_msg("following files would be overwritten by merge") +
3672 #             y/c left untouched (still has uncommitted mods)
3673
3674 test_setup_11c () {
3675         test_create_repo 11c &&
3676         (
3677                 cd 11c &&
3678
3679                 mkdir y x &&
3680                 echo a >y/a &&
3681                 echo b >x/b &&
3682                 test_seq 1 10 >x/c &&
3683                 git add y x &&
3684                 test_tick &&
3685                 git commit -m "O" &&
3686
3687                 git branch O &&
3688                 git branch A &&
3689                 git branch B &&
3690
3691                 git checkout A &&
3692                 git mv x/c y/c &&
3693                 test_tick &&
3694                 git commit -m "A" &&
3695
3696                 git checkout B &&
3697                 mkdir y/c &&
3698                 echo d >y/c/d &&
3699                 echo 11 >>x/c &&
3700                 git add x/c y/c/d &&
3701                 test_tick &&
3702                 git commit -m "B"
3703         )
3704 }
3705
3706 test_expect_success '11c: Avoid losing not-uptodate with rename + D/F conflict' '
3707         test_setup_11c &&
3708         (
3709                 cd 11c &&
3710
3711                 git checkout A^0 &&
3712                 echo stuff >>y/c &&
3713
3714                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3715                 test_i18ngrep "following files would be overwritten by merge" err &&
3716
3717                 grep -q stuff y/c &&
3718                 test_seq 1 10 >expected &&
3719                 echo stuff >>expected &&
3720                 test_cmp expected y/c &&
3721
3722                 git ls-files -s >out &&
3723                 test_line_count = 3 out &&
3724                 git ls-files -u >out &&
3725                 test_line_count = 0 out &&
3726                 git ls-files -m >out &&
3727                 test_line_count = 1 out &&
3728                 git ls-files -o >out &&
3729                 test_line_count = 3 out
3730         )
3731 '
3732
3733 # Testcase 11d, Avoid losing not-up-to-date with rename + D/F conflict
3734 #   Commit O: z/a,         x/{b,c_v1}
3735 #   Commit A: z/{a,c_v1},  x/b,       and z/c_v1 has uncommitted mods
3736 #   Commit B: y/{a,c/d},   x/{b,c_v2}
3737 #   Expected: D/F: y/c_v2 vs y/c/d) +
3738 #             Warning_Msg("Refusing to lose dirty file at z/c) +
3739 #             y/{a,c~HEAD,c/d}, x/b, now-untracked z/c_v1 with uncommitted mods
3740
3741 test_setup_11d () {
3742         test_create_repo 11d &&
3743         (
3744                 cd 11d &&
3745
3746                 mkdir z x &&
3747                 echo a >z/a &&
3748                 echo b >x/b &&
3749                 test_seq 1 10 >x/c &&
3750                 git add z x &&
3751                 test_tick &&
3752                 git commit -m "O" &&
3753
3754                 git branch O &&
3755                 git branch A &&
3756                 git branch B &&
3757
3758                 git checkout A &&
3759                 git mv x/c z/c &&
3760                 test_tick &&
3761                 git commit -m "A" &&
3762
3763                 git checkout B &&
3764                 git mv z y &&
3765                 mkdir y/c &&
3766                 echo d >y/c/d &&
3767                 echo 11 >>x/c &&
3768                 git add x/c y/c/d &&
3769                 test_tick &&
3770                 git commit -m "B"
3771         )
3772 }
3773
3774 test_expect_success '11d: Avoid losing not-uptodate with rename + D/F conflict' '
3775         test_setup_11d &&
3776         (
3777                 cd 11d &&
3778
3779                 git checkout A^0 &&
3780                 echo stuff >>z/c &&
3781
3782                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3783                 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3784
3785                 grep -q stuff z/c &&
3786                 test_seq 1 10 >expected &&
3787                 echo stuff >>expected &&
3788                 test_cmp expected z/c &&
3789
3790                 git ls-files -s >out &&
3791                 test_line_count = 4 out &&
3792                 git ls-files -u >out &&
3793                 test_line_count = 1 out &&
3794                 git ls-files -o >out &&
3795                 test_line_count = 5 out &&
3796
3797                 git rev-parse >actual \
3798                         :0:x/b :0:y/a :0:y/c/d :3:y/c &&
3799                 git rev-parse >expect \
3800                          O:x/b  O:z/a  B:y/c/d  B:x/c &&
3801                 test_cmp expect actual &&
3802
3803                 git hash-object y/c~HEAD >actual &&
3804                 git rev-parse B:x/c >expect &&
3805                 test_cmp expect actual
3806         )
3807 '
3808
3809 # Testcase 11e, Avoid deleting not-up-to-date with dir rename/rename(1to2)/add
3810 #   Commit O: z/{a,b},      x/{c_1,d}
3811 #   Commit A: y/{a,b,c_2},  x/d, w/c_1, and y/c_2 has uncommitted mods
3812 #   Commit B: z/{a,b,c_1},  x/d
3813 #   Expected: Failed Merge; y/{a,b} + x/d +
3814 #             CONFLICT(rename/rename) x/c_1 -> w/c_1 vs y/c_1 +
3815 #             ERROR_MSG(Refusing to lose dirty file at y/c)
3816 #             y/c~B^0 has O:x/c_1 contents
3817 #             y/c~HEAD has A:y/c_2 contents
3818 #             y/c has dirty file from before merge
3819
3820 test_setup_11e () {
3821         test_create_repo 11e &&
3822         (
3823                 cd 11e &&
3824
3825                 mkdir z x &&
3826                 echo a >z/a &&
3827                 echo b >z/b &&
3828                 echo c >x/c &&
3829                 echo d >x/d &&
3830                 git add z x &&
3831                 test_tick &&
3832                 git commit -m "O" &&
3833
3834                 git branch O &&
3835                 git branch A &&
3836                 git branch B &&
3837
3838                 git checkout A &&
3839                 git mv z/ y/ &&
3840                 echo different >y/c &&
3841                 mkdir w &&
3842                 git mv x/c w/ &&
3843                 git add y/c &&
3844                 test_tick &&
3845                 git commit -m "A" &&
3846
3847                 git checkout B &&
3848                 git mv x/c z/ &&
3849                 test_tick &&
3850                 git commit -m "B"
3851         )
3852 }
3853
3854 test_expect_success '11e: Avoid deleting not-uptodate with dir rename/rename(1to2)/add' '
3855         test_setup_11e &&
3856         (
3857                 cd 11e &&
3858
3859                 git checkout A^0 &&
3860                 echo mods >>y/c &&
3861
3862                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3863                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3864                 test_i18ngrep "Refusing to lose dirty file at y/c" out &&
3865
3866                 git ls-files -s >out &&
3867                 test_line_count = 7 out &&
3868                 git ls-files -u >out &&
3869                 test_line_count = 4 out &&
3870                 git ls-files -o >out &&
3871                 test_line_count = 3 out &&
3872
3873                 echo different >expected &&
3874                 echo mods >>expected &&
3875                 test_cmp expected y/c &&
3876
3877                 git rev-parse >actual \
3878                         :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :2:y/c :3:y/c &&
3879                 git rev-parse >expect \
3880                          O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  A:y/c  O:x/c &&
3881                 test_cmp expect actual &&
3882
3883                 # See if y/c~merged has expected contents; requires manually
3884                 # doing the expected file merge
3885                 git cat-file -p A:y/c >c1 &&
3886                 git cat-file -p B:z/c >c2 &&
3887                 >empty &&
3888                 test_must_fail git merge-file \
3889                         -L "HEAD" \
3890                         -L "" \
3891                         -L "B^0" \
3892                         c1 empty c2 &&
3893                 test_cmp c1 y/c~merged
3894         )
3895 '
3896
3897 # Testcase 11f, Avoid deleting not-up-to-date w/ dir rename/rename(2to1)
3898 #   Commit O: z/{a,b},        x/{c_1,d_2}
3899 #   Commit A: y/{a,b,wham_1}, x/d_2, except y/wham has uncommitted mods
3900 #   Commit B: z/{a,b,wham_2}, x/c_1
3901 #   Expected: Failed Merge; y/{a,b} + untracked y/{wham~merged} +
3902 #             y/wham with dirty changes from before merge +
3903 #             CONFLICT(rename/rename) x/c vs x/d -> y/wham
3904 #             ERROR_MSG(Refusing to lose dirty file at y/wham)
3905
3906 test_setup_11f () {
3907         test_create_repo 11f &&
3908         (
3909                 cd 11f &&
3910
3911                 mkdir z x &&
3912                 echo a >z/a &&
3913                 echo b >z/b &&
3914                 test_seq 1 10 >x/c &&
3915                 echo d >x/d &&
3916                 git add z x &&
3917                 test_tick &&
3918                 git commit -m "O" &&
3919
3920                 git branch O &&
3921                 git branch A &&
3922                 git branch B &&
3923
3924                 git checkout A &&
3925                 git mv z/ y/ &&
3926                 git mv x/c y/wham &&
3927                 test_tick &&
3928                 git commit -m "A" &&
3929
3930                 git checkout B &&
3931                 git mv x/d z/wham &&
3932                 test_tick &&
3933                 git commit -m "B"
3934         )
3935 }
3936
3937 test_expect_success '11f: Avoid deleting not-uptodate with dir rename/rename(2to1)' '
3938         test_setup_11f &&
3939         (
3940                 cd 11f &&
3941
3942                 git checkout A^0 &&
3943                 echo important >>y/wham &&
3944
3945                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3946                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3947                 test_i18ngrep "Refusing to lose dirty file at y/wham" out &&
3948
3949                 git ls-files -s >out &&
3950                 test_line_count = 4 out &&
3951                 git ls-files -u >out &&
3952                 test_line_count = 2 out &&
3953                 git ls-files -o >out &&
3954                 test_line_count = 3 out &&
3955
3956                 test_seq 1 10 >expected &&
3957                 echo important >>expected &&
3958                 test_cmp expected y/wham &&
3959
3960                 test_must_fail git rev-parse :1:y/wham &&
3961
3962                 git rev-parse >actual \
3963                         :0:y/a :0:y/b :2:y/wham :3:y/wham &&
3964                 git rev-parse >expect \
3965                          O:z/a  O:z/b  O:x/c     O:x/d &&
3966                 test_cmp expect actual &&
3967
3968                 # Test that the two-way merge in y/wham~merged is as expected
3969                 git cat-file -p :2:y/wham >expect &&
3970                 git cat-file -p :3:y/wham >other &&
3971                 >empty &&
3972                 test_must_fail git merge-file \
3973                         -L "HEAD" \
3974                         -L "" \
3975                         -L "B^0" \
3976                         expect empty other &&
3977                 test_cmp expect y/wham~merged
3978         )
3979 '
3980
3981 ###########################################################################
3982 # SECTION 12: Everything else
3983 #
3984 # Tests suggested by others.  Tests added after implementation completed
3985 # and submitted.  Grab bag.
3986 ###########################################################################
3987
3988 # Testcase 12a, Moving one directory hierarchy into another
3989 #   (Related to testcase 9a)
3990 #   Commit O: node1/{leaf1,leaf2}, node2/{leaf3,leaf4}
3991 #   Commit A: node1/{leaf1,leaf2,node2/{leaf3,leaf4}}
3992 #   Commit B: node1/{leaf1,leaf2,leaf5}, node2/{leaf3,leaf4,leaf6}
3993 #   Expected: node1/{leaf1,leaf2,leaf5,node2/{leaf3,leaf4,leaf6}}
3994
3995 test_setup_12a () {
3996         test_create_repo 12a &&
3997         (
3998                 cd 12a &&
3999
4000                 mkdir -p node1 node2 &&
4001                 echo leaf1 >node1/leaf1 &&
4002                 echo leaf2 >node1/leaf2 &&
4003                 echo leaf3 >node2/leaf3 &&
4004                 echo leaf4 >node2/leaf4 &&
4005                 git add node1 node2 &&
4006                 test_tick &&
4007                 git commit -m "O" &&
4008
4009                 git branch O &&
4010                 git branch A &&
4011                 git branch B &&
4012
4013                 git checkout A &&
4014                 git mv node2/ node1/ &&
4015                 test_tick &&
4016                 git commit -m "A" &&
4017
4018                 git checkout B &&
4019                 echo leaf5 >node1/leaf5 &&
4020                 echo leaf6 >node2/leaf6 &&
4021                 git add node1 node2 &&
4022                 test_tick &&
4023                 git commit -m "B"
4024         )
4025 }
4026
4027 test_expect_success '12a: Moving one directory hierarchy into another' '
4028         test_setup_12a &&
4029         (
4030                 cd 12a &&
4031
4032                 git checkout A^0 &&
4033
4034                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
4035
4036                 git ls-files -s >out &&
4037                 test_line_count = 6 out &&
4038
4039                 git rev-parse >actual \
4040                         HEAD:node1/leaf1 HEAD:node1/leaf2 HEAD:node1/leaf5 \
4041                         HEAD:node1/node2/leaf3 \
4042                         HEAD:node1/node2/leaf4 \
4043                         HEAD:node1/node2/leaf6 &&
4044                 git rev-parse >expect \
4045                         O:node1/leaf1    O:node1/leaf2    B:node1/leaf5 \
4046                         O:node2/leaf3 \
4047                         O:node2/leaf4 \
4048                         B:node2/leaf6 &&
4049                 test_cmp expect actual
4050         )
4051 '
4052
4053 # Testcase 12b1, Moving two directory hierarchies into each other
4054 #   (Related to testcases 1c and 12c)
4055 #   Commit O: node1/{leaf1, leaf2}, node2/{leaf3, leaf4}
4056 #   Commit A: node1/{leaf1, leaf2, node2/{leaf3, leaf4}}
4057 #   Commit B: node2/{leaf3, leaf4, node1/{leaf1, leaf2}}
4058 #   Expected: node1/node2/{leaf3, leaf4}
4059 #             node2/node1/{leaf1, leaf2}
4060 #   NOTE: If there were new files added to the old node1/ or node2/ directories,
4061 #         then we would need to detect renames for those directories and would
4062 #         find that:
4063 #             commit A renames node2/ -> node1/node2/
4064 #             commit B renames node1/ -> node2/node1/
4065 #         Applying those directory renames to the initial result (making all
4066 #         four paths experience a transitive renaming), yields
4067 #             node1/node2/node1/{leaf1, leaf2}
4068 #             node2/node1/node2/{leaf3, leaf4}
4069 #         as the result.  It may be really weird to have two directories
4070 #         rename each other, but simple rules give weird results when given
4071 #         weird inputs.  HOWEVER, the "If" at the beginning of those NOTE was
4072 #         false; there were no new files added and thus there is no directory
4073 #         rename detection to perform.  As such, we just have simple renames
4074 #         and the expected answer is:
4075 #             node1/node2/{leaf3, leaf4}
4076 #             node2/node1/{leaf1, leaf2}
4077
4078 test_setup_12b1 () {
4079         test_create_repo 12b1 &&
4080         (
4081                 cd 12b1 &&
4082
4083                 mkdir -p node1 node2 &&
4084                 echo leaf1 >node1/leaf1 &&
4085                 echo leaf2 >node1/leaf2 &&
4086                 echo leaf3 >node2/leaf3 &&
4087                 echo leaf4 >node2/leaf4 &&
4088                 git add node1 node2 &&
4089                 test_tick &&
4090                 git commit -m "O" &&
4091
4092                 git branch O &&
4093                 git branch A &&
4094                 git branch B &&
4095
4096                 git checkout A &&
4097                 git mv node2/ node1/ &&
4098                 test_tick &&
4099                 git commit -m "A" &&
4100
4101                 git checkout B &&
4102                 git mv node1/ node2/ &&
4103                 test_tick &&
4104                 git commit -m "B"
4105         )
4106 }
4107
4108 test_expect_merge_algorithm failure success '12b1: Moving two directory hierarchies into each other' '
4109         test_setup_12b1 &&
4110         (
4111                 cd 12b1 &&
4112
4113                 git checkout A^0 &&
4114
4115                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
4116
4117                 git ls-files -s >out &&
4118                 test_line_count = 4 out &&
4119
4120                 git rev-parse >actual \
4121                         HEAD:node2/node1/leaf1 \
4122                         HEAD:node2/node1/leaf2 \
4123                         HEAD:node1/node2/leaf3 \
4124                         HEAD:node1/node2/leaf4 &&
4125                 git rev-parse >expect \
4126                         O:node1/leaf1 \
4127                         O:node1/leaf2 \
4128                         O:node2/leaf3 \
4129                         O:node2/leaf4 &&
4130                 test_cmp expect actual
4131         )
4132 '
4133
4134 # Testcase 12b2, Moving two directory hierarchies into each other
4135 #   (Related to testcases 1c and 12c)
4136 #   Commit O: node1/{leaf1, leaf2}, node2/{leaf3, leaf4}
4137 #   Commit A: node1/{leaf1, leaf2, leaf5, node2/{leaf3, leaf4}}
4138 #   Commit B: node2/{leaf3, leaf4, leaf6, node1/{leaf1, leaf2}}
4139 #   Expected: node1/node2/{node1/{leaf1, leaf2}, leaf6}
4140 #             node2/node1/{node2/{leaf3, leaf4}, leaf5}
4141 #   NOTE: Without directory renames, we would expect
4142 #             A: node2/leaf3 -> node1/node2/leaf3
4143 #             A: node2/leaf1 -> node1/node2/leaf4
4144 #             A: Adds           node1/leaf5
4145 #             B: node1/leaf1 -> node2/node1/leaf1
4146 #             B: node1/leaf2 -> node2/node1/leaf2
4147 #             B: Adds           node2/leaf6
4148 #         with directory rename detection, we note that
4149 #             commit A renames node2/ -> node1/node2/
4150 #             commit B renames node1/ -> node2/node1/
4151 #         therefore, applying A's directory rename to the paths added in B gives:
4152 #             B: node1/leaf1 -> node1/node2/node1/leaf1
4153 #             B: node1/leaf2 -> node1/node2/node1/leaf2
4154 #             B: Adds           node1/node2/leaf6
4155 #         and applying B's directory rename to the paths added in A gives:
4156 #             A: node2/leaf3 -> node2/node1/node2/leaf3
4157 #             A: node2/leaf1 -> node2/node1/node2/leaf4
4158 #             A: Adds           node2/node1/leaf5
4159 #         resulting in the expected
4160 #             node1/node2/{node1/{leaf1, leaf2}, leaf6}
4161 #             node2/node1/{node2/{leaf3, leaf4}, leaf5}
4162 #
4163 #         You may ask, is it weird to have two directories rename each other?
4164 #         To which, I can do no more than shrug my shoulders and say that
4165 #         even simple rules give weird results when given weird inputs.
4166
4167 test_setup_12b2 () {
4168         test_create_repo 12b2 &&
4169         (
4170                 cd 12b2 &&
4171
4172                 mkdir -p node1 node2 &&
4173                 echo leaf1 >node1/leaf1 &&
4174                 echo leaf2 >node1/leaf2 &&
4175                 echo leaf3 >node2/leaf3 &&
4176                 echo leaf4 >node2/leaf4 &&
4177                 git add node1 node2 &&
4178                 test_tick &&
4179                 git commit -m "O" &&
4180
4181                 git branch O &&
4182                 git branch A &&
4183                 git branch B &&
4184
4185                 git checkout A &&
4186                 git mv node2/ node1/ &&
4187                 echo leaf5 >node1/leaf5 &&
4188                 git add node1/leaf5 &&
4189                 test_tick &&
4190                 git commit -m "A" &&
4191
4192                 git checkout B &&
4193                 git mv node1/ node2/ &&
4194                 echo leaf6 >node2/leaf6 &&
4195                 git add node2/leaf6 &&
4196                 test_tick &&
4197                 git commit -m "B"
4198         )
4199 }
4200
4201 test_expect_success '12b2: Moving two directory hierarchies into each other' '
4202         test_setup_12b2 &&
4203         (
4204                 cd 12b2 &&
4205
4206                 git checkout A^0 &&
4207
4208                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
4209
4210                 git ls-files -s >out &&
4211                 test_line_count = 6 out &&
4212
4213                 git rev-parse >actual \
4214                         HEAD:node1/node2/node1/leaf1 \
4215                         HEAD:node1/node2/node1/leaf2 \
4216                         HEAD:node2/node1/node2/leaf3 \
4217                         HEAD:node2/node1/node2/leaf4 \
4218                         HEAD:node2/node1/leaf5       \
4219                         HEAD:node1/node2/leaf6       &&
4220                 git rev-parse >expect \
4221                         O:node1/leaf1 \
4222                         O:node1/leaf2 \
4223                         O:node2/leaf3 \
4224                         O:node2/leaf4 \
4225                         A:node1/leaf5 \
4226                         B:node2/leaf6 &&
4227                 test_cmp expect actual
4228         )
4229 '
4230
4231 # Testcase 12c1, Moving two directory hierarchies into each other w/ content merge
4232 #   (Related to testcase 12b)
4233 #   Commit O: node1/{       leaf1_1, leaf2_1}, node2/{leaf3_1, leaf4_1}
4234 #   Commit A: node1/{       leaf1_2, leaf2_2,  node2/{leaf3_2, leaf4_2}}
4235 #   Commit B: node2/{node1/{leaf1_3, leaf2_3},        leaf3_3, leaf4_3}
4236 #   Expected: Content merge conflicts for each of:
4237 #               node1/node2/node1/{leaf1, leaf2},
4238 #               node2/node1/node2/{leaf3, leaf4}
4239 #   NOTE: This is *exactly* like 12b1, except that every path is modified on
4240 #         each side of the merge.
4241
4242 test_setup_12c1 () {
4243         test_create_repo 12c1 &&
4244         (
4245                 cd 12c1 &&
4246
4247                 mkdir -p node1 node2 &&
4248                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf1\n" >node1/leaf1 &&
4249                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf2\n" >node1/leaf2 &&
4250                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf3\n" >node2/leaf3 &&
4251                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf4\n" >node2/leaf4 &&
4252                 git add node1 node2 &&
4253                 test_tick &&
4254                 git commit -m "O" &&
4255
4256                 git branch O &&
4257                 git branch A &&
4258                 git branch B &&
4259
4260                 git checkout A &&
4261                 git mv node2/ node1/ &&
4262                 for i in `git ls-files`; do echo side A >>$i; done &&
4263                 git add -u &&
4264                 test_tick &&
4265                 git commit -m "A" &&
4266
4267                 git checkout B &&
4268                 git mv node1/ node2/ &&
4269                 for i in `git ls-files`; do echo side B >>$i; done &&
4270                 git add -u &&
4271                 test_tick &&
4272                 git commit -m "B"
4273         )
4274 }
4275
4276 test_expect_merge_algorithm failure success '12c1: Moving one directory hierarchy into another w/ content merge' '
4277         test_setup_12c1 &&
4278         (
4279                 cd 12c1 &&
4280
4281                 git checkout A^0 &&
4282
4283                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 &&
4284
4285                 git ls-files -u >out &&
4286                 test_line_count = 12 out &&
4287
4288                 git rev-parse >actual \
4289                         :1:node2/node1/leaf1 \
4290                         :1:node2/node1/leaf2 \
4291                         :1:node1/node2/leaf3 \
4292                         :1:node1/node2/leaf4 \
4293                         :2:node2/node1/leaf1 \
4294                         :2:node2/node1/leaf2 \
4295                         :2:node1/node2/leaf3 \
4296                         :2:node1/node2/leaf4 \
4297                         :3:node2/node1/leaf1 \
4298                         :3:node2/node1/leaf2 \
4299                         :3:node1/node2/leaf3 \
4300                         :3:node1/node2/leaf4 &&
4301                 git rev-parse >expect \
4302                         O:node1/leaf1 \
4303                         O:node1/leaf2 \
4304                         O:node2/leaf3 \
4305                         O:node2/leaf4 \
4306                         A:node1/leaf1 \
4307                         A:node1/leaf2 \
4308                         A:node1/node2/leaf3 \
4309                         A:node1/node2/leaf4 \
4310                         B:node2/node1/leaf1 \
4311                         B:node2/node1/leaf2 \
4312                         B:node2/leaf3 \
4313                         B:node2/leaf4 &&
4314                 test_cmp expect actual
4315         )
4316 '
4317
4318 # Testcase 12c2, Moving two directory hierarchies into each other w/ content merge
4319 #   (Related to testcase 12b)
4320 #   Commit O: node1/{       leaf1_1, leaf2_1}, node2/{leaf3_1, leaf4_1}
4321 #   Commit A: node1/{       leaf1_2, leaf2_2,  node2/{leaf3_2, leaf4_2}, leaf5}
4322 #   Commit B: node2/{node1/{leaf1_3, leaf2_3},        leaf3_3, leaf4_3,  leaf6}
4323 #   Expected: Content merge conflicts for each of:
4324 #               node1/node2/node1/{leaf1, leaf2}
4325 #               node2/node1/node2/{leaf3, leaf4}
4326 #             plus
4327 #               node2/node1/leaf5
4328 #               node1/node2/leaf6
4329 #   NOTE: This is *exactly* like 12b2, except that every path from O is modified
4330 #         on each side of the merge.
4331
4332 test_setup_12c2 () {
4333         test_create_repo 12c2 &&
4334         (
4335                 cd 12c2 &&
4336
4337                 mkdir -p node1 node2 &&
4338                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf1\n" >node1/leaf1 &&
4339                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf2\n" >node1/leaf2 &&
4340                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf3\n" >node2/leaf3 &&
4341                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf4\n" >node2/leaf4 &&
4342                 git add node1 node2 &&
4343                 test_tick &&
4344                 git commit -m "O" &&
4345
4346                 git branch O &&
4347                 git branch A &&
4348                 git branch B &&
4349
4350                 git checkout A &&
4351                 git mv node2/ node1/ &&
4352                 for i in `git ls-files`; do echo side A >>$i; done &&
4353                 git add -u &&
4354                 echo leaf5 >node1/leaf5 &&
4355                 git add node1/leaf5 &&
4356                 test_tick &&
4357                 git commit -m "A" &&
4358
4359                 git checkout B &&
4360                 git mv node1/ node2/ &&
4361                 for i in `git ls-files`; do echo side B >>$i; done &&
4362                 git add -u &&
4363                 echo leaf6 >node2/leaf6 &&
4364                 git add node2/leaf6 &&
4365                 test_tick &&
4366                 git commit -m "B"
4367         )
4368 }
4369
4370 test_expect_success '12c2: Moving one directory hierarchy into another w/ content merge' '
4371         test_setup_12c2 &&
4372         (
4373                 cd 12c2 &&
4374
4375                 git checkout A^0 &&
4376
4377                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 &&
4378
4379                 git ls-files -s >out &&
4380                 test_line_count = 14 out &&
4381                 git ls-files -u >out &&
4382                 test_line_count = 12 out &&
4383
4384                 git rev-parse >actual \
4385                         :1:node1/node2/node1/leaf1 \
4386                         :1:node1/node2/node1/leaf2 \
4387                         :1:node2/node1/node2/leaf3 \
4388                         :1:node2/node1/node2/leaf4 \
4389                         :2:node1/node2/node1/leaf1 \
4390                         :2:node1/node2/node1/leaf2 \
4391                         :2:node2/node1/node2/leaf3 \
4392                         :2:node2/node1/node2/leaf4 \
4393                         :3:node1/node2/node1/leaf1 \
4394                         :3:node1/node2/node1/leaf2 \
4395                         :3:node2/node1/node2/leaf3 \
4396                         :3:node2/node1/node2/leaf4 \
4397                         :0:node2/node1/leaf5       \
4398                         :0:node1/node2/leaf6       &&
4399                 git rev-parse >expect \
4400                         O:node1/leaf1 \
4401                         O:node1/leaf2 \
4402                         O:node2/leaf3 \
4403                         O:node2/leaf4 \
4404                         A:node1/leaf1 \
4405                         A:node1/leaf2 \
4406                         A:node1/node2/leaf3 \
4407                         A:node1/node2/leaf4 \
4408                         B:node2/node1/leaf1 \
4409                         B:node2/node1/leaf2 \
4410                         B:node2/leaf3 \
4411                         B:node2/leaf4 \
4412                         A:node1/leaf5 \
4413                         B:node2/leaf6 &&
4414                 test_cmp expect actual
4415         )
4416 '
4417
4418 # Testcase 12d, Rename/merge of subdirectory into the root
4419 #   Commit O: a/b/subdir/foo
4420 #   Commit A: subdir/foo
4421 #   Commit B: a/b/subdir/foo, a/b/bar
4422 #   Expected: subdir/foo, bar
4423
4424 test_setup_12d () {
4425         test_create_repo 12d &&
4426         (
4427                 cd 12d &&
4428
4429                 mkdir -p a/b/subdir &&
4430                 test_commit a/b/subdir/foo &&
4431
4432                 git branch O &&
4433                 git branch A &&
4434                 git branch B &&
4435
4436                 git checkout A &&
4437                 mkdir subdir &&
4438                 git mv a/b/subdir/foo.t subdir/foo.t &&
4439                 test_tick &&
4440                 git commit -m "A" &&
4441
4442                 git checkout B &&
4443                 test_commit a/b/bar
4444         )
4445 }
4446
4447 test_expect_success '12d: Rename/merge subdir into the root, variant 1' '
4448         test_setup_12d &&
4449         (
4450                 cd 12d &&
4451
4452                 git checkout A^0 &&
4453
4454                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
4455
4456                 git ls-files -s >out &&
4457                 test_line_count = 2 out &&
4458
4459                 git rev-parse >actual \
4460                         HEAD:subdir/foo.t   HEAD:bar.t &&
4461                 git rev-parse >expect \
4462                         O:a/b/subdir/foo.t  B:a/b/bar.t &&
4463                 test_cmp expect actual &&
4464
4465                 git hash-object bar.t >actual &&
4466                 git rev-parse B:a/b/bar.t >expect &&
4467                 test_cmp expect actual &&
4468
4469                 test_must_fail git rev-parse HEAD:a/b/subdir/foo.t &&
4470                 test_must_fail git rev-parse HEAD:a/b/bar.t &&
4471                 test_path_is_missing a/ &&
4472                 test_path_is_file bar.t
4473         )
4474 '
4475
4476 # Testcase 12e, Rename/merge of subdirectory into the root
4477 #   Commit O: a/b/foo
4478 #   Commit A: foo
4479 #   Commit B: a/b/foo, a/b/bar
4480 #   Expected: foo, bar
4481
4482 test_setup_12e () {
4483         test_create_repo 12e &&
4484         (
4485                 cd 12e &&
4486
4487                 mkdir -p a/b &&
4488                 test_commit a/b/foo &&
4489
4490                 git branch O &&
4491                 git branch A &&
4492                 git branch B &&
4493
4494                 git checkout A &&
4495                 mkdir subdir &&
4496                 git mv a/b/foo.t foo.t &&
4497                 test_tick &&
4498                 git commit -m "A" &&
4499
4500                 git checkout B &&
4501                 test_commit a/b/bar
4502         )
4503 }
4504
4505 test_expect_success '12e: Rename/merge subdir into the root, variant 2' '
4506         test_setup_12e &&
4507         (
4508                 cd 12e &&
4509
4510                 git checkout A^0 &&
4511
4512                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
4513
4514                 git ls-files -s >out &&
4515                 test_line_count = 2 out &&
4516
4517                 git rev-parse >actual \
4518                         HEAD:foo.t   HEAD:bar.t &&
4519                 git rev-parse >expect \
4520                         O:a/b/foo.t  B:a/b/bar.t &&
4521                 test_cmp expect actual &&
4522
4523                 git hash-object bar.t >actual &&
4524                 git rev-parse B:a/b/bar.t >expect &&
4525                 test_cmp expect actual &&
4526
4527                 test_must_fail git rev-parse HEAD:a/b/foo.t &&
4528                 test_must_fail git rev-parse HEAD:a/b/bar.t &&
4529                 test_path_is_missing a/ &&
4530                 test_path_is_file bar.t
4531         )
4532 '
4533
4534 # Testcase 12f, Rebase of patches with big directory rename
4535 #   Commit O:
4536 #              dir/subdir/{a,b,c,d,e_O,Makefile_TOP_O}
4537 #              dir/subdir/tweaked/{f,g,h,Makefile_SUB_O}
4538 #              dir/unchanged/<LOTS OF FILES>
4539 #   Commit A:
4540 #     (Remove f & g, move e into newsubdir, rename dir/->folder/, modify files)
4541 #              folder/subdir/{a,b,c,d,Makefile_TOP_A}
4542 #              folder/subdir/newsubdir/e_A
4543 #              folder/subdir/tweaked/{h,Makefile_SUB_A}
4544 #              folder/unchanged/<LOTS OF FILES>
4545 #   Commit B1:
4546 #     (add newfile.{c,py}, modify underscored files)
4547 #              dir/{a,b,c,d,e_B1,Makefile_TOP_B1,newfile.c}
4548 #              dir/tweaked/{f,g,h,Makefile_SUB_B1,newfile.py}
4549 #              dir/unchanged/<LOTS OF FILES>
4550 #   Commit B2:
4551 #     (Modify e further, add newfile.rs)
4552 #              dir/{a,b,c,d,e_B2,Makefile_TOP_B1,newfile.c,newfile.rs}
4553 #              dir/tweaked/{f,g,h,Makefile_SUB_B1,newfile.py}
4554 #              dir/unchanged/<LOTS OF FILES>
4555 #   Expected:
4556 #          B1-picked:
4557 #              folder/subdir/{a,b,c,d,Makefile_TOP_Merge1,newfile.c}
4558 #              folder/subdir/newsubdir/e_Merge1
4559 #              folder/subdir/tweaked/{h,Makefile_SUB_Merge1,newfile.py}
4560 #              folder/unchanged/<LOTS OF FILES>
4561 #          B2-picked:
4562 #              folder/subdir/{a,b,c,d,Makefile_TOP_Merge1,newfile.c,newfile.rs}
4563 #              folder/subdir/newsubdir/e_Merge2
4564 #              folder/subdir/tweaked/{h,Makefile_SUB_Merge1,newfile.py}
4565 #              folder/unchanged/<LOTS OF FILES>
4566 #
4567 # Notes: This testcase happens to exercise lots of the
4568 #        optimization-specific codepaths in merge-ort, and also
4569 #        demonstrated a failing of the directory rename detection algorithm
4570 #        in merge-recursive; newfile.c should not get pushed into
4571 #        folder/subdir/newsubdir/, yet merge-recursive put it there because
4572 #        the rename of dir/subdir/{a,b,c,d} -> folder/subdir/{a,b,c,d}
4573 #        looks like
4574 #            dir/ -> folder/,
4575 #        whereas the rename of dir/subdir/e -> folder/subdir/newsubdir/e
4576 #        looks like
4577 #            dir/subdir/ -> folder/subdir/newsubdir/
4578 #        and if we note that newfile.c is found in dir/subdir/, we might
4579 #        overlook the dir/ -> folder/ rule that has more weight.
4580
4581 test_setup_12f () {
4582         test_create_repo 12f &&
4583         (
4584                 cd 12f &&
4585
4586                 mkdir -p dir/unchanged &&
4587                 mkdir -p dir/subdir/tweaked &&
4588                 echo a >dir/subdir/a &&
4589                 echo b >dir/subdir/b &&
4590                 echo c >dir/subdir/c &&
4591                 echo d >dir/subdir/d &&
4592                 test_seq 1 10 >dir/subdir/e &&
4593                 test_seq 10 20 >dir/subdir/Makefile &&
4594                 echo f >dir/subdir/tweaked/f &&
4595                 echo g >dir/subdir/tweaked/g &&
4596                 echo h >dir/subdir/tweaked/h &&
4597                 test_seq 20 30 >dir/subdir/tweaked/Makefile &&
4598                 for i in `test_seq 1 88`; do
4599                         echo content $i >dir/unchanged/file_$i
4600                 done &&
4601                 git add . &&
4602                 git commit -m "O" &&
4603
4604                 git branch O &&
4605                 git branch A &&
4606                 git branch B &&
4607
4608                 git switch A &&
4609                 git rm dir/subdir/tweaked/f dir/subdir/tweaked/g &&
4610                 test_seq 2 10 >dir/subdir/e &&
4611                 test_seq 11 20 >dir/subdir/Makefile &&
4612                 test_seq 21 30 >dir/subdir/tweaked/Makefile &&
4613                 mkdir dir/subdir/newsubdir &&
4614                 git mv dir/subdir/e dir/subdir/newsubdir/ &&
4615                 git mv dir folder &&
4616                 git add . &&
4617                 git commit -m "A" &&
4618
4619                 git switch B &&
4620                 mkdir dir/subdir/newsubdir/ &&
4621                 echo c code >dir/subdir/newfile.c &&
4622                 echo python code >dir/subdir/newsubdir/newfile.py &&
4623                 test_seq 1 11 >dir/subdir/e &&
4624                 test_seq 10 21 >dir/subdir/Makefile &&
4625                 test_seq 20 31 >dir/subdir/tweaked/Makefile &&
4626                 git add . &&
4627                 git commit -m "B1" &&
4628
4629                 echo rust code >dir/subdir/newfile.rs &&
4630                 test_seq 1 12 >dir/subdir/e &&
4631                 git add . &&
4632                 git commit -m "B2"
4633         )
4634 }
4635
4636 test_expect_merge_algorithm failure success '12f: Trivial directory resolve, caching, all kinds of fun' '
4637         test_setup_12f &&
4638         (
4639                 cd 12f &&
4640
4641                 git checkout A^0 &&
4642                 git branch Bmod B &&
4643
4644                 git -c merge.directoryRenames=true rebase A Bmod &&
4645
4646                 echo Checking the pick of B1... &&
4647
4648                 test_must_fail git rev-parse Bmod~1:dir &&
4649
4650                 git ls-tree -r Bmod~1 >out &&
4651                 test_line_count = 98 out &&
4652
4653                 git diff --name-status A Bmod~1 >actual &&
4654                 q_to_tab >expect <<-\EOF &&
4655                 MQfolder/subdir/Makefile
4656                 AQfolder/subdir/newfile.c
4657                 MQfolder/subdir/newsubdir/e
4658                 AQfolder/subdir/newsubdir/newfile.py
4659                 MQfolder/subdir/tweaked/Makefile
4660                 EOF
4661                 test_cmp expect actual &&
4662
4663                 # Three-way merged files
4664                 test_seq  2 11 >e_Merge1 &&
4665                 test_seq 11 21 >Makefile_TOP &&
4666                 test_seq 21 31 >Makefile_SUB &&
4667                 git hash-object >expect      \
4668                         e_Merge1             \
4669                         Makefile_TOP         \
4670                         Makefile_SUB         &&
4671                 git rev-parse >actual              \
4672                         Bmod~1:folder/subdir/newsubdir/e     \
4673                         Bmod~1:folder/subdir/Makefile        \
4674                         Bmod~1:folder/subdir/tweaked/Makefile &&
4675                 test_cmp expect actual &&
4676
4677                 # New files showed up at the right location with right contents
4678                 git rev-parse >expect                \
4679                         B~1:dir/subdir/newfile.c            \
4680                         B~1:dir/subdir/newsubdir/newfile.py &&
4681                 git rev-parse >actual                      \
4682                         Bmod~1:folder/subdir/newfile.c            \
4683                         Bmod~1:folder/subdir/newsubdir/newfile.py &&
4684                 test_cmp expect actual &&
4685
4686                 # Removed files
4687                 test_path_is_missing folder/subdir/tweaked/f &&
4688                 test_path_is_missing folder/subdir/tweaked/g &&
4689
4690                 # Unchanged files or directories
4691                 git rev-parse >actual        \
4692                         Bmod~1:folder/subdir/a          \
4693                         Bmod~1:folder/subdir/b          \
4694                         Bmod~1:folder/subdir/c          \
4695                         Bmod~1:folder/subdir/d          \
4696                         Bmod~1:folder/unchanged         \
4697                         Bmod~1:folder/subdir/tweaked/h &&
4698                 git rev-parse >expect          \
4699                         O:dir/subdir/a         \
4700                         O:dir/subdir/b         \
4701                         O:dir/subdir/c         \
4702                         O:dir/subdir/d         \
4703                         O:dir/unchanged        \
4704                         O:dir/subdir/tweaked/h &&
4705                 test_cmp expect actual &&
4706
4707                 echo Checking the pick of B2... &&
4708
4709                 test_must_fail git rev-parse Bmod:dir &&
4710
4711                 git ls-tree -r Bmod >out &&
4712                 test_line_count = 99 out &&
4713
4714                 git diff --name-status Bmod~1 Bmod >actual &&
4715                 q_to_tab >expect <<-\EOF &&
4716                 AQfolder/subdir/newfile.rs
4717                 MQfolder/subdir/newsubdir/e
4718                 EOF
4719                 test_cmp expect actual &&
4720
4721                 # Three-way merged file
4722                 test_seq  2 12 >e_Merge2 &&
4723                 git hash-object e_Merge2 >expect &&
4724                 git rev-parse Bmod:folder/subdir/newsubdir/e >actual &&
4725                 test_cmp expect actual
4726         )
4727 '
4728
4729 ###########################################################################
4730 # SECTION 13: Checking informational and conflict messages
4731 #
4732 # A year after directory rename detection became the default, it was
4733 # instead decided to report conflicts on the pathname on the basis that
4734 # some users may expect the new files added or moved into a directory to
4735 # be unrelated to all the other files in that directory, and thus that
4736 # directory rename detection is unexpected.  Test that the messages printed
4737 # match our expectation.
4738 ###########################################################################
4739
4740 # Testcase 13a, Basic directory rename with newly added files
4741 #   Commit O: z/{b,c}
4742 #   Commit A: y/{b,c}
4743 #   Commit B: z/{b,c,d,e/f}
4744 #   Expected: y/{b,c,d,e/f}, with notices/conflicts for both y/d and y/e/f
4745
4746 test_setup_13a () {
4747         test_create_repo 13a_$1 &&
4748         (
4749                 cd 13a_$1 &&
4750
4751                 mkdir z &&
4752                 echo b >z/b &&
4753                 echo c >z/c &&
4754                 git add z &&
4755                 test_tick &&
4756                 git commit -m "O" &&
4757
4758                 git branch O &&
4759                 git branch A &&
4760                 git branch B &&
4761
4762                 git checkout A &&
4763                 git mv z y &&
4764                 test_tick &&
4765                 git commit -m "A" &&
4766
4767                 git checkout B &&
4768                 echo d >z/d &&
4769                 mkdir z/e &&
4770                 echo f >z/e/f &&
4771                 git add z/d z/e/f &&
4772                 test_tick &&
4773                 git commit -m "B"
4774         )
4775 }
4776
4777 test_expect_success '13a(conflict): messages for newly added files' '
4778         test_setup_13a conflict &&
4779         (
4780                 cd 13a_conflict &&
4781
4782                 git checkout A^0 &&
4783
4784                 test_must_fail git merge -s recursive B^0 >out 2>err &&
4785
4786                 test_i18ngrep CONFLICT..file.location.*z/e/f.added.in.B^0.*y/e/f out &&
4787                 test_i18ngrep CONFLICT..file.location.*z/d.added.in.B^0.*y/d out &&
4788
4789                 git ls-files >paths &&
4790                 ! grep z/ paths &&
4791                 grep "y/[de]" paths &&
4792
4793                 test_path_is_missing z/d &&
4794                 test_path_is_file    y/d &&
4795                 test_path_is_missing z/e/f &&
4796                 test_path_is_file    y/e/f
4797         )
4798 '
4799
4800 test_expect_success '13a(info): messages for newly added files' '
4801         test_setup_13a info &&
4802         (
4803                 cd 13a_info &&
4804
4805                 git reset --hard &&
4806                 git checkout A^0 &&
4807
4808                 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
4809
4810                 test_i18ngrep Path.updated:.*z/e/f.added.in.B^0.*y/e/f out &&
4811                 test_i18ngrep Path.updated:.*z/d.added.in.B^0.*y/d out &&
4812
4813                 git ls-files >paths &&
4814                 ! grep z/ paths &&
4815                 grep "y/[de]" paths &&
4816
4817                 test_path_is_missing z/d &&
4818                 test_path_is_file    y/d &&
4819                 test_path_is_missing z/e/f &&
4820                 test_path_is_file    y/e/f
4821         )
4822 '
4823
4824 # Testcase 13b, Transitive rename with conflicted content merge and default
4825 #               "conflict" setting
4826 #   (Related to testcase 1c, 9b)
4827 #   Commit O: z/{b,c},   x/d_1
4828 #   Commit A: y/{b,c},   x/d_2
4829 #   Commit B: z/{b,c,d_3}
4830 #   Expected: y/{b,c,d_merged}, with two conflict messages for y/d,
4831 #             one about content, and one about file location
4832
4833 test_setup_13b () {
4834         test_create_repo 13b_$1 &&
4835         (
4836                 cd 13b_$1 &&
4837
4838                 mkdir x &&
4839                 mkdir z &&
4840                 test_seq 1 10 >x/d &&
4841                 echo b >z/b &&
4842                 echo c >z/c &&
4843                 git add x z &&
4844                 test_tick &&
4845                 git commit -m "O" &&
4846
4847                 git branch O &&
4848                 git branch A &&
4849                 git branch B &&
4850
4851                 git checkout A &&
4852                 git mv z y &&
4853                 echo 11 >>x/d &&
4854                 git add x/d &&
4855                 test_tick &&
4856                 git commit -m "A" &&
4857
4858                 git checkout B &&
4859                 echo eleven >>x/d &&
4860                 git mv x/d z/d &&
4861                 git add z/d &&
4862                 test_tick &&
4863                 git commit -m "B"
4864         )
4865 }
4866
4867 test_expect_success '13b(conflict): messages for transitive rename with conflicted content' '
4868         test_setup_13b conflict &&
4869         (
4870                 cd 13b_conflict &&
4871
4872                 git checkout A^0 &&
4873
4874                 test_must_fail git merge -s recursive B^0 >out 2>err &&
4875
4876                 test_i18ngrep CONFLICT.*content.*Merge.conflict.in.y/d out &&
4877                 test_i18ngrep CONFLICT..file.location.*x/d.renamed.to.z/d.*moved.to.y/d out &&
4878
4879                 git ls-files >paths &&
4880                 ! grep z/ paths &&
4881                 grep "y/d" paths &&
4882
4883                 test_path_is_missing z/d &&
4884                 test_path_is_file    y/d
4885         )
4886 '
4887
4888 test_expect_success '13b(info): messages for transitive rename with conflicted content' '
4889         test_setup_13b info &&
4890         (
4891                 cd 13b_info &&
4892
4893                 git reset --hard &&
4894                 git checkout A^0 &&
4895
4896                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
4897
4898                 test_i18ngrep CONFLICT.*content.*Merge.conflict.in.y/d out &&
4899                 test_i18ngrep Path.updated:.*x/d.renamed.to.z/d.in.B^0.*moving.it.to.y/d out &&
4900
4901                 git ls-files >paths &&
4902                 ! grep z/ paths &&
4903                 grep "y/d" paths &&
4904
4905                 test_path_is_missing z/d &&
4906                 test_path_is_file    y/d
4907         )
4908 '
4909
4910 # Testcase 13c, Rename/rename(1to1) due to directory rename
4911 #   Commit O: z/{b,c},   x/{d,e}
4912 #   Commit A: y/{b,c,d}, x/e
4913 #   Commit B: z/{b,c,d}, x/e
4914 #   Expected: y/{b,c,d}, x/e, with info or conflict messages for d
4915 #             A: renamed x/d -> z/d; B: renamed z/ -> y/ AND renamed x/d to y/d
4916 #             One could argue A had partial knowledge of what was done with
4917 #             d and B had full knowledge, but that's a slippery slope as
4918 #             shown in testcase 13d.
4919
4920 test_setup_13c () {
4921         test_create_repo 13c_$1 &&
4922         (
4923                 cd 13c_$1 &&
4924
4925                 mkdir x &&
4926                 mkdir z &&
4927                 test_seq 1 10 >x/d &&
4928                 echo e >x/e &&
4929                 echo b >z/b &&
4930                 echo c >z/c &&
4931                 git add x z &&
4932                 test_tick &&
4933                 git commit -m "O" &&
4934
4935                 git branch O &&
4936                 git branch A &&
4937                 git branch B &&
4938
4939                 git checkout A &&
4940                 git mv z y &&
4941                 git mv x/d y/ &&
4942                 test_tick &&
4943                 git commit -m "A" &&
4944
4945                 git checkout B &&
4946                 git mv x/d z/d &&
4947                 git add z/d &&
4948                 test_tick &&
4949                 git commit -m "B"
4950         )
4951 }
4952
4953 test_expect_success '13c(conflict): messages for rename/rename(1to1) via transitive rename' '
4954         test_setup_13c conflict &&
4955         (
4956                 cd 13c_conflict &&
4957
4958                 git checkout A^0 &&
4959
4960                 test_must_fail git merge -s recursive B^0 >out 2>err &&
4961
4962                 test_i18ngrep CONFLICT..file.location.*x/d.renamed.to.z/d.*moved.to.y/d out &&
4963
4964                 git ls-files >paths &&
4965                 ! grep z/ paths &&
4966                 grep "y/d" paths &&
4967
4968                 test_path_is_missing z/d &&
4969                 test_path_is_file    y/d
4970         )
4971 '
4972
4973 test_expect_success '13c(info): messages for rename/rename(1to1) via transitive rename' '
4974         test_setup_13c info &&
4975         (
4976                 cd 13c_info &&
4977
4978                 git reset --hard &&
4979                 git checkout A^0 &&
4980
4981                 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
4982
4983                 test_i18ngrep Path.updated:.*x/d.renamed.to.z/d.in.B^0.*moving.it.to.y/d out &&
4984
4985                 git ls-files >paths &&
4986                 ! grep z/ paths &&
4987                 grep "y/d" paths &&
4988
4989                 test_path_is_missing z/d &&
4990                 test_path_is_file    y/d
4991         )
4992 '
4993
4994 # Testcase 13d, Rename/rename(1to1) due to directory rename on both sides
4995 #   Commit O: a/{z,y}, b/x,     c/w
4996 #   Commit A: a/z,     b/{y,x}, d/w
4997 #   Commit B: a/z,     d/x,     c/{y,w}
4998 #   Expected: a/z, d/{y,x,w} with no file location conflict for x
4999 #             Easy cases:
5000 #               * z is always in a; so it stays in a.
5001 #               * x starts in b, only modified on one side to move into d/
5002 #               * w starts in c, only modified on one side to move into d/
5003 #             Hard case:
5004 #               * A renames a/y to b/y, and B renames b/->d/ => a/y -> d/y
5005 #               * B renames a/y to c/y, and A renames c/->d/ => a/y -> d/y
5006 #               No conflict in where a/y ends up, so put it in d/y.
5007
5008 test_setup_13d () {
5009         test_create_repo 13d_$1 &&
5010         (
5011                 cd 13d_$1 &&
5012
5013                 mkdir a &&
5014                 mkdir b &&
5015                 mkdir c &&
5016                 echo z >a/z &&
5017                 echo y >a/y &&
5018                 echo x >b/x &&
5019                 echo w >c/w &&
5020                 git add a b c &&
5021                 test_tick &&
5022                 git commit -m "O" &&
5023
5024                 git branch O &&
5025                 git branch A &&
5026                 git branch B &&
5027
5028                 git checkout A &&
5029                 git mv a/y b/ &&
5030                 git mv c/ d/ &&
5031                 test_tick &&
5032                 git commit -m "A" &&
5033
5034                 git checkout B &&
5035                 git mv a/y c/ &&
5036                 git mv b/ d/ &&
5037                 test_tick &&
5038                 git commit -m "B"
5039         )
5040 }
5041
5042 test_expect_success '13d(conflict): messages for rename/rename(1to1) via dual transitive rename' '
5043         test_setup_13d conflict &&
5044         (
5045                 cd 13d_conflict &&
5046
5047                 git checkout A^0 &&
5048
5049                 test_must_fail git merge -s recursive B^0 >out 2>err &&
5050
5051                 test_i18ngrep CONFLICT..file.location.*a/y.renamed.to.b/y.*moved.to.d/y out &&
5052                 test_i18ngrep CONFLICT..file.location.*a/y.renamed.to.c/y.*moved.to.d/y out &&
5053
5054                 git ls-files >paths &&
5055                 ! grep b/ paths &&
5056                 ! grep c/ paths &&
5057                 grep "d/y" paths &&
5058
5059                 test_path_is_missing b/y &&
5060                 test_path_is_missing c/y &&
5061                 test_path_is_file    d/y
5062         )
5063 '
5064
5065 test_expect_success '13d(info): messages for rename/rename(1to1) via dual transitive rename' '
5066         test_setup_13d info &&
5067         (
5068                 cd 13d_info &&
5069
5070                 git reset --hard &&
5071                 git checkout A^0 &&
5072
5073                 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
5074
5075                 test_i18ngrep Path.updated.*a/y.renamed.to.b/y.*moving.it.to.d/y out &&
5076                 test_i18ngrep Path.updated.*a/y.renamed.to.c/y.*moving.it.to.d/y out &&
5077
5078                 git ls-files >paths &&
5079                 ! grep b/ paths &&
5080                 ! grep c/ paths &&
5081                 grep "d/y" paths &&
5082
5083                 test_path_is_missing b/y &&
5084                 test_path_is_missing c/y &&
5085                 test_path_is_file    d/y
5086         )
5087 '
5088
5089 # Testcase 13e, directory rename in virtual merge base
5090 #
5091 # This testcase has a slightly different setup than all the above cases, in
5092 # order to include a recursive case:
5093 #
5094 #      A   C
5095 #      o - o
5096 #     / \ / \
5097 #  O o   X   ?
5098 #     \ / \ /
5099 #      o   o
5100 #      B   D
5101 #
5102 #   Commit O: a/{z,y}
5103 #   Commit A: b/{z,y}
5104 #   Commit B: a/{z,y,x}
5105 #   Commit C: b/{z,y,x}
5106 #   Commit D: b/{z,y}, a/x
5107 #   Expected: b/{z,y,x}  (sort of; see below for why this might not be expected)
5108 #
5109 #   NOTES: 'X' represents a virtual merge base.  With the default of
5110 #          directory rename detection yielding conflicts, merging A and B
5111 #          results in a conflict complaining about whether 'x' should be
5112 #          under 'a/' or 'b/'.  However, when creating the virtual merge
5113 #          base 'X', since virtual merge bases need to be written out as a
5114 #          tree, we cannot have a conflict, so some resolution has to be
5115 #          picked.
5116 #
5117 #          In choosing the right resolution, it's worth noting here that
5118 #          commits C & D are merges of A & B that choose different
5119 #          locations for 'x' (i.e. they resolve the conflict differently),
5120 #          and so it would be nice when merging C & D if git could detect
5121 #          this difference of opinion and report a conflict.  But the only
5122 #          way to do so that I can think of would be to have the virtual
5123 #          merge base place 'x' in some directory other than either 'a/' or
5124 #          'b/', which seems a little weird -- especially since it'd result
5125 #          in a rename/rename(1to2) conflict with a source path that never
5126 #          existed in any version.
5127 #
5128 #          So, for now, when directory rename detection is set to
5129 #          'conflict' just avoid doing directory rename detection at all in
5130 #          the recursive case.  This will not allow us to detect a conflict
5131 #          in the outer merge for this special kind of setup, but it at
5132 #          least avoids hitting a BUG().
5133 #
5134 test_setup_13e () {
5135         test_create_repo 13e &&
5136         (
5137                 cd 13e &&
5138
5139                 mkdir a &&
5140                 echo z >a/z &&
5141                 echo y >a/y &&
5142                 git add a &&
5143                 test_tick &&
5144                 git commit -m "O" &&
5145
5146                 git branch O &&
5147                 git branch A &&
5148                 git branch B &&
5149
5150                 git checkout A &&
5151                 git mv a/ b/ &&
5152                 test_tick &&
5153                 git commit -m "A" &&
5154
5155                 git checkout B &&
5156                 echo x >a/x &&
5157                 git add a &&
5158                 test_tick &&
5159                 git commit -m "B" &&
5160
5161                 git branch C A &&
5162                 git branch D B &&
5163
5164                 git checkout C &&
5165                 test_must_fail git -c merge.directoryRenames=conflict merge B &&
5166                 git add b/x &&
5167                 test_tick &&
5168                 git commit -m "C" &&
5169
5170
5171                 git checkout D &&
5172                 test_must_fail git -c merge.directoryRenames=conflict merge A &&
5173                 git add b/x &&
5174                 mkdir a &&
5175                 git mv b/x a/x &&
5176                 test_tick &&
5177                 git commit -m "D"
5178         )
5179 }
5180
5181 test_expect_success '13e: directory rename detection in recursive case' '
5182         test_setup_13e &&
5183         (
5184                 cd 13e &&
5185
5186                 git checkout --quiet D^0 &&
5187
5188                 git -c merge.directoryRenames=conflict merge -s recursive C^0 >out 2>err &&
5189
5190                 test_i18ngrep ! CONFLICT out &&
5191                 test_i18ngrep ! BUG: err &&
5192                 test_i18ngrep ! core.dumped err &&
5193                 test_must_be_empty err &&
5194
5195                 git ls-files >paths &&
5196                 ! grep a/x paths &&
5197                 grep b/x paths
5198         )
5199 '
5200
5201 test_done