t6404, t6423: expect improved rename/delete handling in ort backend
[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                 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
1181                 then
1182                         test_line_count = 1 out &&
1183
1184                         git rev-parse >actual \
1185                             :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d~HEAD :0:y/d/e
1186                 else
1187                         test_line_count = 2 out &&
1188
1189                         git rev-parse >actual \
1190                             :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d      :0:y/d/e
1191                 fi &&
1192                 git rev-parse >expect \
1193                          O:z/b  O:z/c  B:z/d  B:z/f  A:y/d  B:y/d/e &&
1194                 test_cmp expect actual &&
1195
1196                 git hash-object y/d~HEAD >actual &&
1197                 git rev-parse A:y/d >expect &&
1198                 test_cmp expect actual
1199         )
1200 '
1201
1202 ###########################################################################
1203 # Rules suggested by section 5:
1204 #
1205 #   If a subset of to-be-renamed files have a file or directory in the way,
1206 #   "turn off" the directory rename for those specific sub-paths, falling
1207 #   back to old handling.  But, sadly, see testcases 8a and 8b.
1208 ###########################################################################
1209
1210
1211 ###########################################################################
1212 # SECTION 6: Same side of the merge was the one that did the rename
1213 #
1214 # It may sound obvious that you only want to apply implicit directory
1215 # renames to directories if the _other_ side of history did the renaming.
1216 # If you did make an implementation that didn't explicitly enforce this
1217 # rule, the majority of cases that would fall under this section would
1218 # also be solved by following the rules from the above sections.  But
1219 # there are still a few that stick out, so this section covers them just
1220 # to make sure we also get them right.
1221 ###########################################################################
1222
1223 # Testcase 6a, Tricky rename/delete
1224 #   Commit O: z/{b,c,d}
1225 #   Commit A: z/b
1226 #   Commit B: y/{b,c}, z/d
1227 #   Expected: y/b, CONFLICT(rename/delete, z/c -> y/c vs. NULL)
1228 #   Note: We're just checking here that the rename of z/b and z/c to put
1229 #         them under y/ doesn't accidentally catch z/d and make it look like
1230 #         it is also involved in a rename/delete conflict.
1231
1232 test_setup_6a () {
1233         test_create_repo 6a &&
1234         (
1235                 cd 6a &&
1236
1237                 mkdir z &&
1238                 echo b >z/b &&
1239                 echo c >z/c &&
1240                 echo d >z/d &&
1241                 git add z &&
1242                 test_tick &&
1243                 git commit -m "O" &&
1244
1245                 git branch O &&
1246                 git branch A &&
1247                 git branch B &&
1248
1249                 git checkout A &&
1250                 git rm z/c &&
1251                 git rm z/d &&
1252                 test_tick &&
1253                 git commit -m "A" &&
1254
1255                 git checkout B &&
1256                 mkdir y &&
1257                 git mv z/b y/ &&
1258                 git mv z/c y/ &&
1259                 test_tick &&
1260                 git commit -m "B"
1261         )
1262 }
1263
1264 test_expect_success '6a: Tricky rename/delete' '
1265         test_setup_6a &&
1266         (
1267                 cd 6a &&
1268
1269                 git checkout A^0 &&
1270
1271                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1272                 test_i18ngrep "CONFLICT (rename/delete).*z/c.*y/c" out &&
1273
1274                 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
1275                 then
1276                         git ls-files -s >out &&
1277                         test_line_count = 3 out &&
1278                         git ls-files -u >out &&
1279                         test_line_count = 2 out &&
1280                         git ls-files -o >out &&
1281                         test_line_count = 1 out &&
1282
1283                         git rev-parse >actual \
1284                                 :0:y/b :1:y/c :3:y/c &&
1285                         git rev-parse >expect \
1286                                  O:z/b  O:z/c  O:z/c
1287                 else
1288                         git ls-files -s >out &&
1289                         test_line_count = 2 out &&
1290                         git ls-files -u >out &&
1291                         test_line_count = 1 out &&
1292                         git ls-files -o >out &&
1293                         test_line_count = 1 out &&
1294
1295                         git rev-parse >actual \
1296                                 :0:y/b :3:y/c &&
1297                         git rev-parse >expect \
1298                                  O:z/b  O:z/c
1299                 fi &&
1300                 test_cmp expect actual
1301         )
1302 '
1303
1304 # Testcase 6b1, Same rename done on both sides
1305 #   (Related to testcase 6b2 and 8e)
1306 #   Commit O: z/{b,c,d,e}
1307 #   Commit A: y/{b,c,d}, x/e
1308 #   Commit B: y/{b,c,d}, z/{e,f}
1309 #   Expected: y/{b,c,d,f}, x/e
1310 #   Note: Directory rename detection says A renamed z/ -> y/ (3 paths renamed
1311 #         to y/ and only 1 renamed to x/), therefore the new file 'z/f' in B
1312 #         should be moved to 'y/f'.
1313 #
1314 #         This is a bit of an edge case where any behavior might surprise users,
1315 #         whether that is treating A as renaming z/ -> y/, treating A as renaming
1316 #         z/ -> x/, or treating A as not doing any directory rename.  However, I
1317 #         think this answer is the least confusing and most consistent with the
1318 #         rules elsewhere.
1319 #
1320 #         A note about z/ -> x/, since it may not be clear how that could come
1321 #         about: If we were to ignore files renamed by both sides
1322 #         (i.e. z/{b,c,d}), as directory rename detection did in git-2.18 thru
1323 #         at least git-2.28, then we would note there are no renames from z/ to
1324 #         y/ and one rename from z/ to x/ and thus come to the conclusion that
1325 #         A renamed z/ -> x/.  This seems more confusing for end users than a
1326 #         rename of z/ to y/, it makes directory rename detection behavior
1327 #         harder for them to predict.  As such, we modified the rule, changed
1328 #         the behavior on testcases 6b2 and 8e, and introduced this 6b1 testcase.
1329
1330 test_setup_6b1 () {
1331         test_create_repo 6b1 &&
1332         (
1333                 cd 6b1 &&
1334
1335                 mkdir z &&
1336                 echo b >z/b &&
1337                 echo c >z/c &&
1338                 echo d >z/d &&
1339                 echo e >z/e &&
1340                 git add z &&
1341                 test_tick &&
1342                 git commit -m "O" &&
1343
1344                 git branch O &&
1345                 git branch A &&
1346                 git branch B &&
1347
1348                 git checkout A &&
1349                 git mv z y &&
1350                 mkdir x &&
1351                 git mv y/e x/e &&
1352                 test_tick &&
1353                 git commit -m "A" &&
1354
1355                 git checkout B &&
1356                 git mv z y &&
1357                 mkdir z &&
1358                 git mv y/e z/e &&
1359                 echo f >z/f &&
1360                 git add z/f &&
1361                 test_tick &&
1362                 git commit -m "B"
1363         )
1364 }
1365
1366 test_expect_merge_algorithm failure success '6b1: Same renames done on both sides, plus another rename' '
1367         test_setup_6b1 &&
1368         (
1369                 cd 6b1 &&
1370
1371                 git checkout A^0 &&
1372
1373                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
1374
1375                 git ls-files -s >out &&
1376                 test_line_count = 5 out &&
1377                 git ls-files -u >out &&
1378                 test_line_count = 0 out &&
1379                 git ls-files -o >out &&
1380                 test_line_count = 1 out &&
1381
1382                 git rev-parse >actual \
1383                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:x/e HEAD:y/f &&
1384                 git rev-parse >expect \
1385                         O:z/b    O:z/c    O:z/d    O:z/e    B:z/f &&
1386                 test_cmp expect actual
1387         )
1388 '
1389
1390 # Testcase 6b2, Same rename done on both sides
1391 #   (Related to testcases 6c and 8e)
1392 #   Commit O: z/{b,c}
1393 #   Commit A: y/{b,c}
1394 #   Commit B: y/{b,c}, z/d
1395 #   Expected: y/{b,c,d}
1396 #   Alternate: y/{b,c}, z/d
1397 #   Note: Directory rename detection says A renamed z/ -> y/, therefore the new
1398 #         file 'z/d' in B should be moved to 'y/d'.
1399 #
1400 #         We could potentially ignore the renames of z/{b,c} on side A since
1401 #         those were renamed on both sides.  However, it's a bit of a corner
1402 #         case because what if there was also a z/e that side A moved to x/e
1403 #         and side B left alone?  If we used the "ignore renames done on both
1404 #         sides" logic, then we'd compute that A renamed z/ -> x/, and move
1405 #         z/d to x/d.  That seems more surprising and uglier than allowing
1406 #         the z/ -> y/ rename.
1407
1408 test_setup_6b2 () {
1409         test_create_repo 6b2 &&
1410         (
1411                 cd 6b2 &&
1412
1413                 mkdir z &&
1414                 echo b >z/b &&
1415                 echo c >z/c &&
1416                 git add z &&
1417                 test_tick &&
1418                 git commit -m "O" &&
1419
1420                 git branch O &&
1421                 git branch A &&
1422                 git branch B &&
1423
1424                 git checkout A &&
1425                 git mv z y &&
1426                 test_tick &&
1427                 git commit -m "A" &&
1428
1429                 git checkout B &&
1430                 git mv z y &&
1431                 mkdir z &&
1432                 echo d >z/d &&
1433                 git add z/d &&
1434                 test_tick &&
1435                 git commit -m "B"
1436         )
1437 }
1438
1439 test_expect_merge_algorithm failure success '6b2: Same rename done on both sides' '
1440         test_setup_6b2 &&
1441         (
1442                 cd 6b2 &&
1443
1444                 git checkout A^0 &&
1445
1446                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
1447
1448                 git ls-files -s >out &&
1449                 test_line_count = 3 out &&
1450                 git ls-files -u >out &&
1451                 test_line_count = 0 out &&
1452                 git ls-files -o >out &&
1453                 test_line_count = 1 out &&
1454
1455                 git rev-parse >actual \
1456                         HEAD:y/b HEAD:y/c HEAD:y/d &&
1457                 git rev-parse >expect \
1458                         O:z/b    O:z/c    B:z/d &&
1459                 test_cmp expect actual
1460         )
1461 '
1462
1463 # Testcase 6c, Rename only done on same side
1464 #   (Related to testcases 6b1, 6b2, and 8e)
1465 #   Commit O: z/{b,c}
1466 #   Commit A: z/{b,c} (no change)
1467 #   Commit B: y/{b,c}, z/d
1468 #   Expected: y/{b,c}, z/d
1469 #   NOTE: Seems obvious, but just checking that the implementation doesn't
1470 #         "accidentally detect a rename" and give us y/{b,c,d}.
1471
1472 test_setup_6c () {
1473         test_create_repo 6c &&
1474         (
1475                 cd 6c &&
1476
1477                 mkdir z &&
1478                 echo b >z/b &&
1479                 echo c >z/c &&
1480                 git add z &&
1481                 test_tick &&
1482                 git commit -m "O" &&
1483
1484                 git branch O &&
1485                 git branch A &&
1486                 git branch B &&
1487
1488                 git checkout A &&
1489                 test_tick &&
1490                 git commit --allow-empty -m "A" &&
1491
1492                 git checkout B &&
1493                 git mv z y &&
1494                 mkdir z &&
1495                 echo d >z/d &&
1496                 git add z/d &&
1497                 test_tick &&
1498                 git commit -m "B"
1499         )
1500 }
1501
1502 test_expect_success '6c: Rename only done on same side' '
1503         test_setup_6c &&
1504         (
1505                 cd 6c &&
1506
1507                 git checkout A^0 &&
1508
1509                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
1510
1511                 git ls-files -s >out &&
1512                 test_line_count = 3 out &&
1513                 git ls-files -u >out &&
1514                 test_line_count = 0 out &&
1515                 git ls-files -o >out &&
1516                 test_line_count = 1 out &&
1517
1518                 git rev-parse >actual \
1519                         HEAD:y/b HEAD:y/c HEAD:z/d &&
1520                 git rev-parse >expect \
1521                         O:z/b    O:z/c    B:z/d &&
1522                 test_cmp expect actual
1523         )
1524 '
1525
1526 # Testcase 6d, We don't always want transitive renaming
1527 #   (Related to testcase 1c)
1528 #   Commit O: z/{b,c}, x/d
1529 #   Commit A: z/{b,c}, x/d (no change)
1530 #   Commit B: y/{b,c}, z/d
1531 #   Expected: y/{b,c}, z/d
1532 #   NOTE: Again, this seems obvious but just checking that the implementation
1533 #         doesn't "accidentally detect a rename" and give us y/{b,c,d}.
1534
1535 test_setup_6d () {
1536         test_create_repo 6d &&
1537         (
1538                 cd 6d &&
1539
1540                 mkdir z &&
1541                 echo b >z/b &&
1542                 echo c >z/c &&
1543                 mkdir x &&
1544                 echo d >x/d &&
1545                 git add z x &&
1546                 test_tick &&
1547                 git commit -m "O" &&
1548
1549                 git branch O &&
1550                 git branch A &&
1551                 git branch B &&
1552
1553                 git checkout A &&
1554                 test_tick &&
1555                 git commit --allow-empty -m "A" &&
1556
1557                 git checkout B &&
1558                 git mv z y &&
1559                 git mv x z &&
1560                 test_tick &&
1561                 git commit -m "B"
1562         )
1563 }
1564
1565 test_expect_success '6d: We do not always want transitive renaming' '
1566         test_setup_6d &&
1567         (
1568                 cd 6d &&
1569
1570                 git checkout A^0 &&
1571
1572                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
1573
1574                 git ls-files -s >out &&
1575                 test_line_count = 3 out &&
1576                 git ls-files -u >out &&
1577                 test_line_count = 0 out &&
1578                 git ls-files -o >out &&
1579                 test_line_count = 1 out &&
1580
1581                 git rev-parse >actual \
1582                         HEAD:y/b HEAD:y/c HEAD:z/d &&
1583                 git rev-parse >expect \
1584                         O:z/b    O:z/c    O:x/d &&
1585                 test_cmp expect actual
1586         )
1587 '
1588
1589 # Testcase 6e, Add/add from one-side
1590 #   Commit O: z/{b,c}
1591 #   Commit A: z/{b,c} (no change)
1592 #   Commit B: y/{b,c,d_1}, z/d_2
1593 #   Expected: y/{b,c,d_1}, z/d_2
1594 #   NOTE: Again, this seems obvious but just checking that the implementation
1595 #         doesn't "accidentally detect a rename" and give us y/{b,c} +
1596 #         add/add conflict on y/d_1 vs y/d_2.
1597
1598 test_setup_6e () {
1599         test_create_repo 6e &&
1600         (
1601                 cd 6e &&
1602
1603                 mkdir z &&
1604                 echo b >z/b &&
1605                 echo c >z/c &&
1606                 git add z &&
1607                 test_tick &&
1608                 git commit -m "O" &&
1609
1610                 git branch O &&
1611                 git branch A &&
1612                 git branch B &&
1613
1614                 git checkout A &&
1615                 test_tick &&
1616                 git commit --allow-empty -m "A" &&
1617
1618                 git checkout B &&
1619                 git mv z y &&
1620                 echo d1 > y/d &&
1621                 mkdir z &&
1622                 echo d2 > z/d &&
1623                 git add y/d z/d &&
1624                 test_tick &&
1625                 git commit -m "B"
1626         )
1627 }
1628
1629 test_expect_success '6e: Add/add from one side' '
1630         test_setup_6e &&
1631         (
1632                 cd 6e &&
1633
1634                 git checkout A^0 &&
1635
1636                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
1637
1638                 git ls-files -s >out &&
1639                 test_line_count = 4 out &&
1640                 git ls-files -u >out &&
1641                 test_line_count = 0 out &&
1642                 git ls-files -o >out &&
1643                 test_line_count = 1 out &&
1644
1645                 git rev-parse >actual \
1646                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/d &&
1647                 git rev-parse >expect \
1648                         O:z/b    O:z/c    B:y/d    B:z/d &&
1649                 test_cmp expect actual
1650         )
1651 '
1652
1653 ###########################################################################
1654 # Rules suggested by section 6:
1655 #
1656 #   Only apply implicit directory renames to directories if the other
1657 #   side of history is the one doing the renaming.
1658 ###########################################################################
1659
1660
1661 ###########################################################################
1662 # SECTION 7: More involved Edge/Corner cases
1663 #
1664 # The ruleset we have generated in the above sections seems to provide
1665 # well-defined merges.  But can we find edge/corner cases that either (a)
1666 # are harder for users to understand, or (b) have a resolution that is
1667 # non-intuitive or suboptimal?
1668 #
1669 # The testcases in this section dive into cases that I've tried to craft in
1670 # a way to find some that might be surprising to users or difficult for
1671 # them to understand (the next section will look at non-intuitive or
1672 # suboptimal merge results).  Some of the testcases are similar to ones
1673 # from past sections, but have been simplified to try to highlight error
1674 # messages using a "modified" path (due to the directory rename).  Are
1675 # users okay with these?
1676 #
1677 # In my opinion, testcases that are difficult to understand from this
1678 # section is due to difficulty in the testcase rather than the directory
1679 # renaming (similar to how t6042 and t6036 have difficult resolutions due
1680 # to the problem setup itself being complex).  And I don't think the
1681 # error messages are a problem.
1682 #
1683 # On the other hand, the testcases in section 8 worry me slightly more...
1684 ###########################################################################
1685
1686 # Testcase 7a, rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file
1687 #   Commit O: z/{b,c}
1688 #   Commit A: y/{b,c}
1689 #   Commit B: w/b, x/c, z/d
1690 #   Expected: y/d, CONFLICT(rename/rename for both z/b and z/c)
1691 #   NOTE: There's a rename of z/ here, y/ has more renames, so z/d -> y/d.
1692
1693 test_setup_7a () {
1694         test_create_repo 7a &&
1695         (
1696                 cd 7a &&
1697
1698                 mkdir z &&
1699                 echo b >z/b &&
1700                 echo c >z/c &&
1701                 git add z &&
1702                 test_tick &&
1703                 git commit -m "O" &&
1704
1705                 git branch O &&
1706                 git branch A &&
1707                 git branch B &&
1708
1709                 git checkout A &&
1710                 git mv z y &&
1711                 test_tick &&
1712                 git commit -m "A" &&
1713
1714                 git checkout B &&
1715                 mkdir w &&
1716                 mkdir x &&
1717                 git mv z/b w/ &&
1718                 git mv z/c x/ &&
1719                 echo d > z/d &&
1720                 git add z/d &&
1721                 test_tick &&
1722                 git commit -m "B"
1723         )
1724 }
1725
1726 test_expect_success '7a: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file' '
1727         test_setup_7a &&
1728         (
1729                 cd 7a &&
1730
1731                 git checkout A^0 &&
1732
1733                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1734                 test_i18ngrep "CONFLICT (rename/rename).*z/b.*y/b.*w/b" out &&
1735                 test_i18ngrep "CONFLICT (rename/rename).*z/c.*y/c.*x/c" out &&
1736
1737                 git ls-files -s >out &&
1738                 test_line_count = 7 out &&
1739                 git ls-files -u >out &&
1740                 test_line_count = 6 out &&
1741                 git ls-files -o >out &&
1742                 test_line_count = 1 out &&
1743
1744                 git rev-parse >actual \
1745                         :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:x/c :0:y/d &&
1746                 git rev-parse >expect \
1747                          O:z/b  O:z/b  O:z/b  O:z/c  O:z/c  O:z/c  B:z/d &&
1748                 test_cmp expect actual &&
1749
1750                 git hash-object >actual \
1751                         y/b   w/b   y/c   x/c &&
1752                 git rev-parse >expect \
1753                         O:z/b O:z/b O:z/c O:z/c &&
1754                 test_cmp expect actual
1755         )
1756 '
1757
1758 # Testcase 7b, rename/rename(2to1), but only due to transitive rename
1759 #   (Related to testcase 1d)
1760 #   Commit O: z/{b,c},     x/d_1, w/d_2
1761 #   Commit A: y/{b,c,d_2}, x/d_1
1762 #   Commit B: z/{b,c,d_1},        w/d_2
1763 #   Expected: y/{b,c}, CONFLICT(rename/rename(2to1): x/d_1, w/d_2 -> y_d)
1764
1765 test_setup_7b () {
1766         test_create_repo 7b &&
1767         (
1768                 cd 7b &&
1769
1770                 mkdir z &&
1771                 mkdir x &&
1772                 mkdir w &&
1773                 echo b >z/b &&
1774                 echo c >z/c &&
1775                 echo d1 > x/d &&
1776                 echo d2 > w/d &&
1777                 git add z x w &&
1778                 test_tick &&
1779                 git commit -m "O" &&
1780
1781                 git branch O &&
1782                 git branch A &&
1783                 git branch B &&
1784
1785                 git checkout A &&
1786                 git mv z y &&
1787                 git mv w/d y/ &&
1788                 test_tick &&
1789                 git commit -m "A" &&
1790
1791                 git checkout B &&
1792                 git mv x/d z/ &&
1793                 rmdir x &&
1794                 test_tick &&
1795                 git commit -m "B"
1796         )
1797 }
1798
1799 test_expect_success '7b: rename/rename(2to1), but only due to transitive rename' '
1800         test_setup_7b &&
1801         (
1802                 cd 7b &&
1803
1804                 git checkout A^0 &&
1805
1806                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1807                 test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
1808
1809                 git ls-files -s >out &&
1810                 test_line_count = 4 out &&
1811                 git ls-files -u >out &&
1812                 test_line_count = 2 out &&
1813                 git ls-files -o >out &&
1814                 test_line_count = 1 out &&
1815
1816                 git rev-parse >actual \
1817                         :0:y/b :0:y/c :2:y/d :3:y/d &&
1818                 git rev-parse >expect \
1819                          O:z/b  O:z/c  O:w/d  O:x/d &&
1820                 test_cmp expect actual &&
1821
1822                 # Test that the two-way merge in y/d is as expected
1823                 git cat-file -p :2:y/d >expect &&
1824                 git cat-file -p :3:y/d >other &&
1825                 >empty &&
1826                 test_must_fail git merge-file \
1827                         -L "HEAD" \
1828                         -L "" \
1829                         -L "B^0" \
1830                         expect empty other &&
1831                 test_cmp expect y/d
1832         )
1833 '
1834
1835 # Testcase 7c, rename/rename(1to...2or3); transitive rename may add complexity
1836 #   (Related to testcases 3b and 5c)
1837 #   Commit O: z/{b,c}, x/d
1838 #   Commit A: y/{b,c}, w/d
1839 #   Commit B: z/{b,c,d}
1840 #   Expected: y/{b,c}, CONFLICT(x/d -> w/d vs. y/d)
1841 #   NOTE: z/ was renamed to y/ so we do want to report
1842 #         neither CONFLICT(x/d -> w/d vs. z/d)
1843 #         nor CONFLiCT x/d -> w/d vs. y/d vs. z/d)
1844
1845 test_setup_7c () {
1846         test_create_repo 7c &&
1847         (
1848                 cd 7c &&
1849
1850                 mkdir z &&
1851                 echo b >z/b &&
1852                 echo c >z/c &&
1853                 mkdir x &&
1854                 echo d >x/d &&
1855                 git add z x &&
1856                 test_tick &&
1857                 git commit -m "O" &&
1858
1859                 git branch O &&
1860                 git branch A &&
1861                 git branch B &&
1862
1863                 git checkout A &&
1864                 git mv z y &&
1865                 git mv x w &&
1866                 test_tick &&
1867                 git commit -m "A" &&
1868
1869                 git checkout B &&
1870                 git mv x/d z/ &&
1871                 rmdir x &&
1872                 test_tick &&
1873                 git commit -m "B"
1874         )
1875 }
1876
1877 test_expect_success '7c: rename/rename(1to...2or3); transitive rename may add complexity' '
1878         test_setup_7c &&
1879         (
1880                 cd 7c &&
1881
1882                 git checkout A^0 &&
1883
1884                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1885                 test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*y/d" out &&
1886
1887                 git ls-files -s >out &&
1888                 test_line_count = 5 out &&
1889                 git ls-files -u >out &&
1890                 test_line_count = 3 out &&
1891                 git ls-files -o >out &&
1892                 test_line_count = 1 out &&
1893
1894                 git rev-parse >actual \
1895                         :0:y/b :0:y/c :1:x/d :2:w/d :3:y/d &&
1896                 git rev-parse >expect \
1897                          O:z/b  O:z/c  O:x/d  O:x/d  O:x/d &&
1898                 test_cmp expect actual
1899         )
1900 '
1901
1902 # Testcase 7d, transitive rename involved in rename/delete; how is it reported?
1903 #   (Related somewhat to testcases 5b and 8d)
1904 #   Commit O: z/{b,c}, x/d
1905 #   Commit A: y/{b,c}
1906 #   Commit B: z/{b,c,d}
1907 #   Expected: y/{b,c}, CONFLICT(delete x/d vs rename to y/d)
1908 #   NOTE: z->y so NOT CONFLICT(delete x/d vs rename to z/d)
1909
1910 test_setup_7d () {
1911         test_create_repo 7d &&
1912         (
1913                 cd 7d &&
1914
1915                 mkdir z &&
1916                 echo b >z/b &&
1917                 echo c >z/c &&
1918                 mkdir x &&
1919                 echo d >x/d &&
1920                 git add z x &&
1921                 test_tick &&
1922                 git commit -m "O" &&
1923
1924                 git branch O &&
1925                 git branch A &&
1926                 git branch B &&
1927
1928                 git checkout A &&
1929                 git mv z y &&
1930                 git rm -rf x &&
1931                 test_tick &&
1932                 git commit -m "A" &&
1933
1934                 git checkout B &&
1935                 git mv x/d z/ &&
1936                 rmdir x &&
1937                 test_tick &&
1938                 git commit -m "B"
1939         )
1940 }
1941
1942 test_expect_success '7d: transitive rename involved in rename/delete; how is it reported?' '
1943         test_setup_7d &&
1944         (
1945                 cd 7d &&
1946
1947                 git checkout A^0 &&
1948
1949                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
1950                 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1951
1952                 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
1953                 then
1954                         git ls-files -s >out &&
1955                         test_line_count = 4 out &&
1956                         git ls-files -u >out &&
1957                         test_line_count = 2 out &&
1958                         git ls-files -o >out &&
1959                         test_line_count = 1 out &&
1960
1961                         git rev-parse >actual \
1962                                 :0:y/b :0:y/c :1:y/d :3:y/d &&
1963                         git rev-parse >expect \
1964                                  O:z/b  O:z/c  O:x/d  O:x/d
1965                 else
1966                         git ls-files -s >out &&
1967                         test_line_count = 3 out &&
1968                         git ls-files -u >out &&
1969                         test_line_count = 1 out &&
1970                         git ls-files -o >out &&
1971                         test_line_count = 1 out &&
1972
1973                         git rev-parse >actual \
1974                                 :0:y/b :0:y/c :3:y/d &&
1975                         git rev-parse >expect \
1976                                  O:z/b  O:z/c  O:x/d
1977                 fi &&
1978                 test_cmp expect actual
1979         )
1980 '
1981
1982 # Testcase 7e, transitive rename in rename/delete AND dirs in the way
1983 #   (Very similar to 'both rename source and destination involved in D/F conflict' from t6022-merge-rename.sh)
1984 #   (Also related to testcases 9c and 9d)
1985 #   Commit O: z/{b,c},     x/d_1
1986 #   Commit A: y/{b,c,d/g}, x/d/f
1987 #   Commit B: z/{b,c,d_1}
1988 #   Expected: rename/delete(x/d_1->y/d_1 vs. None) + D/F conflict on y/d
1989 #             y/{b,c,d/g}, y/d_1~B^0, x/d/f
1990
1991 #   NOTE: The main path of interest here is d_1 and where it ends up, but
1992 #         this is actually a case that has two potential directory renames
1993 #         involved and D/F conflict(s), so it makes sense to walk through
1994 #         each step.
1995 #
1996 #         Commit A renames z/ -> y/.  Thus everything that B adds to z/
1997 #         should be instead moved to y/.  This gives us the D/F conflict on
1998 #         y/d because x/d_1 -> z/d_1 -> y/d_1 conflicts with y/d/g.
1999 #
2000 #         Further, commit B renames x/ -> z/, thus everything A adds to x/
2001 #         should instead be moved to z/...BUT we removed z/ and renamed it
2002 #         to y/, so maybe everything should move not from x/ to z/, but
2003 #         from x/ to z/ to y/.  Doing so might make sense from the logic so
2004 #         far, but note that commit A had both an x/ and a y/; it did the
2005 #         renaming of z/ to y/ and created x/d/f and it clearly made these
2006 #         things separate, so it doesn't make much sense to push these
2007 #         together.  Doing so is what I'd call a doubly transitive rename;
2008 #         see testcases 9c and 9d for further discussion of this issue and
2009 #         how it's resolved.
2010
2011 test_setup_7e () {
2012         test_create_repo 7e &&
2013         (
2014                 cd 7e &&
2015
2016                 mkdir z &&
2017                 echo b >z/b &&
2018                 echo c >z/c &&
2019                 mkdir x &&
2020                 echo d1 >x/d &&
2021                 git add z x &&
2022                 test_tick &&
2023                 git commit -m "O" &&
2024
2025                 git branch O &&
2026                 git branch A &&
2027                 git branch B &&
2028
2029                 git checkout A &&
2030                 git mv z y &&
2031                 git rm x/d &&
2032                 mkdir -p x/d &&
2033                 mkdir -p y/d &&
2034                 echo f >x/d/f &&
2035                 echo g >y/d/g &&
2036                 git add x/d/f y/d/g &&
2037                 test_tick &&
2038                 git commit -m "A" &&
2039
2040                 git checkout B &&
2041                 git mv x/d z/ &&
2042                 rmdir x &&
2043                 test_tick &&
2044                 git commit -m "B"
2045         )
2046 }
2047
2048 test_expect_success '7e: transitive rename in rename/delete AND dirs in the way' '
2049         test_setup_7e &&
2050         (
2051                 cd 7e &&
2052
2053                 git checkout A^0 &&
2054
2055                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2056                 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
2057
2058                 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
2059                 then
2060                         git ls-files -s >out &&
2061                         test_line_count = 6 out &&
2062                         git ls-files -u >out &&
2063                         test_line_count = 2 out &&
2064                         git ls-files -o >out &&
2065                         test_line_count = 1 out &&
2066
2067                         git rev-parse >actual \
2068                                 :0:x/d/f :0:y/d/g :0:y/b :0:y/c :1:y/d~B^0 :3:y/d~B^0 &&
2069                         git rev-parse >expect \
2070                                  A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d      O:x/d
2071                 else
2072                         git ls-files -s >out &&
2073                         test_line_count = 5 out &&
2074                         git ls-files -u >out &&
2075                         test_line_count = 1 out &&
2076                         git ls-files -o >out &&
2077                         test_line_count = 2 out &&
2078
2079                         git rev-parse >actual \
2080                                 :0:x/d/f :0:y/d/g :0:y/b :0:y/c :3:y/d &&
2081                         git rev-parse >expect \
2082                                  A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d
2083                 fi &&
2084                 test_cmp expect actual &&
2085
2086                 git hash-object y/d~B^0 >actual &&
2087                 git rev-parse O:x/d >expect &&
2088                 test_cmp expect actual
2089         )
2090 '
2091
2092 ###########################################################################
2093 # SECTION 8: Suboptimal merges
2094 #
2095 # As alluded to in the last section, the ruleset we have built up for
2096 # detecting directory renames unfortunately has some special cases where it
2097 # results in slightly suboptimal or non-intuitive behavior.  This section
2098 # explores these cases.
2099 #
2100 # To be fair, we already had non-intuitive or suboptimal behavior for most
2101 # of these cases in git before introducing implicit directory rename
2102 # detection, but it'd be nice if there was a modified ruleset out there
2103 # that handled these cases a bit better.
2104 ###########################################################################
2105
2106 # Testcase 8a, Dual-directory rename, one into the others' way
2107 #   Commit O. x/{a,b},   y/{c,d}
2108 #   Commit A. x/{a,b,e}, y/{c,d,f}
2109 #   Commit B. y/{a,b},   z/{c,d}
2110 #
2111 # Possible Resolutions:
2112 #   w/o dir-rename detection: y/{a,b,f},   z/{c,d},   x/e
2113 #   Currently expected:       y/{a,b,e,f}, z/{c,d}
2114 #   Optimal:                  y/{a,b,e},   z/{c,d,f}
2115 #
2116 # Note: Both x and y got renamed and it'd be nice to detect both, and we do
2117 # better with directory rename detection than git did without, but the
2118 # simple rule from section 5 prevents me from handling this as optimally as
2119 # we potentially could.
2120
2121 test_setup_8a () {
2122         test_create_repo 8a &&
2123         (
2124                 cd 8a &&
2125
2126                 mkdir x &&
2127                 mkdir y &&
2128                 echo a >x/a &&
2129                 echo b >x/b &&
2130                 echo c >y/c &&
2131                 echo d >y/d &&
2132                 git add x y &&
2133                 test_tick &&
2134                 git commit -m "O" &&
2135
2136                 git branch O &&
2137                 git branch A &&
2138                 git branch B &&
2139
2140                 git checkout A &&
2141                 echo e >x/e &&
2142                 echo f >y/f &&
2143                 git add x/e y/f &&
2144                 test_tick &&
2145                 git commit -m "A" &&
2146
2147                 git checkout B &&
2148                 git mv y z &&
2149                 git mv x y &&
2150                 test_tick &&
2151                 git commit -m "B"
2152         )
2153 }
2154
2155 test_expect_success '8a: Dual-directory rename, one into the others way' '
2156         test_setup_8a &&
2157         (
2158                 cd 8a &&
2159
2160                 git checkout A^0 &&
2161
2162                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2163
2164                 git ls-files -s >out &&
2165                 test_line_count = 6 out &&
2166                 git ls-files -u >out &&
2167                 test_line_count = 0 out &&
2168                 git ls-files -o >out &&
2169                 test_line_count = 1 out &&
2170
2171                 git rev-parse >actual \
2172                         HEAD:y/a HEAD:y/b HEAD:y/e HEAD:y/f HEAD:z/c HEAD:z/d &&
2173                 git rev-parse >expect \
2174                         O:x/a    O:x/b    A:x/e    A:y/f    O:y/c    O:y/d &&
2175                 test_cmp expect actual
2176         )
2177 '
2178
2179 # Testcase 8b, Dual-directory rename, one into the others' way, with conflicting filenames
2180 #   Commit O. x/{a_1,b_1},     y/{a_2,b_2}
2181 #   Commit A. x/{a_1,b_1,e_1}, y/{a_2,b_2,e_2}
2182 #   Commit B. y/{a_1,b_1},     z/{a_2,b_2}
2183 #
2184 #   w/o dir-rename detection: y/{a_1,b_1,e_2}, z/{a_2,b_2}, x/e_1
2185 #   Currently expected:       <same>
2186 #   Scary:                    y/{a_1,b_1},     z/{a_2,b_2}, CONFLICT(add/add, e_1 vs. e_2)
2187 #   Optimal:                  y/{a_1,b_1,e_1}, z/{a_2,b_2,e_2}
2188 #
2189 # Note: Very similar to 8a, except instead of 'e' and 'f' in directories x and
2190 # y, both are named 'e'.  Without directory rename detection, neither file
2191 # moves directories.  Implement directory rename detection suboptimally, and
2192 # you get an add/add conflict, but both files were added in commit A, so this
2193 # is an add/add conflict where one side of history added both files --
2194 # something we can't represent in the index.  Obviously, we'd prefer the last
2195 # resolution, but our previous rules are too coarse to allow it.  Using both
2196 # the rules from section 4 and section 5 save us from the Scary resolution,
2197 # making us fall back to pre-directory-rename-detection behavior for both
2198 # e_1 and e_2.
2199
2200 test_setup_8b () {
2201         test_create_repo 8b &&
2202         (
2203                 cd 8b &&
2204
2205                 mkdir x &&
2206                 mkdir y &&
2207                 echo a1 >x/a &&
2208                 echo b1 >x/b &&
2209                 echo a2 >y/a &&
2210                 echo b2 >y/b &&
2211                 git add x y &&
2212                 test_tick &&
2213                 git commit -m "O" &&
2214
2215                 git branch O &&
2216                 git branch A &&
2217                 git branch B &&
2218
2219                 git checkout A &&
2220                 echo e1 >x/e &&
2221                 echo e2 >y/e &&
2222                 git add x/e y/e &&
2223                 test_tick &&
2224                 git commit -m "A" &&
2225
2226                 git checkout B &&
2227                 git mv y z &&
2228                 git mv x y &&
2229                 test_tick &&
2230                 git commit -m "B"
2231         )
2232 }
2233
2234 test_expect_success '8b: Dual-directory rename, one into the others way, with conflicting filenames' '
2235         test_setup_8b &&
2236         (
2237                 cd 8b &&
2238
2239                 git checkout A^0 &&
2240
2241                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2242
2243                 git ls-files -s >out &&
2244                 test_line_count = 6 out &&
2245                 git ls-files -u >out &&
2246                 test_line_count = 0 out &&
2247                 git ls-files -o >out &&
2248                 test_line_count = 1 out &&
2249
2250                 git rev-parse >actual \
2251                         HEAD:y/a HEAD:y/b HEAD:z/a HEAD:z/b HEAD:x/e HEAD:y/e &&
2252                 git rev-parse >expect \
2253                         O:x/a    O:x/b    O:y/a    O:y/b    A:x/e    A:y/e &&
2254                 test_cmp expect actual
2255         )
2256 '
2257
2258 # Testcase 8c, modify/delete or rename+modify/delete?
2259 #   (Related to testcases 5b, 8d, and 9h)
2260 #   Commit O: z/{b,c,d}
2261 #   Commit A: y/{b,c}
2262 #   Commit B: z/{b,c,d_modified,e}
2263 #   Expected: y/{b,c,e}, CONFLICT(modify/delete: on z/d)
2264 #
2265 #   Note: It could easily be argued that the correct resolution here is
2266 #         y/{b,c,e}, CONFLICT(rename/delete: z/d -> y/d vs deleted)
2267 #         and that the modified version of d should be present in y/ after
2268 #         the merge, just marked as conflicted.  Indeed, I previously did
2269 #         argue that.  But applying directory renames to the side of
2270 #         history where a file is merely modified results in spurious
2271 #         rename/rename(1to2) conflicts -- see testcase 9h.  See also
2272 #         notes in 8d.
2273
2274 test_setup_8c () {
2275         test_create_repo 8c &&
2276         (
2277                 cd 8c &&
2278
2279                 mkdir z &&
2280                 echo b >z/b &&
2281                 echo c >z/c &&
2282                 test_seq 1 10 >z/d &&
2283                 git add z &&
2284                 test_tick &&
2285                 git commit -m "O" &&
2286
2287                 git branch O &&
2288                 git branch A &&
2289                 git branch B &&
2290
2291                 git checkout A &&
2292                 git rm z/d &&
2293                 git mv z y &&
2294                 test_tick &&
2295                 git commit -m "A" &&
2296
2297                 git checkout B &&
2298                 echo 11 >z/d &&
2299                 test_chmod +x z/d &&
2300                 echo e >z/e &&
2301                 git add z/d z/e &&
2302                 test_tick &&
2303                 git commit -m "B"
2304         )
2305 }
2306
2307 test_expect_success '8c: modify/delete or rename+modify/delete' '
2308         test_setup_8c &&
2309         (
2310                 cd 8c &&
2311
2312                 git checkout A^0 &&
2313
2314                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2315                 test_i18ngrep "CONFLICT (modify/delete).* z/d" out &&
2316
2317                 git ls-files -s >out &&
2318                 test_line_count = 5 out &&
2319                 git ls-files -u >out &&
2320                 test_line_count = 2 out &&
2321                 git ls-files -o >out &&
2322                 test_line_count = 1 out &&
2323
2324                 git rev-parse >actual \
2325                         :0:y/b :0:y/c :0:y/e :1:z/d :3:z/d &&
2326                 git rev-parse >expect \
2327                          O:z/b  O:z/c  B:z/e  O:z/d  B:z/d &&
2328                 test_cmp expect actual &&
2329
2330                 test_must_fail git rev-parse :2:z/d &&
2331                 git ls-files -s z/d | grep ^100755 &&
2332                 test_path_is_file z/d &&
2333                 test_path_is_missing y/d
2334         )
2335 '
2336
2337 # Testcase 8d, rename/delete...or not?
2338 #   (Related to testcase 5b; these may appear slightly inconsistent to users;
2339 #    Also related to testcases 7d and 7e)
2340 #   Commit O: z/{b,c,d}
2341 #   Commit A: y/{b,c}
2342 #   Commit B: z/{b,c,d,e}
2343 #   Expected: y/{b,c,e}
2344 #
2345 #   Note: It would also be somewhat reasonable to resolve this as
2346 #             y/{b,c,e}, CONFLICT(rename/delete: x/d -> y/d or deleted)
2347 #
2348 #   In this case, I'm leaning towards: commit A was the one that deleted z/d
2349 #   and it did the rename of z to y, so the two "conflicts" (rename vs.
2350 #   delete) are both coming from commit A, which is illogical.  Conflicts
2351 #   during merging are supposed to be about opposite sides doing things
2352 #   differently.
2353
2354 test_setup_8d () {
2355         test_create_repo 8d &&
2356         (
2357                 cd 8d &&
2358
2359                 mkdir z &&
2360                 echo b >z/b &&
2361                 echo c >z/c &&
2362                 test_seq 1 10 >z/d &&
2363                 git add z &&
2364                 test_tick &&
2365                 git commit -m "O" &&
2366
2367                 git branch O &&
2368                 git branch A &&
2369                 git branch B &&
2370
2371                 git checkout A &&
2372                 git rm z/d &&
2373                 git mv z y &&
2374                 test_tick &&
2375                 git commit -m "A" &&
2376
2377                 git checkout B &&
2378                 echo e >z/e &&
2379                 git add z/e &&
2380                 test_tick &&
2381                 git commit -m "B"
2382         )
2383 }
2384
2385 test_expect_success '8d: rename/delete...or not?' '
2386         test_setup_8d &&
2387         (
2388                 cd 8d &&
2389
2390                 git checkout A^0 &&
2391
2392                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2393
2394                 git ls-files -s >out &&
2395                 test_line_count = 3 out &&
2396
2397                 git rev-parse >actual \
2398                         HEAD:y/b HEAD:y/c HEAD:y/e &&
2399                 git rev-parse >expect \
2400                         O:z/b    O:z/c    B:z/e &&
2401                 test_cmp expect actual
2402         )
2403 '
2404
2405 # Testcase 8e, Both sides rename, one side adds to original directory
2406 #   Commit O: z/{b,c}
2407 #   Commit A: y/{b,c}
2408 #   Commit B: w/{b,c}, z/d
2409 #
2410 # Possible Resolutions:
2411 #   if z not considered renamed: z/d, CONFLICT(z/b -> y/b vs. w/b),
2412 #                                     CONFLICT(z/c -> y/c vs. w/c)
2413 #   if z->y rename considered:   y/d, CONFLICT(z/b -> y/b vs. w/b),
2414 #                                     CONFLICT(z/c -> y/c vs. w/c)
2415 #   Optimal:                     ??
2416 #
2417 # Notes: In commit A, directory z got renamed to y.  In commit B, directory z
2418 #        did NOT get renamed; the directory is still present; instead it is
2419 #        considered to have just renamed a subset of paths in directory z
2420 #        elsewhere.  This is much like testcase 6b2 (where commit B moves all
2421 #        the original paths out of z/ but opted to keep d within z/).
2422 #
2423 #        It was not clear in the past what should be done with this testcase;
2424 #        in fact, I noted that I "just picked one" previously.  However,
2425 #        following the new logic for testcase 6b2, we should take the rename
2426 #        and move z/d to y/d.
2427 #
2428 #        6b1, 6b2, and this case are definitely somewhat fuzzy in terms of
2429 #        whether they are optimal for end users, but (a) the default for
2430 #        directory rename detection is to mark these all as conflicts
2431 #        anyway, (b) it feels like this is less prone to higher order corner
2432 #        case confusion, and (c) the current algorithm requires less global
2433 #        knowledge (i.e. less coupling in the algorithm between renames done
2434 #        on both sides) which thus means users are better able to predict
2435 #        the behavior, and predict it without computing as many details.
2436
2437 test_setup_8e () {
2438         test_create_repo 8e &&
2439         (
2440                 cd 8e &&
2441
2442                 mkdir z &&
2443                 echo b >z/b &&
2444                 echo c >z/c &&
2445                 git add z &&
2446                 test_tick &&
2447                 git commit -m "O" &&
2448
2449                 git branch O &&
2450                 git branch A &&
2451                 git branch B &&
2452
2453                 git checkout A &&
2454                 git mv z y &&
2455                 test_tick &&
2456                 git commit -m "A" &&
2457
2458                 git checkout B &&
2459                 git mv z w &&
2460                 mkdir z &&
2461                 echo d >z/d &&
2462                 git add z/d &&
2463                 test_tick &&
2464                 git commit -m "B"
2465         )
2466 }
2467
2468 test_expect_success '8e: Both sides rename, one side adds to original directory' '
2469         test_setup_8e &&
2470         (
2471                 cd 8e &&
2472
2473                 git checkout A^0 &&
2474
2475                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
2476                 test_i18ngrep CONFLICT.*rename/rename.*z/c.*y/c.*w/c out &&
2477                 test_i18ngrep CONFLICT.*rename/rename.*z/b.*y/b.*w/b out &&
2478
2479                 git ls-files -s >out &&
2480                 test_line_count = 7 out &&
2481                 git ls-files -u >out &&
2482                 test_line_count = 6 out &&
2483                 git ls-files -o >out &&
2484                 test_line_count = 2 out &&
2485
2486                 git rev-parse >actual \
2487                         :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:w/c :0:y/d &&
2488                 git rev-parse >expect \
2489                          O:z/b  O:z/b  O:z/b  O:z/c  O:z/c  O:z/c  B:z/d &&
2490                 test_cmp expect actual &&
2491
2492                 git hash-object >actual \
2493                         y/b   w/b   y/c   w/c &&
2494                 git rev-parse >expect \
2495                         O:z/b O:z/b O:z/c O:z/c &&
2496                 test_cmp expect actual &&
2497
2498                 test_path_is_missing z/b &&
2499                 test_path_is_missing z/c
2500         )
2501 '
2502
2503 ###########################################################################
2504 # SECTION 9: Other testcases
2505 #
2506 # This section consists of miscellaneous testcases I thought of during
2507 # the implementation which round out the testing.
2508 ###########################################################################
2509
2510 # Testcase 9a, Inner renamed directory within outer renamed directory
2511 #   (Related to testcase 1f)
2512 #   Commit O: z/{b,c,d/{e,f,g}}
2513 #   Commit A: y/{b,c}, x/w/{e,f,g}
2514 #   Commit B: z/{b,c,d/{e,f,g,h},i}
2515 #   Expected: y/{b,c,i}, x/w/{e,f,g,h}
2516 #   NOTE: The only reason this one is interesting is because when a directory
2517 #         is split into multiple other directories, we determine by the weight
2518 #         of which one had the most paths going to it.  A naive implementation
2519 #         of that could take the new file in commit B at z/i to x/w/i or x/i.
2520
2521 test_setup_9a () {
2522         test_create_repo 9a &&
2523         (
2524                 cd 9a &&
2525
2526                 mkdir -p z/d &&
2527                 echo b >z/b &&
2528                 echo c >z/c &&
2529                 echo e >z/d/e &&
2530                 echo f >z/d/f &&
2531                 echo g >z/d/g &&
2532                 git add z &&
2533                 test_tick &&
2534                 git commit -m "O" &&
2535
2536                 git branch O &&
2537                 git branch A &&
2538                 git branch B &&
2539
2540                 git checkout A &&
2541                 mkdir x &&
2542                 git mv z/d x/w &&
2543                 git mv z y &&
2544                 test_tick &&
2545                 git commit -m "A" &&
2546
2547                 git checkout B &&
2548                 echo h >z/d/h &&
2549                 echo i >z/i &&
2550                 git add z &&
2551                 test_tick &&
2552                 git commit -m "B"
2553         )
2554 }
2555
2556 test_expect_success '9a: Inner renamed directory within outer renamed directory' '
2557         test_setup_9a &&
2558         (
2559                 cd 9a &&
2560
2561                 git checkout A^0 &&
2562
2563                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2564
2565                 git ls-files -s >out &&
2566                 test_line_count = 7 out &&
2567                 git ls-files -u >out &&
2568                 test_line_count = 0 out &&
2569                 git ls-files -o >out &&
2570                 test_line_count = 1 out &&
2571
2572                 git rev-parse >actual \
2573                         HEAD:y/b HEAD:y/c HEAD:y/i &&
2574                 git rev-parse >expect \
2575                         O:z/b    O:z/c    B:z/i &&
2576                 test_cmp expect actual &&
2577
2578                 git rev-parse >actual \
2579                         HEAD:x/w/e HEAD:x/w/f HEAD:x/w/g HEAD:x/w/h &&
2580                 git rev-parse >expect \
2581                         O:z/d/e    O:z/d/f    O:z/d/g    B:z/d/h &&
2582                 test_cmp expect actual
2583         )
2584 '
2585
2586 # Testcase 9b, Transitive rename with content merge
2587 #   (Related to testcase 1c)
2588 #   Commit O: z/{b,c},   x/d_1
2589 #   Commit A: y/{b,c},   x/d_2
2590 #   Commit B: z/{b,c,d_3}
2591 #   Expected: y/{b,c,d_merged}
2592
2593 test_setup_9b () {
2594         test_create_repo 9b &&
2595         (
2596                 cd 9b &&
2597
2598                 mkdir z &&
2599                 echo b >z/b &&
2600                 echo c >z/c &&
2601                 mkdir x &&
2602                 test_seq 1 10 >x/d &&
2603                 git add z x &&
2604                 test_tick &&
2605                 git commit -m "O" &&
2606
2607                 git branch O &&
2608                 git branch A &&
2609                 git branch B &&
2610
2611                 git checkout A &&
2612                 git mv z y &&
2613                 test_seq 1 11 >x/d &&
2614                 git add x/d &&
2615                 test_tick &&
2616                 git commit -m "A" &&
2617
2618                 git checkout B &&
2619                 test_seq 0 10 >x/d &&
2620                 git mv x/d z/d &&
2621                 git add z/d &&
2622                 test_tick &&
2623                 git commit -m "B"
2624         )
2625 }
2626
2627 test_expect_success '9b: Transitive rename with content merge' '
2628         test_setup_9b &&
2629         (
2630                 cd 9b &&
2631
2632                 git checkout A^0 &&
2633
2634                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2635
2636                 git ls-files -s >out &&
2637                 test_line_count = 3 out &&
2638
2639                 test_seq 0 11 >expected &&
2640                 test_cmp expected y/d &&
2641                 git add expected &&
2642                 git rev-parse >actual \
2643                         HEAD:y/b HEAD:y/c HEAD:y/d &&
2644                 git rev-parse >expect \
2645                         O:z/b    O:z/c    :0:expected &&
2646                 test_cmp expect actual &&
2647                 test_must_fail git rev-parse HEAD:x/d &&
2648                 test_must_fail git rev-parse HEAD:z/d &&
2649                 test_path_is_missing z/d &&
2650
2651                 test $(git rev-parse HEAD:y/d) != $(git rev-parse O:x/d) &&
2652                 test $(git rev-parse HEAD:y/d) != $(git rev-parse A:x/d) &&
2653                 test $(git rev-parse HEAD:y/d) != $(git rev-parse B:z/d)
2654         )
2655 '
2656
2657 # Testcase 9c, Doubly transitive rename?
2658 #   (Related to testcase 1c, 7e, and 9d)
2659 #   Commit O: z/{b,c},     x/{d,e},    w/f
2660 #   Commit A: y/{b,c},     x/{d,e,f,g}
2661 #   Commit B: z/{b,c,d,e},             w/f
2662 #   Expected: y/{b,c,d,e}, x/{f,g}
2663 #
2664 #   NOTE: x/f and x/g may be slightly confusing here.  The rename from w/f to
2665 #         x/f is clear.  Let's look beyond that.  Here's the logic:
2666 #            Commit B renamed x/ -> z/
2667 #            Commit A renamed z/ -> y/
2668 #         So, we could possibly further rename x/f to z/f to y/f, a doubly
2669 #         transient rename.  However, where does it end?  We can chain these
2670 #         indefinitely (see testcase 9d).  What if there is a D/F conflict
2671 #         at z/f/ or y/f/?  Or just another file conflict at one of those
2672 #         paths?  In the case of an N-long chain of transient renamings,
2673 #         where do we "abort" the rename at?  Can the user make sense of
2674 #         the resulting conflict and resolve it?
2675 #
2676 #         To avoid this confusion I use the simple rule that if the other side
2677 #         of history did a directory rename to a path that your side renamed
2678 #         away, then ignore that particular rename from the other side of
2679 #         history for any implicit directory renames.
2680
2681 test_setup_9c () {
2682         test_create_repo 9c &&
2683         (
2684                 cd 9c &&
2685
2686                 mkdir z &&
2687                 echo b >z/b &&
2688                 echo c >z/c &&
2689                 mkdir x &&
2690                 echo d >x/d &&
2691                 echo e >x/e &&
2692                 mkdir w &&
2693                 echo f >w/f &&
2694                 git add z x w &&
2695                 test_tick &&
2696                 git commit -m "O" &&
2697
2698                 git branch O &&
2699                 git branch A &&
2700                 git branch B &&
2701
2702                 git checkout A &&
2703                 git mv z y &&
2704                 git mv w/f x/ &&
2705                 echo g >x/g &&
2706                 git add x/g &&
2707                 test_tick &&
2708                 git commit -m "A" &&
2709
2710                 git checkout B &&
2711                 git mv x/d z/d &&
2712                 git mv x/e z/e &&
2713                 test_tick &&
2714                 git commit -m "B"
2715         )
2716 }
2717
2718 test_expect_success '9c: Doubly transitive rename?' '
2719         test_setup_9c &&
2720         (
2721                 cd 9c &&
2722
2723                 git checkout A^0 &&
2724
2725                 git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2726                 test_i18ngrep "WARNING: Avoiding applying x -> z rename to x/f" out &&
2727
2728                 git ls-files -s >out &&
2729                 test_line_count = 6 out &&
2730                 git ls-files -o >out &&
2731                 test_line_count = 1 out &&
2732
2733                 git rev-parse >actual \
2734                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e HEAD:x/f HEAD:x/g &&
2735                 git rev-parse >expect \
2736                         O:z/b    O:z/c    O:x/d    O:x/e    O:w/f    A:x/g &&
2737                 test_cmp expect actual
2738         )
2739 '
2740
2741 # Testcase 9d, N-fold transitive rename?
2742 #   (Related to testcase 9c...and 1c and 7e)
2743 #   Commit O: z/a, y/b, x/c, w/d, v/e, u/f
2744 #   Commit A:  y/{a,b},  w/{c,d},  u/{e,f}
2745 #   Commit B: z/{a,t}, x/{b,c}, v/{d,e}, u/f
2746 #   Expected: <see NOTE first>
2747 #
2748 #   NOTE: z/ -> y/ (in commit A)
2749 #         y/ -> x/ (in commit B)
2750 #         x/ -> w/ (in commit A)
2751 #         w/ -> v/ (in commit B)
2752 #         v/ -> u/ (in commit A)
2753 #         So, if we add a file to z, say z/t, where should it end up?  In u?
2754 #         What if there's another file or directory named 't' in one of the
2755 #         intervening directories and/or in u itself?  Also, shouldn't the
2756 #         same logic that places 't' in u/ also move ALL other files to u/?
2757 #         What if there are file or directory conflicts in any of them?  If
2758 #         we attempted to do N-way (N-fold? N-ary? N-uple?) transitive renames
2759 #         like this, would the user have any hope of understanding any
2760 #         conflicts or how their working tree ended up?  I think not, so I'm
2761 #         ruling out N-ary transitive renames for N>1.
2762 #
2763 #   Therefore our expected result is:
2764 #     z/t, y/a, x/b, w/c, u/d, u/e, u/f
2765 #   The reason that v/d DOES get transitively renamed to u/d is that u/ isn't
2766 #   renamed somewhere.  A slightly sub-optimal result, but it uses fairly
2767 #   simple rules that are consistent with what we need for all the other
2768 #   testcases and simplifies things for the user.
2769
2770 test_setup_9d () {
2771         test_create_repo 9d &&
2772         (
2773                 cd 9d &&
2774
2775                 mkdir z y x w v u &&
2776                 echo a >z/a &&
2777                 echo b >y/b &&
2778                 echo c >x/c &&
2779                 echo d >w/d &&
2780                 echo e >v/e &&
2781                 echo f >u/f &&
2782                 git add z y x w v u &&
2783                 test_tick &&
2784                 git commit -m "O" &&
2785
2786                 git branch O &&
2787                 git branch A &&
2788                 git branch B &&
2789
2790                 git checkout A &&
2791                 git mv z/a y/ &&
2792                 git mv x/c w/ &&
2793                 git mv v/e u/ &&
2794                 test_tick &&
2795                 git commit -m "A" &&
2796
2797                 git checkout B &&
2798                 echo t >z/t &&
2799                 git mv y/b x/ &&
2800                 git mv w/d v/ &&
2801                 git add z/t &&
2802                 test_tick &&
2803                 git commit -m "B"
2804         )
2805 }
2806
2807 test_expect_success '9d: N-way transitive rename?' '
2808         test_setup_9d &&
2809         (
2810                 cd 9d &&
2811
2812                 git checkout A^0 &&
2813
2814                 git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2815                 test_i18ngrep "WARNING: Avoiding applying z -> y rename to z/t" out &&
2816                 test_i18ngrep "WARNING: Avoiding applying y -> x rename to y/a" out &&
2817                 test_i18ngrep "WARNING: Avoiding applying x -> w rename to x/b" out &&
2818                 test_i18ngrep "WARNING: Avoiding applying w -> v rename to w/c" out &&
2819
2820                 git ls-files -s >out &&
2821                 test_line_count = 7 out &&
2822                 git ls-files -o >out &&
2823                 test_line_count = 1 out &&
2824
2825                 git rev-parse >actual \
2826                         HEAD:z/t \
2827                         HEAD:y/a HEAD:x/b HEAD:w/c \
2828                         HEAD:u/d HEAD:u/e HEAD:u/f &&
2829                 git rev-parse >expect \
2830                         B:z/t    \
2831                         O:z/a    O:y/b    O:x/c    \
2832                         O:w/d    O:v/e    A:u/f &&
2833                 test_cmp expect actual
2834         )
2835 '
2836
2837 # Testcase 9e, N-to-1 whammo
2838 #   (Related to testcase 9c...and 1c and 7e)
2839 #   Commit O: dir1/{a,b}, dir2/{d,e}, dir3/{g,h}, dirN/{j,k}
2840 #   Commit A: dir1/{a,b,c,yo}, dir2/{d,e,f,yo}, dir3/{g,h,i,yo}, dirN/{j,k,l,yo}
2841 #   Commit B: combined/{a,b,d,e,g,h,j,k}
2842 #   Expected: combined/{a,b,c,d,e,f,g,h,i,j,k,l}, CONFLICT(Nto1) warnings,
2843 #             dir1/yo, dir2/yo, dir3/yo, dirN/yo
2844
2845 test_setup_9e () {
2846         test_create_repo 9e &&
2847         (
2848                 cd 9e &&
2849
2850                 mkdir dir1 dir2 dir3 dirN &&
2851                 echo a >dir1/a &&
2852                 echo b >dir1/b &&
2853                 echo d >dir2/d &&
2854                 echo e >dir2/e &&
2855                 echo g >dir3/g &&
2856                 echo h >dir3/h &&
2857                 echo j >dirN/j &&
2858                 echo k >dirN/k &&
2859                 git add dir* &&
2860                 test_tick &&
2861                 git commit -m "O" &&
2862
2863                 git branch O &&
2864                 git branch A &&
2865                 git branch B &&
2866
2867                 git checkout A &&
2868                 echo c  >dir1/c &&
2869                 echo yo >dir1/yo &&
2870                 echo f  >dir2/f &&
2871                 echo yo >dir2/yo &&
2872                 echo i  >dir3/i &&
2873                 echo yo >dir3/yo &&
2874                 echo l  >dirN/l &&
2875                 echo yo >dirN/yo &&
2876                 git add dir* &&
2877                 test_tick &&
2878                 git commit -m "A" &&
2879
2880                 git checkout B &&
2881                 git mv dir1 combined &&
2882                 git mv dir2/* combined/ &&
2883                 git mv dir3/* combined/ &&
2884                 git mv dirN/* combined/ &&
2885                 test_tick &&
2886                 git commit -m "B"
2887         )
2888 }
2889
2890 test_expect_success C_LOCALE_OUTPUT '9e: N-to-1 whammo' '
2891         test_setup_9e &&
2892         (
2893                 cd 9e &&
2894
2895                 git checkout A^0 &&
2896
2897                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
2898                 grep "CONFLICT (implicit dir rename): Cannot map more than one path to combined/yo" out >error_line &&
2899                 grep -q dir1/yo error_line &&
2900                 grep -q dir2/yo error_line &&
2901                 grep -q dir3/yo error_line &&
2902                 grep -q dirN/yo error_line &&
2903
2904                 git ls-files -s >out &&
2905                 test_line_count = 16 out &&
2906                 git ls-files -u >out &&
2907                 test_line_count = 0 out &&
2908                 git ls-files -o >out &&
2909                 test_line_count = 2 out &&
2910
2911                 git rev-parse >actual \
2912                         :0:combined/a :0:combined/b :0:combined/c \
2913                         :0:combined/d :0:combined/e :0:combined/f \
2914                         :0:combined/g :0:combined/h :0:combined/i \
2915                         :0:combined/j :0:combined/k :0:combined/l &&
2916                 git rev-parse >expect \
2917                          O:dir1/a      O:dir1/b      A:dir1/c \
2918                          O:dir2/d      O:dir2/e      A:dir2/f \
2919                          O:dir3/g      O:dir3/h      A:dir3/i \
2920                          O:dirN/j      O:dirN/k      A:dirN/l &&
2921                 test_cmp expect actual &&
2922
2923                 git rev-parse >actual \
2924                         :0:dir1/yo :0:dir2/yo :0:dir3/yo :0:dirN/yo &&
2925                 git rev-parse >expect \
2926                          A:dir1/yo  A:dir2/yo  A:dir3/yo  A:dirN/yo &&
2927                 test_cmp expect actual
2928         )
2929 '
2930
2931 # Testcase 9f, Renamed directory that only contained immediate subdirs
2932 #   (Related to testcases 1e & 9g)
2933 #   Commit O: goal/{a,b}/$more_files
2934 #   Commit A: priority/{a,b}/$more_files
2935 #   Commit B: goal/{a,b}/$more_files, goal/c
2936 #   Expected: priority/{a,b}/$more_files, priority/c
2937
2938 test_setup_9f () {
2939         test_create_repo 9f &&
2940         (
2941                 cd 9f &&
2942
2943                 mkdir -p goal/a &&
2944                 mkdir -p goal/b &&
2945                 echo foo >goal/a/foo &&
2946                 echo bar >goal/b/bar &&
2947                 echo baz >goal/b/baz &&
2948                 git add goal &&
2949                 test_tick &&
2950                 git commit -m "O" &&
2951
2952                 git branch O &&
2953                 git branch A &&
2954                 git branch B &&
2955
2956                 git checkout A &&
2957                 git mv goal/ priority &&
2958                 test_tick &&
2959                 git commit -m "A" &&
2960
2961                 git checkout B &&
2962                 echo c >goal/c &&
2963                 git add goal/c &&
2964                 test_tick &&
2965                 git commit -m "B"
2966         )
2967 }
2968
2969 test_expect_success '9f: Renamed directory that only contained immediate subdirs' '
2970         test_setup_9f &&
2971         (
2972                 cd 9f &&
2973
2974                 git checkout A^0 &&
2975
2976                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
2977
2978                 git ls-files -s >out &&
2979                 test_line_count = 4 out &&
2980
2981                 git rev-parse >actual \
2982                         HEAD:priority/a/foo \
2983                         HEAD:priority/b/bar \
2984                         HEAD:priority/b/baz \
2985                         HEAD:priority/c &&
2986                 git rev-parse >expect \
2987                         O:goal/a/foo \
2988                         O:goal/b/bar \
2989                         O:goal/b/baz \
2990                         B:goal/c &&
2991                 test_cmp expect actual &&
2992                 test_must_fail git rev-parse HEAD:goal/c
2993         )
2994 '
2995
2996 # Testcase 9g, Renamed directory that only contained immediate subdirs, immediate subdirs renamed
2997 #   (Related to testcases 1e & 9f)
2998 #   Commit O: goal/{a,b}/$more_files
2999 #   Commit A: priority/{alpha,bravo}/$more_files
3000 #   Commit B: goal/{a,b}/$more_files, goal/c
3001 #   Expected: priority/{alpha,bravo}/$more_files, priority/c
3002 # We currently fail this test because the directory renames we detect are
3003 #   goal/a/ -> priority/alpha/
3004 #   goal/b/ -> priority/bravo/
3005 # We do not detect
3006 #   goal/   -> priority/
3007 # because of no files found within goal/, and the fact that "a" != "alpha"
3008 # and "b" != "bravo".  But I'm not sure it's really a failure given that
3009 # viewpoint...
3010
3011 test_setup_9g () {
3012         test_create_repo 9g &&
3013         (
3014                 cd 9g &&
3015
3016                 mkdir -p goal/a &&
3017                 mkdir -p goal/b &&
3018                 echo foo >goal/a/foo &&
3019                 echo bar >goal/b/bar &&
3020                 echo baz >goal/b/baz &&
3021                 git add goal &&
3022                 test_tick &&
3023                 git commit -m "O" &&
3024
3025                 git branch O &&
3026                 git branch A &&
3027                 git branch B &&
3028
3029                 git checkout A &&
3030                 mkdir priority &&
3031                 git mv goal/a/ priority/alpha &&
3032                 git mv goal/b/ priority/beta &&
3033                 rmdir goal/ &&
3034                 test_tick &&
3035                 git commit -m "A" &&
3036
3037                 git checkout B &&
3038                 echo c >goal/c &&
3039                 git add goal/c &&
3040                 test_tick &&
3041                 git commit -m "B"
3042         )
3043 }
3044
3045 test_expect_failure '9g: Renamed directory that only contained immediate subdirs, immediate subdirs renamed' '
3046         test_setup_9g &&
3047         (
3048                 cd 9g &&
3049
3050                 git checkout A^0 &&
3051
3052                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
3053
3054                 git ls-files -s >out &&
3055                 test_line_count = 4 out &&
3056
3057                 git rev-parse >actual \
3058                         HEAD:priority/alpha/foo \
3059                         HEAD:priority/beta/bar  \
3060                         HEAD:priority/beta/baz  \
3061                         HEAD:priority/c &&
3062                 git rev-parse >expect \
3063                         O:goal/a/foo \
3064                         O:goal/b/bar \
3065                         O:goal/b/baz \
3066                         B:goal/c &&
3067                 test_cmp expect actual &&
3068                 test_must_fail git rev-parse HEAD:goal/c
3069         )
3070 '
3071
3072 # Testcase 9h, Avoid implicit rename if involved as source on other side
3073 #   (Extremely closely related to testcase 3a)
3074 #   Commit O: z/{b,c,d_1}
3075 #   Commit A: z/{b,c,d_2}
3076 #   Commit B: y/{b,c}, x/d_1
3077 #   Expected: y/{b,c}, x/d_2
3078 #   NOTE: If we applied the z/ -> y/ rename to z/d, then we'd end up with
3079 #         a rename/rename(1to2) conflict (z/d -> y/d vs. x/d)
3080 test_setup_9h () {
3081         test_create_repo 9h &&
3082         (
3083                 cd 9h &&
3084
3085                 mkdir z &&
3086                 echo b >z/b &&
3087                 echo c >z/c &&
3088                 printf "1\n2\n3\n4\n5\n6\n7\n8\nd\n" >z/d &&
3089                 git add z &&
3090                 test_tick &&
3091                 git commit -m "O" &&
3092
3093                 git branch O &&
3094                 git branch A &&
3095                 git branch B &&
3096
3097                 git checkout A &&
3098                 test_tick &&
3099                 echo more >>z/d &&
3100                 git add z/d &&
3101                 git commit -m "A" &&
3102
3103                 git checkout B &&
3104                 mkdir y &&
3105                 mkdir x &&
3106                 git mv z/b y/ &&
3107                 git mv z/c y/ &&
3108                 git mv z/d x/ &&
3109                 rmdir z &&
3110                 test_tick &&
3111                 git commit -m "B"
3112         )
3113 }
3114
3115 test_expect_success '9h: Avoid dir rename on merely modified path' '
3116         test_setup_9h &&
3117         (
3118                 cd 9h &&
3119
3120                 git checkout A^0 &&
3121
3122                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
3123
3124                 git ls-files -s >out &&
3125                 test_line_count = 3 out &&
3126
3127                 git rev-parse >actual \
3128                         HEAD:y/b HEAD:y/c HEAD:x/d &&
3129                 git rev-parse >expect \
3130                         O:z/b    O:z/c    A:z/d &&
3131                 test_cmp expect actual
3132         )
3133 '
3134
3135 ###########################################################################
3136 # Rules suggested by section 9:
3137 #
3138 #   If the other side of history did a directory rename to a path that your
3139 #   side renamed away, then ignore that particular rename from the other
3140 #   side of history for any implicit directory renames.
3141 ###########################################################################
3142
3143 ###########################################################################
3144 # SECTION 10: Handling untracked files
3145 #
3146 # unpack_trees(), upon which the recursive merge algorithm is based, aborts
3147 # the operation if untracked or dirty files would be deleted or overwritten
3148 # by the merge.  Unfortunately, unpack_trees() does not understand renames,
3149 # and if it doesn't abort, then it muddies up the working directory before
3150 # we even get to the point of detecting renames, so we need some special
3151 # handling, at least in the case of directory renames.
3152 ###########################################################################
3153
3154 # Testcase 10a, Overwrite untracked: normal rename/delete
3155 #   Commit O: z/{b,c_1}
3156 #   Commit A: z/b + untracked z/c + untracked z/d
3157 #   Commit B: z/{b,d_1}
3158 #   Expected: Aborted Merge +
3159 #       ERROR_MSG(untracked working tree files would be overwritten by merge)
3160
3161 test_setup_10a () {
3162         test_create_repo 10a &&
3163         (
3164                 cd 10a &&
3165
3166                 mkdir z &&
3167                 echo b >z/b &&
3168                 echo c >z/c &&
3169                 git add z &&
3170                 test_tick &&
3171                 git commit -m "O" &&
3172
3173                 git branch O &&
3174                 git branch A &&
3175                 git branch B &&
3176
3177                 git checkout A &&
3178                 git rm z/c &&
3179                 test_tick &&
3180                 git commit -m "A" &&
3181
3182                 git checkout B &&
3183                 git mv z/c z/d &&
3184                 test_tick &&
3185                 git commit -m "B"
3186         )
3187 }
3188
3189 test_expect_success '10a: Overwrite untracked with normal rename/delete' '
3190         test_setup_10a &&
3191         (
3192                 cd 10a &&
3193
3194                 git checkout A^0 &&
3195                 echo very >z/c &&
3196                 echo important >z/d &&
3197
3198                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3199                 test_i18ngrep "The following untracked working tree files would be overwritten by merge" err &&
3200
3201                 git ls-files -s >out &&
3202                 test_line_count = 1 out &&
3203                 git ls-files -o >out &&
3204                 test_line_count = 4 out &&
3205
3206                 echo very >expect &&
3207                 test_cmp expect z/c &&
3208
3209                 echo important >expect &&
3210                 test_cmp expect z/d &&
3211
3212                 git rev-parse HEAD:z/b >actual &&
3213                 git rev-parse O:z/b >expect &&
3214                 test_cmp expect actual
3215         )
3216 '
3217
3218 # Testcase 10b, Overwrite untracked: dir rename + delete
3219 #   Commit O: z/{b,c_1}
3220 #   Commit A: y/b + untracked y/{c,d,e}
3221 #   Commit B: z/{b,d_1,e}
3222 #   Expected: Failed Merge; y/b + untracked y/c + untracked y/d on disk +
3223 #             z/c_1 -> z/d_1 rename recorded at stage 3 for y/d +
3224 #       ERROR_MSG(refusing to lose untracked file at 'y/d')
3225
3226 test_setup_10b () {
3227         test_create_repo 10b &&
3228         (
3229                 cd 10b &&
3230
3231                 mkdir z &&
3232                 echo b >z/b &&
3233                 echo c >z/c &&
3234                 git add z &&
3235                 test_tick &&
3236                 git commit -m "O" &&
3237
3238                 git branch O &&
3239                 git branch A &&
3240                 git branch B &&
3241
3242                 git checkout A &&
3243                 git rm z/c &&
3244                 git mv z/ y/ &&
3245                 test_tick &&
3246                 git commit -m "A" &&
3247
3248                 git checkout B &&
3249                 git mv z/c z/d &&
3250                 echo e >z/e &&
3251                 git add z/e &&
3252                 test_tick &&
3253                 git commit -m "B"
3254         )
3255 }
3256
3257 test_expect_success '10b: Overwrite untracked with dir rename + delete' '
3258         test_setup_10b &&
3259         (
3260                 cd 10b &&
3261
3262                 git checkout A^0 &&
3263                 echo very >y/c &&
3264                 echo important >y/d &&
3265                 echo contents >y/e &&
3266
3267                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3268                 test_i18ngrep "CONFLICT (rename/delete).*Version B\^0 of y/d left in tree at y/d~B\^0" out &&
3269                 test_i18ngrep "Error: Refusing to lose untracked file at y/e; writing to y/e~B\^0 instead" out &&
3270
3271                 git ls-files -s >out &&
3272                 test_line_count = 3 out &&
3273                 git ls-files -u >out &&
3274                 test_line_count = 2 out &&
3275                 git ls-files -o >out &&
3276                 test_line_count = 5 out &&
3277
3278                 git rev-parse >actual \
3279                         :0:y/b :3:y/d :3:y/e &&
3280                 git rev-parse >expect \
3281                         O:z/b  O:z/c  B:z/e &&
3282                 test_cmp expect actual &&
3283
3284                 echo very >expect &&
3285                 test_cmp expect y/c &&
3286
3287                 echo important >expect &&
3288                 test_cmp expect y/d &&
3289
3290                 echo contents >expect &&
3291                 test_cmp expect y/e
3292         )
3293 '
3294
3295 # Testcase 10c, Overwrite untracked: dir rename/rename(1to2)
3296 #   Commit O: z/{a,b}, x/{c,d}
3297 #   Commit A: y/{a,b}, w/c, x/d + different untracked y/c
3298 #   Commit B: z/{a,b,c}, x/d
3299 #   Expected: Failed Merge; y/{a,b} + x/d + untracked y/c +
3300 #             CONFLICT(rename/rename) x/c -> w/c vs y/c +
3301 #             y/c~B^0 +
3302 #             ERROR_MSG(Refusing to lose untracked file at y/c)
3303
3304 test_setup_10c () {
3305         test_create_repo 10c_$1 &&
3306         (
3307                 cd 10c_$1 &&
3308
3309                 mkdir z x &&
3310                 echo a >z/a &&
3311                 echo b >z/b &&
3312                 echo c >x/c &&
3313                 echo d >x/d &&
3314                 git add z x &&
3315                 test_tick &&
3316                 git commit -m "O" &&
3317
3318                 git branch O &&
3319                 git branch A &&
3320                 git branch B &&
3321
3322                 git checkout A &&
3323                 mkdir w &&
3324                 git mv x/c w/c &&
3325                 git mv z/ y/ &&
3326                 test_tick &&
3327                 git commit -m "A" &&
3328
3329                 git checkout B &&
3330                 git mv x/c z/ &&
3331                 test_tick &&
3332                 git commit -m "B"
3333         )
3334 }
3335
3336 test_expect_success '10c1: Overwrite untracked with dir rename/rename(1to2)' '
3337         test_setup_10c 1 &&
3338         (
3339                 cd 10c_1 &&
3340
3341                 git checkout A^0 &&
3342                 echo important >y/c &&
3343
3344                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3345                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3346                 test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~B\^0 instead" out &&
3347
3348                 git ls-files -s >out &&
3349                 test_line_count = 6 out &&
3350                 git ls-files -u >out &&
3351                 test_line_count = 3 out &&
3352                 git ls-files -o >out &&
3353                 test_line_count = 3 out &&
3354
3355                 git rev-parse >actual \
3356                         :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :3:y/c &&
3357                 git rev-parse >expect \
3358                          O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&
3359                 test_cmp expect actual &&
3360
3361                 git hash-object y/c~B^0 >actual &&
3362                 git rev-parse O:x/c >expect &&
3363                 test_cmp expect actual &&
3364
3365                 echo important >expect &&
3366                 test_cmp expect y/c
3367         )
3368 '
3369
3370 test_expect_success '10c2: Overwrite untracked with dir rename/rename(1to2), other direction' '
3371         test_setup_10c 2 &&
3372         (
3373                 cd 10c_2 &&
3374
3375                 git reset --hard &&
3376                 git clean -fdqx &&
3377
3378                 git checkout B^0 &&
3379                 mkdir y &&
3380                 echo important >y/c &&
3381
3382                 test_must_fail git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
3383                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3384                 test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~HEAD instead" out &&
3385
3386                 git ls-files -s >out &&
3387                 test_line_count = 6 out &&
3388                 git ls-files -u >out &&
3389                 test_line_count = 3 out &&
3390                 git ls-files -o >out &&
3391                 test_line_count = 3 out &&
3392
3393                 git rev-parse >actual \
3394                         :0:y/a :0:y/b :0:x/d :1:x/c :3:w/c :2:y/c &&
3395                 git rev-parse >expect \
3396                          O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&
3397                 test_cmp expect actual &&
3398
3399                 git hash-object y/c~HEAD >actual &&
3400                 git rev-parse O:x/c >expect &&
3401                 test_cmp expect actual &&
3402
3403                 echo important >expect &&
3404                 test_cmp expect y/c
3405         )
3406 '
3407
3408 # Testcase 10d, Delete untracked w/ dir rename/rename(2to1)
3409 #   Commit O: z/{a,b,c_1},        x/{d,e,f_2}
3410 #   Commit A: y/{a,b},            x/{d,e,f_2,wham_1} + untracked y/wham
3411 #   Commit B: z/{a,b,c_1,wham_2}, y/{d,e}
3412 #   Expected: Failed Merge; y/{a,b,d,e} + untracked y/{wham,wham~merged}+
3413 #             CONFLICT(rename/rename) z/c_1 vs x/f_2 -> y/wham
3414 #             ERROR_MSG(Refusing to lose untracked file at y/wham)
3415
3416 test_setup_10d () {
3417         test_create_repo 10d &&
3418         (
3419                 cd 10d &&
3420
3421                 mkdir z x &&
3422                 echo a >z/a &&
3423                 echo b >z/b &&
3424                 echo c >z/c &&
3425                 echo d >x/d &&
3426                 echo e >x/e &&
3427                 echo f >x/f &&
3428                 git add z x &&
3429                 test_tick &&
3430                 git commit -m "O" &&
3431
3432                 git branch O &&
3433                 git branch A &&
3434                 git branch B &&
3435
3436                 git checkout A &&
3437                 git mv z/c x/wham &&
3438                 git mv z/ y/ &&
3439                 test_tick &&
3440                 git commit -m "A" &&
3441
3442                 git checkout B &&
3443                 git mv x/f z/wham &&
3444                 git mv x/ y/ &&
3445                 test_tick &&
3446                 git commit -m "B"
3447         )
3448 }
3449
3450 test_expect_success '10d: Delete untracked with dir rename/rename(2to1)' '
3451         test_setup_10d &&
3452         (
3453                 cd 10d &&
3454
3455                 git checkout A^0 &&
3456                 echo important >y/wham &&
3457
3458                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3459                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3460                 test_i18ngrep "Refusing to lose untracked file at y/wham" out &&
3461
3462                 git ls-files -s >out &&
3463                 test_line_count = 6 out &&
3464                 git ls-files -u >out &&
3465                 test_line_count = 2 out &&
3466                 git ls-files -o >out &&
3467                 test_line_count = 3 out &&
3468
3469                 git rev-parse >actual \
3470                         :0:y/a :0:y/b :0:y/d :0:y/e :2:y/wham :3:y/wham &&
3471                 git rev-parse >expect \
3472                          O:z/a  O:z/b  O:x/d  O:x/e  O:z/c     O:x/f &&
3473                 test_cmp expect actual &&
3474
3475                 test_must_fail git rev-parse :1:y/wham &&
3476
3477                 echo important >expect &&
3478                 test_cmp expect y/wham &&
3479
3480                 # Test that the two-way merge in y/wham~merged is as expected
3481                 git cat-file -p :2:y/wham >expect &&
3482                 git cat-file -p :3:y/wham >other &&
3483                 >empty &&
3484                 test_must_fail git merge-file \
3485                         -L "HEAD" \
3486                         -L "" \
3487                         -L "B^0" \
3488                         expect empty other &&
3489                 test_cmp expect y/wham~merged
3490         )
3491 '
3492
3493 # Testcase 10e, Does git complain about untracked file that's not in the way?
3494 #   Commit O: z/{a,b}
3495 #   Commit A: y/{a,b} + untracked z/c
3496 #   Commit B: z/{a,b,c}
3497 #   Expected: y/{a,b,c} + untracked z/c
3498
3499 test_setup_10e () {
3500         test_create_repo 10e &&
3501         (
3502                 cd 10e &&
3503
3504                 mkdir z &&
3505                 echo a >z/a &&
3506                 echo b >z/b &&
3507                 git add z &&
3508                 test_tick &&
3509                 git commit -m "O" &&
3510
3511                 git branch O &&
3512                 git branch A &&
3513                 git branch B &&
3514
3515                 git checkout A &&
3516                 git mv z/ y/ &&
3517                 test_tick &&
3518                 git commit -m "A" &&
3519
3520                 git checkout B &&
3521                 echo c >z/c &&
3522                 git add z/c &&
3523                 test_tick &&
3524                 git commit -m "B"
3525         )
3526 }
3527
3528 test_expect_merge_algorithm failure success '10e: Does git complain about untracked file that is not really in the way?' '
3529         test_setup_10e &&
3530         (
3531                 cd 10e &&
3532
3533                 git checkout A^0 &&
3534                 mkdir z &&
3535                 echo random >z/c &&
3536
3537                 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3538                 test_i18ngrep ! "following untracked working tree files would be overwritten by merge" err &&
3539
3540                 git ls-files -s >out &&
3541                 test_line_count = 3 out &&
3542                 git ls-files -u >out &&
3543                 test_line_count = 0 out &&
3544                 git ls-files -o >out &&
3545                 test_line_count = 3 out &&
3546
3547                 git rev-parse >actual \
3548                         :0:y/a :0:y/b :0:y/c &&
3549                 git rev-parse >expect \
3550                          O:z/a  O:z/b  B:z/c &&
3551                 test_cmp expect actual &&
3552
3553                 echo random >expect &&
3554                 test_cmp expect z/c
3555         )
3556 '
3557
3558 ###########################################################################
3559 # SECTION 11: Handling dirty (not up-to-date) files
3560 #
3561 # unpack_trees(), upon which the recursive merge algorithm is based, aborts
3562 # the operation if untracked or dirty files would be deleted or overwritten
3563 # by the merge.  Unfortunately, unpack_trees() does not understand renames,
3564 # and if it doesn't abort, then it muddies up the working directory before
3565 # we even get to the point of detecting renames, so we need some special
3566 # handling.  This was true even of normal renames, but there are additional
3567 # codepaths that need special handling with directory renames.  Add
3568 # testcases for both renamed-by-directory-rename-detection and standard
3569 # rename cases.
3570 ###########################################################################
3571
3572 # Testcase 11a, Avoid losing dirty contents with simple rename
3573 #   Commit O: z/{a,b_v1},
3574 #   Commit A: z/{a,c_v1}, and z/c_v1 has uncommitted mods
3575 #   Commit B: z/{a,b_v2}
3576 #   Expected: ERROR_MSG(Refusing to lose dirty file at z/c) +
3577 #             z/a, staged version of z/c has sha1sum matching B:z/b_v2,
3578 #             z/c~HEAD with contents of B:z/b_v2,
3579 #             z/c with uncommitted mods on top of A:z/c_v1
3580
3581 test_setup_11a () {
3582         test_create_repo 11a &&
3583         (
3584                 cd 11a &&
3585
3586                 mkdir z &&
3587                 echo a >z/a &&
3588                 test_seq 1 10 >z/b &&
3589                 git add z &&
3590                 test_tick &&
3591                 git commit -m "O" &&
3592
3593                 git branch O &&
3594                 git branch A &&
3595                 git branch B &&
3596
3597                 git checkout A &&
3598                 git mv z/b z/c &&
3599                 test_tick &&
3600                 git commit -m "A" &&
3601
3602                 git checkout B &&
3603                 echo 11 >>z/b &&
3604                 git add z/b &&
3605                 test_tick &&
3606                 git commit -m "B"
3607         )
3608 }
3609
3610 test_expect_success '11a: Avoid losing dirty contents with simple rename' '
3611         test_setup_11a &&
3612         (
3613                 cd 11a &&
3614
3615                 git checkout A^0 &&
3616                 echo stuff >>z/c &&
3617
3618                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3619                 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3620
3621                 test_seq 1 10 >expected &&
3622                 echo stuff >>expected &&
3623                 test_cmp expected z/c &&
3624
3625                 git ls-files -s >out &&
3626                 test_line_count = 2 out &&
3627                 git ls-files -u >out &&
3628                 test_line_count = 1 out &&
3629                 git ls-files -o >out &&
3630                 test_line_count = 4 out &&
3631
3632                 git rev-parse >actual \
3633                         :0:z/a :2:z/c &&
3634                 git rev-parse >expect \
3635                          O:z/a  B:z/b &&
3636                 test_cmp expect actual &&
3637
3638                 git hash-object z/c~HEAD >actual &&
3639                 git rev-parse B:z/b >expect &&
3640                 test_cmp expect actual
3641         )
3642 '
3643
3644 # Testcase 11b, Avoid losing dirty file involved in directory rename
3645 #   Commit O: z/a,         x/{b,c_v1}
3646 #   Commit A: z/{a,c_v1},  x/b,       and z/c_v1 has uncommitted mods
3647 #   Commit B: y/a,         x/{b,c_v2}
3648 #   Expected: y/{a,c_v2}, x/b, z/c_v1 with uncommitted mods untracked,
3649 #             ERROR_MSG(Refusing to lose dirty file at z/c)
3650
3651
3652 test_setup_11b () {
3653         test_create_repo 11b &&
3654         (
3655                 cd 11b &&
3656
3657                 mkdir z x &&
3658                 echo a >z/a &&
3659                 echo b >x/b &&
3660                 test_seq 1 10 >x/c &&
3661                 git add z x &&
3662                 test_tick &&
3663                 git commit -m "O" &&
3664
3665                 git branch O &&
3666                 git branch A &&
3667                 git branch B &&
3668
3669                 git checkout A &&
3670                 git mv x/c z/c &&
3671                 test_tick &&
3672                 git commit -m "A" &&
3673
3674                 git checkout B &&
3675                 git mv z y &&
3676                 echo 11 >>x/c &&
3677                 git add x/c &&
3678                 test_tick &&
3679                 git commit -m "B"
3680         )
3681 }
3682
3683 test_expect_success '11b: Avoid losing dirty file involved in directory rename' '
3684         test_setup_11b &&
3685         (
3686                 cd 11b &&
3687
3688                 git checkout A^0 &&
3689                 echo stuff >>z/c &&
3690
3691                 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3692                 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3693
3694                 grep -q stuff z/c &&
3695                 test_seq 1 10 >expected &&
3696                 echo stuff >>expected &&
3697                 test_cmp expected z/c &&
3698
3699                 git ls-files -s >out &&
3700                 test_line_count = 3 out &&
3701                 git ls-files -u >out &&
3702                 test_line_count = 0 out &&
3703                 git ls-files -m >out &&
3704                 test_line_count = 0 out &&
3705                 git ls-files -o >out &&
3706                 test_line_count = 4 out &&
3707
3708                 git rev-parse >actual \
3709                         :0:x/b :0:y/a :0:y/c &&
3710                 git rev-parse >expect \
3711                          O:x/b  O:z/a  B:x/c &&
3712                 test_cmp expect actual &&
3713
3714                 git hash-object y/c >actual &&
3715                 git rev-parse B:x/c >expect &&
3716                 test_cmp expect actual
3717         )
3718 '
3719
3720 # Testcase 11c, Avoid losing not-up-to-date with rename + D/F conflict
3721 #   Commit O: y/a,         x/{b,c_v1}
3722 #   Commit A: y/{a,c_v1},  x/b,       and y/c_v1 has uncommitted mods
3723 #   Commit B: y/{a,c/d},   x/{b,c_v2}
3724 #   Expected: Abort_msg("following files would be overwritten by merge") +
3725 #             y/c left untouched (still has uncommitted mods)
3726
3727 test_setup_11c () {
3728         test_create_repo 11c &&
3729         (
3730                 cd 11c &&
3731
3732                 mkdir y x &&
3733                 echo a >y/a &&
3734                 echo b >x/b &&
3735                 test_seq 1 10 >x/c &&
3736                 git add y x &&
3737                 test_tick &&
3738                 git commit -m "O" &&
3739
3740                 git branch O &&
3741                 git branch A &&
3742                 git branch B &&
3743
3744                 git checkout A &&
3745                 git mv x/c y/c &&
3746                 test_tick &&
3747                 git commit -m "A" &&
3748
3749                 git checkout B &&
3750                 mkdir y/c &&
3751                 echo d >y/c/d &&
3752                 echo 11 >>x/c &&
3753                 git add x/c y/c/d &&
3754                 test_tick &&
3755                 git commit -m "B"
3756         )
3757 }
3758
3759 test_expect_success '11c: Avoid losing not-uptodate with rename + D/F conflict' '
3760         test_setup_11c &&
3761         (
3762                 cd 11c &&
3763
3764                 git checkout A^0 &&
3765                 echo stuff >>y/c &&
3766
3767                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3768                 test_i18ngrep "following files would be overwritten by merge" err &&
3769
3770                 grep -q stuff y/c &&
3771                 test_seq 1 10 >expected &&
3772                 echo stuff >>expected &&
3773                 test_cmp expected y/c &&
3774
3775                 git ls-files -s >out &&
3776                 test_line_count = 3 out &&
3777                 git ls-files -u >out &&
3778                 test_line_count = 0 out &&
3779                 git ls-files -m >out &&
3780                 test_line_count = 1 out &&
3781                 git ls-files -o >out &&
3782                 test_line_count = 3 out
3783         )
3784 '
3785
3786 # Testcase 11d, Avoid losing not-up-to-date with rename + D/F conflict
3787 #   Commit O: z/a,         x/{b,c_v1}
3788 #   Commit A: z/{a,c_v1},  x/b,       and z/c_v1 has uncommitted mods
3789 #   Commit B: y/{a,c/d},   x/{b,c_v2}
3790 #   Expected: D/F: y/c_v2 vs y/c/d) +
3791 #             Warning_Msg("Refusing to lose dirty file at z/c) +
3792 #             y/{a,c~HEAD,c/d}, x/b, now-untracked z/c_v1 with uncommitted mods
3793
3794 test_setup_11d () {
3795         test_create_repo 11d &&
3796         (
3797                 cd 11d &&
3798
3799                 mkdir z x &&
3800                 echo a >z/a &&
3801                 echo b >x/b &&
3802                 test_seq 1 10 >x/c &&
3803                 git add z x &&
3804                 test_tick &&
3805                 git commit -m "O" &&
3806
3807                 git branch O &&
3808                 git branch A &&
3809                 git branch B &&
3810
3811                 git checkout A &&
3812                 git mv x/c z/c &&
3813                 test_tick &&
3814                 git commit -m "A" &&
3815
3816                 git checkout B &&
3817                 git mv z y &&
3818                 mkdir y/c &&
3819                 echo d >y/c/d &&
3820                 echo 11 >>x/c &&
3821                 git add x/c y/c/d &&
3822                 test_tick &&
3823                 git commit -m "B"
3824         )
3825 }
3826
3827 test_expect_success '11d: Avoid losing not-uptodate with rename + D/F conflict' '
3828         test_setup_11d &&
3829         (
3830                 cd 11d &&
3831
3832                 git checkout A^0 &&
3833                 echo stuff >>z/c &&
3834
3835                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3836                 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3837
3838                 grep -q stuff z/c &&
3839                 test_seq 1 10 >expected &&
3840                 echo stuff >>expected &&
3841                 test_cmp expected z/c &&
3842
3843                 git ls-files -s >out &&
3844                 test_line_count = 4 out &&
3845                 git ls-files -u >out &&
3846                 test_line_count = 1 out &&
3847                 git ls-files -o >out &&
3848                 test_line_count = 5 out &&
3849
3850                 git rev-parse >actual \
3851                         :0:x/b :0:y/a :0:y/c/d :3:y/c &&
3852                 git rev-parse >expect \
3853                          O:x/b  O:z/a  B:y/c/d  B:x/c &&
3854                 test_cmp expect actual &&
3855
3856                 git hash-object y/c~HEAD >actual &&
3857                 git rev-parse B:x/c >expect &&
3858                 test_cmp expect actual
3859         )
3860 '
3861
3862 # Testcase 11e, Avoid deleting not-up-to-date with dir rename/rename(1to2)/add
3863 #   Commit O: z/{a,b},      x/{c_1,d}
3864 #   Commit A: y/{a,b,c_2},  x/d, w/c_1, and y/c_2 has uncommitted mods
3865 #   Commit B: z/{a,b,c_1},  x/d
3866 #   Expected: Failed Merge; y/{a,b} + x/d +
3867 #             CONFLICT(rename/rename) x/c_1 -> w/c_1 vs y/c_1 +
3868 #             ERROR_MSG(Refusing to lose dirty file at y/c)
3869 #             y/c~B^0 has O:x/c_1 contents
3870 #             y/c~HEAD has A:y/c_2 contents
3871 #             y/c has dirty file from before merge
3872
3873 test_setup_11e () {
3874         test_create_repo 11e &&
3875         (
3876                 cd 11e &&
3877
3878                 mkdir z x &&
3879                 echo a >z/a &&
3880                 echo b >z/b &&
3881                 echo c >x/c &&
3882                 echo d >x/d &&
3883                 git add z x &&
3884                 test_tick &&
3885                 git commit -m "O" &&
3886
3887                 git branch O &&
3888                 git branch A &&
3889                 git branch B &&
3890
3891                 git checkout A &&
3892                 git mv z/ y/ &&
3893                 echo different >y/c &&
3894                 mkdir w &&
3895                 git mv x/c w/ &&
3896                 git add y/c &&
3897                 test_tick &&
3898                 git commit -m "A" &&
3899
3900                 git checkout B &&
3901                 git mv x/c z/ &&
3902                 test_tick &&
3903                 git commit -m "B"
3904         )
3905 }
3906
3907 test_expect_success '11e: Avoid deleting not-uptodate with dir rename/rename(1to2)/add' '
3908         test_setup_11e &&
3909         (
3910                 cd 11e &&
3911
3912                 git checkout A^0 &&
3913                 echo mods >>y/c &&
3914
3915                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3916                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3917                 test_i18ngrep "Refusing to lose dirty file at y/c" out &&
3918
3919                 git ls-files -s >out &&
3920                 test_line_count = 7 out &&
3921                 git ls-files -u >out &&
3922                 test_line_count = 4 out &&
3923                 git ls-files -o >out &&
3924                 test_line_count = 3 out &&
3925
3926                 echo different >expected &&
3927                 echo mods >>expected &&
3928                 test_cmp expected y/c &&
3929
3930                 git rev-parse >actual \
3931                         :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :2:y/c :3:y/c &&
3932                 git rev-parse >expect \
3933                          O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  A:y/c  O:x/c &&
3934                 test_cmp expect actual &&
3935
3936                 # See if y/c~merged has expected contents; requires manually
3937                 # doing the expected file merge
3938                 git cat-file -p A:y/c >c1 &&
3939                 git cat-file -p B:z/c >c2 &&
3940                 >empty &&
3941                 test_must_fail git merge-file \
3942                         -L "HEAD" \
3943                         -L "" \
3944                         -L "B^0" \
3945                         c1 empty c2 &&
3946                 test_cmp c1 y/c~merged
3947         )
3948 '
3949
3950 # Testcase 11f, Avoid deleting not-up-to-date w/ dir rename/rename(2to1)
3951 #   Commit O: z/{a,b},        x/{c_1,d_2}
3952 #   Commit A: y/{a,b,wham_1}, x/d_2, except y/wham has uncommitted mods
3953 #   Commit B: z/{a,b,wham_2}, x/c_1
3954 #   Expected: Failed Merge; y/{a,b} + untracked y/{wham~merged} +
3955 #             y/wham with dirty changes from before merge +
3956 #             CONFLICT(rename/rename) x/c vs x/d -> y/wham
3957 #             ERROR_MSG(Refusing to lose dirty file at y/wham)
3958
3959 test_setup_11f () {
3960         test_create_repo 11f &&
3961         (
3962                 cd 11f &&
3963
3964                 mkdir z x &&
3965                 echo a >z/a &&
3966                 echo b >z/b &&
3967                 test_seq 1 10 >x/c &&
3968                 echo d >x/d &&
3969                 git add z x &&
3970                 test_tick &&
3971                 git commit -m "O" &&
3972
3973                 git branch O &&
3974                 git branch A &&
3975                 git branch B &&
3976
3977                 git checkout A &&
3978                 git mv z/ y/ &&
3979                 git mv x/c y/wham &&
3980                 test_tick &&
3981                 git commit -m "A" &&
3982
3983                 git checkout B &&
3984                 git mv x/d z/wham &&
3985                 test_tick &&
3986                 git commit -m "B"
3987         )
3988 }
3989
3990 test_expect_success '11f: Avoid deleting not-uptodate with dir rename/rename(2to1)' '
3991         test_setup_11f &&
3992         (
3993                 cd 11f &&
3994
3995                 git checkout A^0 &&
3996                 echo important >>y/wham &&
3997
3998                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
3999                 test_i18ngrep "CONFLICT (rename/rename)" out &&
4000                 test_i18ngrep "Refusing to lose dirty file at y/wham" out &&
4001
4002                 git ls-files -s >out &&
4003                 test_line_count = 4 out &&
4004                 git ls-files -u >out &&
4005                 test_line_count = 2 out &&
4006                 git ls-files -o >out &&
4007                 test_line_count = 3 out &&
4008
4009                 test_seq 1 10 >expected &&
4010                 echo important >>expected &&
4011                 test_cmp expected y/wham &&
4012
4013                 test_must_fail git rev-parse :1:y/wham &&
4014
4015                 git rev-parse >actual \
4016                         :0:y/a :0:y/b :2:y/wham :3:y/wham &&
4017                 git rev-parse >expect \
4018                          O:z/a  O:z/b  O:x/c     O:x/d &&
4019                 test_cmp expect actual &&
4020
4021                 # Test that the two-way merge in y/wham~merged is as expected
4022                 git cat-file -p :2:y/wham >expect &&
4023                 git cat-file -p :3:y/wham >other &&
4024                 >empty &&
4025                 test_must_fail git merge-file \
4026                         -L "HEAD" \
4027                         -L "" \
4028                         -L "B^0" \
4029                         expect empty other &&
4030                 test_cmp expect y/wham~merged
4031         )
4032 '
4033
4034 ###########################################################################
4035 # SECTION 12: Everything else
4036 #
4037 # Tests suggested by others.  Tests added after implementation completed
4038 # and submitted.  Grab bag.
4039 ###########################################################################
4040
4041 # Testcase 12a, Moving one directory hierarchy into another
4042 #   (Related to testcase 9a)
4043 #   Commit O: node1/{leaf1,leaf2}, node2/{leaf3,leaf4}
4044 #   Commit A: node1/{leaf1,leaf2,node2/{leaf3,leaf4}}
4045 #   Commit B: node1/{leaf1,leaf2,leaf5}, node2/{leaf3,leaf4,leaf6}
4046 #   Expected: node1/{leaf1,leaf2,leaf5,node2/{leaf3,leaf4,leaf6}}
4047
4048 test_setup_12a () {
4049         test_create_repo 12a &&
4050         (
4051                 cd 12a &&
4052
4053                 mkdir -p node1 node2 &&
4054                 echo leaf1 >node1/leaf1 &&
4055                 echo leaf2 >node1/leaf2 &&
4056                 echo leaf3 >node2/leaf3 &&
4057                 echo leaf4 >node2/leaf4 &&
4058                 git add node1 node2 &&
4059                 test_tick &&
4060                 git commit -m "O" &&
4061
4062                 git branch O &&
4063                 git branch A &&
4064                 git branch B &&
4065
4066                 git checkout A &&
4067                 git mv node2/ node1/ &&
4068                 test_tick &&
4069                 git commit -m "A" &&
4070
4071                 git checkout B &&
4072                 echo leaf5 >node1/leaf5 &&
4073                 echo leaf6 >node2/leaf6 &&
4074                 git add node1 node2 &&
4075                 test_tick &&
4076                 git commit -m "B"
4077         )
4078 }
4079
4080 test_expect_success '12a: Moving one directory hierarchy into another' '
4081         test_setup_12a &&
4082         (
4083                 cd 12a &&
4084
4085                 git checkout A^0 &&
4086
4087                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
4088
4089                 git ls-files -s >out &&
4090                 test_line_count = 6 out &&
4091
4092                 git rev-parse >actual \
4093                         HEAD:node1/leaf1 HEAD:node1/leaf2 HEAD:node1/leaf5 \
4094                         HEAD:node1/node2/leaf3 \
4095                         HEAD:node1/node2/leaf4 \
4096                         HEAD:node1/node2/leaf6 &&
4097                 git rev-parse >expect \
4098                         O:node1/leaf1    O:node1/leaf2    B:node1/leaf5 \
4099                         O:node2/leaf3 \
4100                         O:node2/leaf4 \
4101                         B:node2/leaf6 &&
4102                 test_cmp expect actual
4103         )
4104 '
4105
4106 # Testcase 12b1, Moving two directory hierarchies into each other
4107 #   (Related to testcases 1c and 12c)
4108 #   Commit O: node1/{leaf1, leaf2}, node2/{leaf3, leaf4}
4109 #   Commit A: node1/{leaf1, leaf2, node2/{leaf3, leaf4}}
4110 #   Commit B: node2/{leaf3, leaf4, node1/{leaf1, leaf2}}
4111 #   Expected: node1/node2/{leaf3, leaf4}
4112 #             node2/node1/{leaf1, leaf2}
4113 #   NOTE: If there were new files added to the old node1/ or node2/ directories,
4114 #         then we would need to detect renames for those directories and would
4115 #         find that:
4116 #             commit A renames node2/ -> node1/node2/
4117 #             commit B renames node1/ -> node2/node1/
4118 #         Applying those directory renames to the initial result (making all
4119 #         four paths experience a transitive renaming), yields
4120 #             node1/node2/node1/{leaf1, leaf2}
4121 #             node2/node1/node2/{leaf3, leaf4}
4122 #         as the result.  It may be really weird to have two directories
4123 #         rename each other, but simple rules give weird results when given
4124 #         weird inputs.  HOWEVER, the "If" at the beginning of those NOTE was
4125 #         false; there were no new files added and thus there is no directory
4126 #         rename detection to perform.  As such, we just have simple renames
4127 #         and the expected answer is:
4128 #             node1/node2/{leaf3, leaf4}
4129 #             node2/node1/{leaf1, leaf2}
4130
4131 test_setup_12b1 () {
4132         test_create_repo 12b1 &&
4133         (
4134                 cd 12b1 &&
4135
4136                 mkdir -p node1 node2 &&
4137                 echo leaf1 >node1/leaf1 &&
4138                 echo leaf2 >node1/leaf2 &&
4139                 echo leaf3 >node2/leaf3 &&
4140                 echo leaf4 >node2/leaf4 &&
4141                 git add node1 node2 &&
4142                 test_tick &&
4143                 git commit -m "O" &&
4144
4145                 git branch O &&
4146                 git branch A &&
4147                 git branch B &&
4148
4149                 git checkout A &&
4150                 git mv node2/ node1/ &&
4151                 test_tick &&
4152                 git commit -m "A" &&
4153
4154                 git checkout B &&
4155                 git mv node1/ node2/ &&
4156                 test_tick &&
4157                 git commit -m "B"
4158         )
4159 }
4160
4161 test_expect_merge_algorithm failure success '12b1: Moving two directory hierarchies into each other' '
4162         test_setup_12b1 &&
4163         (
4164                 cd 12b1 &&
4165
4166                 git checkout A^0 &&
4167
4168                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
4169
4170                 git ls-files -s >out &&
4171                 test_line_count = 4 out &&
4172
4173                 git rev-parse >actual \
4174                         HEAD:node2/node1/leaf1 \
4175                         HEAD:node2/node1/leaf2 \
4176                         HEAD:node1/node2/leaf3 \
4177                         HEAD:node1/node2/leaf4 &&
4178                 git rev-parse >expect \
4179                         O:node1/leaf1 \
4180                         O:node1/leaf2 \
4181                         O:node2/leaf3 \
4182                         O:node2/leaf4 &&
4183                 test_cmp expect actual
4184         )
4185 '
4186
4187 # Testcase 12b2, Moving two directory hierarchies into each other
4188 #   (Related to testcases 1c and 12c)
4189 #   Commit O: node1/{leaf1, leaf2}, node2/{leaf3, leaf4}
4190 #   Commit A: node1/{leaf1, leaf2, leaf5, node2/{leaf3, leaf4}}
4191 #   Commit B: node2/{leaf3, leaf4, leaf6, node1/{leaf1, leaf2}}
4192 #   Expected: node1/node2/{node1/{leaf1, leaf2}, leaf6}
4193 #             node2/node1/{node2/{leaf3, leaf4}, leaf5}
4194 #   NOTE: Without directory renames, we would expect
4195 #             A: node2/leaf3 -> node1/node2/leaf3
4196 #             A: node2/leaf1 -> node1/node2/leaf4
4197 #             A: Adds           node1/leaf5
4198 #             B: node1/leaf1 -> node2/node1/leaf1
4199 #             B: node1/leaf2 -> node2/node1/leaf2
4200 #             B: Adds           node2/leaf6
4201 #         with directory rename detection, we note that
4202 #             commit A renames node2/ -> node1/node2/
4203 #             commit B renames node1/ -> node2/node1/
4204 #         therefore, applying A's directory rename to the paths added in B gives:
4205 #             B: node1/leaf1 -> node1/node2/node1/leaf1
4206 #             B: node1/leaf2 -> node1/node2/node1/leaf2
4207 #             B: Adds           node1/node2/leaf6
4208 #         and applying B's directory rename to the paths added in A gives:
4209 #             A: node2/leaf3 -> node2/node1/node2/leaf3
4210 #             A: node2/leaf1 -> node2/node1/node2/leaf4
4211 #             A: Adds           node2/node1/leaf5
4212 #         resulting in the expected
4213 #             node1/node2/{node1/{leaf1, leaf2}, leaf6}
4214 #             node2/node1/{node2/{leaf3, leaf4}, leaf5}
4215 #
4216 #         You may ask, is it weird to have two directories rename each other?
4217 #         To which, I can do no more than shrug my shoulders and say that
4218 #         even simple rules give weird results when given weird inputs.
4219
4220 test_setup_12b2 () {
4221         test_create_repo 12b2 &&
4222         (
4223                 cd 12b2 &&
4224
4225                 mkdir -p node1 node2 &&
4226                 echo leaf1 >node1/leaf1 &&
4227                 echo leaf2 >node1/leaf2 &&
4228                 echo leaf3 >node2/leaf3 &&
4229                 echo leaf4 >node2/leaf4 &&
4230                 git add node1 node2 &&
4231                 test_tick &&
4232                 git commit -m "O" &&
4233
4234                 git branch O &&
4235                 git branch A &&
4236                 git branch B &&
4237
4238                 git checkout A &&
4239                 git mv node2/ node1/ &&
4240                 echo leaf5 >node1/leaf5 &&
4241                 git add node1/leaf5 &&
4242                 test_tick &&
4243                 git commit -m "A" &&
4244
4245                 git checkout B &&
4246                 git mv node1/ node2/ &&
4247                 echo leaf6 >node2/leaf6 &&
4248                 git add node2/leaf6 &&
4249                 test_tick &&
4250                 git commit -m "B"
4251         )
4252 }
4253
4254 test_expect_success '12b2: Moving two directory hierarchies into each other' '
4255         test_setup_12b2 &&
4256         (
4257                 cd 12b2 &&
4258
4259                 git checkout A^0 &&
4260
4261                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
4262
4263                 git ls-files -s >out &&
4264                 test_line_count = 6 out &&
4265
4266                 git rev-parse >actual \
4267                         HEAD:node1/node2/node1/leaf1 \
4268                         HEAD:node1/node2/node1/leaf2 \
4269                         HEAD:node2/node1/node2/leaf3 \
4270                         HEAD:node2/node1/node2/leaf4 \
4271                         HEAD:node2/node1/leaf5       \
4272                         HEAD:node1/node2/leaf6       &&
4273                 git rev-parse >expect \
4274                         O:node1/leaf1 \
4275                         O:node1/leaf2 \
4276                         O:node2/leaf3 \
4277                         O:node2/leaf4 \
4278                         A:node1/leaf5 \
4279                         B:node2/leaf6 &&
4280                 test_cmp expect actual
4281         )
4282 '
4283
4284 # Testcase 12c1, Moving two directory hierarchies into each other w/ content merge
4285 #   (Related to testcase 12b)
4286 #   Commit O: node1/{       leaf1_1, leaf2_1}, node2/{leaf3_1, leaf4_1}
4287 #   Commit A: node1/{       leaf1_2, leaf2_2,  node2/{leaf3_2, leaf4_2}}
4288 #   Commit B: node2/{node1/{leaf1_3, leaf2_3},        leaf3_3, leaf4_3}
4289 #   Expected: Content merge conflicts for each of:
4290 #               node1/node2/node1/{leaf1, leaf2},
4291 #               node2/node1/node2/{leaf3, leaf4}
4292 #   NOTE: This is *exactly* like 12b1, except that every path is modified on
4293 #         each side of the merge.
4294
4295 test_setup_12c1 () {
4296         test_create_repo 12c1 &&
4297         (
4298                 cd 12c1 &&
4299
4300                 mkdir -p node1 node2 &&
4301                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf1\n" >node1/leaf1 &&
4302                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf2\n" >node1/leaf2 &&
4303                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf3\n" >node2/leaf3 &&
4304                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf4\n" >node2/leaf4 &&
4305                 git add node1 node2 &&
4306                 test_tick &&
4307                 git commit -m "O" &&
4308
4309                 git branch O &&
4310                 git branch A &&
4311                 git branch B &&
4312
4313                 git checkout A &&
4314                 git mv node2/ node1/ &&
4315                 for i in `git ls-files`; do echo side A >>$i; done &&
4316                 git add -u &&
4317                 test_tick &&
4318                 git commit -m "A" &&
4319
4320                 git checkout B &&
4321                 git mv node1/ node2/ &&
4322                 for i in `git ls-files`; do echo side B >>$i; done &&
4323                 git add -u &&
4324                 test_tick &&
4325                 git commit -m "B"
4326         )
4327 }
4328
4329 test_expect_merge_algorithm failure success '12c1: Moving one directory hierarchy into another w/ content merge' '
4330         test_setup_12c1 &&
4331         (
4332                 cd 12c1 &&
4333
4334                 git checkout A^0 &&
4335
4336                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 &&
4337
4338                 git ls-files -u >out &&
4339                 test_line_count = 12 out &&
4340
4341                 git rev-parse >actual \
4342                         :1:node2/node1/leaf1 \
4343                         :1:node2/node1/leaf2 \
4344                         :1:node1/node2/leaf3 \
4345                         :1:node1/node2/leaf4 \
4346                         :2:node2/node1/leaf1 \
4347                         :2:node2/node1/leaf2 \
4348                         :2:node1/node2/leaf3 \
4349                         :2:node1/node2/leaf4 \
4350                         :3:node2/node1/leaf1 \
4351                         :3:node2/node1/leaf2 \
4352                         :3:node1/node2/leaf3 \
4353                         :3:node1/node2/leaf4 &&
4354                 git rev-parse >expect \
4355                         O:node1/leaf1 \
4356                         O:node1/leaf2 \
4357                         O:node2/leaf3 \
4358                         O:node2/leaf4 \
4359                         A:node1/leaf1 \
4360                         A:node1/leaf2 \
4361                         A:node1/node2/leaf3 \
4362                         A:node1/node2/leaf4 \
4363                         B:node2/node1/leaf1 \
4364                         B:node2/node1/leaf2 \
4365                         B:node2/leaf3 \
4366                         B:node2/leaf4 &&
4367                 test_cmp expect actual
4368         )
4369 '
4370
4371 # Testcase 12c2, Moving two directory hierarchies into each other w/ content merge
4372 #   (Related to testcase 12b)
4373 #   Commit O: node1/{       leaf1_1, leaf2_1}, node2/{leaf3_1, leaf4_1}
4374 #   Commit A: node1/{       leaf1_2, leaf2_2,  node2/{leaf3_2, leaf4_2}, leaf5}
4375 #   Commit B: node2/{node1/{leaf1_3, leaf2_3},        leaf3_3, leaf4_3,  leaf6}
4376 #   Expected: Content merge conflicts for each of:
4377 #               node1/node2/node1/{leaf1, leaf2}
4378 #               node2/node1/node2/{leaf3, leaf4}
4379 #             plus
4380 #               node2/node1/leaf5
4381 #               node1/node2/leaf6
4382 #   NOTE: This is *exactly* like 12b2, except that every path from O is modified
4383 #         on each side of the merge.
4384
4385 test_setup_12c2 () {
4386         test_create_repo 12c2 &&
4387         (
4388                 cd 12c2 &&
4389
4390                 mkdir -p node1 node2 &&
4391                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf1\n" >node1/leaf1 &&
4392                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf2\n" >node1/leaf2 &&
4393                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf3\n" >node2/leaf3 &&
4394                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf4\n" >node2/leaf4 &&
4395                 git add node1 node2 &&
4396                 test_tick &&
4397                 git commit -m "O" &&
4398
4399                 git branch O &&
4400                 git branch A &&
4401                 git branch B &&
4402
4403                 git checkout A &&
4404                 git mv node2/ node1/ &&
4405                 for i in `git ls-files`; do echo side A >>$i; done &&
4406                 git add -u &&
4407                 echo leaf5 >node1/leaf5 &&
4408                 git add node1/leaf5 &&
4409                 test_tick &&
4410                 git commit -m "A" &&
4411
4412                 git checkout B &&
4413                 git mv node1/ node2/ &&
4414                 for i in `git ls-files`; do echo side B >>$i; done &&
4415                 git add -u &&
4416                 echo leaf6 >node2/leaf6 &&
4417                 git add node2/leaf6 &&
4418                 test_tick &&
4419                 git commit -m "B"
4420         )
4421 }
4422
4423 test_expect_success '12c2: Moving one directory hierarchy into another w/ content merge' '
4424         test_setup_12c2 &&
4425         (
4426                 cd 12c2 &&
4427
4428                 git checkout A^0 &&
4429
4430                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 &&
4431
4432                 git ls-files -s >out &&
4433                 test_line_count = 14 out &&
4434                 git ls-files -u >out &&
4435                 test_line_count = 12 out &&
4436
4437                 git rev-parse >actual \
4438                         :1:node1/node2/node1/leaf1 \
4439                         :1:node1/node2/node1/leaf2 \
4440                         :1:node2/node1/node2/leaf3 \
4441                         :1:node2/node1/node2/leaf4 \
4442                         :2:node1/node2/node1/leaf1 \
4443                         :2:node1/node2/node1/leaf2 \
4444                         :2:node2/node1/node2/leaf3 \
4445                         :2:node2/node1/node2/leaf4 \
4446                         :3:node1/node2/node1/leaf1 \
4447                         :3:node1/node2/node1/leaf2 \
4448                         :3:node2/node1/node2/leaf3 \
4449                         :3:node2/node1/node2/leaf4 \
4450                         :0:node2/node1/leaf5       \
4451                         :0:node1/node2/leaf6       &&
4452                 git rev-parse >expect \
4453                         O:node1/leaf1 \
4454                         O:node1/leaf2 \
4455                         O:node2/leaf3 \
4456                         O:node2/leaf4 \
4457                         A:node1/leaf1 \
4458                         A:node1/leaf2 \
4459                         A:node1/node2/leaf3 \
4460                         A:node1/node2/leaf4 \
4461                         B:node2/node1/leaf1 \
4462                         B:node2/node1/leaf2 \
4463                         B:node2/leaf3 \
4464                         B:node2/leaf4 \
4465                         A:node1/leaf5 \
4466                         B:node2/leaf6 &&
4467                 test_cmp expect actual
4468         )
4469 '
4470
4471 # Testcase 12d, Rename/merge of subdirectory into the root
4472 #   Commit O: a/b/subdir/foo
4473 #   Commit A: subdir/foo
4474 #   Commit B: a/b/subdir/foo, a/b/bar
4475 #   Expected: subdir/foo, bar
4476
4477 test_setup_12d () {
4478         test_create_repo 12d &&
4479         (
4480                 cd 12d &&
4481
4482                 mkdir -p a/b/subdir &&
4483                 test_commit a/b/subdir/foo &&
4484
4485                 git branch O &&
4486                 git branch A &&
4487                 git branch B &&
4488
4489                 git checkout A &&
4490                 mkdir subdir &&
4491                 git mv a/b/subdir/foo.t subdir/foo.t &&
4492                 test_tick &&
4493                 git commit -m "A" &&
4494
4495                 git checkout B &&
4496                 test_commit a/b/bar
4497         )
4498 }
4499
4500 test_expect_success '12d: Rename/merge subdir into the root, variant 1' '
4501         test_setup_12d &&
4502         (
4503                 cd 12d &&
4504
4505                 git checkout A^0 &&
4506
4507                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
4508
4509                 git ls-files -s >out &&
4510                 test_line_count = 2 out &&
4511
4512                 git rev-parse >actual \
4513                         HEAD:subdir/foo.t   HEAD:bar.t &&
4514                 git rev-parse >expect \
4515                         O:a/b/subdir/foo.t  B:a/b/bar.t &&
4516                 test_cmp expect actual &&
4517
4518                 git hash-object bar.t >actual &&
4519                 git rev-parse B:a/b/bar.t >expect &&
4520                 test_cmp expect actual &&
4521
4522                 test_must_fail git rev-parse HEAD:a/b/subdir/foo.t &&
4523                 test_must_fail git rev-parse HEAD:a/b/bar.t &&
4524                 test_path_is_missing a/ &&
4525                 test_path_is_file bar.t
4526         )
4527 '
4528
4529 # Testcase 12e, Rename/merge of subdirectory into the root
4530 #   Commit O: a/b/foo
4531 #   Commit A: foo
4532 #   Commit B: a/b/foo, a/b/bar
4533 #   Expected: foo, bar
4534
4535 test_setup_12e () {
4536         test_create_repo 12e &&
4537         (
4538                 cd 12e &&
4539
4540                 mkdir -p a/b &&
4541                 test_commit a/b/foo &&
4542
4543                 git branch O &&
4544                 git branch A &&
4545                 git branch B &&
4546
4547                 git checkout A &&
4548                 mkdir subdir &&
4549                 git mv a/b/foo.t foo.t &&
4550                 test_tick &&
4551                 git commit -m "A" &&
4552
4553                 git checkout B &&
4554                 test_commit a/b/bar
4555         )
4556 }
4557
4558 test_expect_success '12e: Rename/merge subdir into the root, variant 2' '
4559         test_setup_12e &&
4560         (
4561                 cd 12e &&
4562
4563                 git checkout A^0 &&
4564
4565                 git -c merge.directoryRenames=true merge -s recursive B^0 &&
4566
4567                 git ls-files -s >out &&
4568                 test_line_count = 2 out &&
4569
4570                 git rev-parse >actual \
4571                         HEAD:foo.t   HEAD:bar.t &&
4572                 git rev-parse >expect \
4573                         O:a/b/foo.t  B:a/b/bar.t &&
4574                 test_cmp expect actual &&
4575
4576                 git hash-object bar.t >actual &&
4577                 git rev-parse B:a/b/bar.t >expect &&
4578                 test_cmp expect actual &&
4579
4580                 test_must_fail git rev-parse HEAD:a/b/foo.t &&
4581                 test_must_fail git rev-parse HEAD:a/b/bar.t &&
4582                 test_path_is_missing a/ &&
4583                 test_path_is_file bar.t
4584         )
4585 '
4586
4587 # Testcase 12f, Rebase of patches with big directory rename
4588 #   Commit O:
4589 #              dir/subdir/{a,b,c,d,e_O,Makefile_TOP_O}
4590 #              dir/subdir/tweaked/{f,g,h,Makefile_SUB_O}
4591 #              dir/unchanged/<LOTS OF FILES>
4592 #   Commit A:
4593 #     (Remove f & g, move e into newsubdir, rename dir/->folder/, modify files)
4594 #              folder/subdir/{a,b,c,d,Makefile_TOP_A}
4595 #              folder/subdir/newsubdir/e_A
4596 #              folder/subdir/tweaked/{h,Makefile_SUB_A}
4597 #              folder/unchanged/<LOTS OF FILES>
4598 #   Commit B1:
4599 #     (add newfile.{c,py}, modify underscored files)
4600 #              dir/{a,b,c,d,e_B1,Makefile_TOP_B1,newfile.c}
4601 #              dir/tweaked/{f,g,h,Makefile_SUB_B1,newfile.py}
4602 #              dir/unchanged/<LOTS OF FILES>
4603 #   Commit B2:
4604 #     (Modify e further, add newfile.rs)
4605 #              dir/{a,b,c,d,e_B2,Makefile_TOP_B1,newfile.c,newfile.rs}
4606 #              dir/tweaked/{f,g,h,Makefile_SUB_B1,newfile.py}
4607 #              dir/unchanged/<LOTS OF FILES>
4608 #   Expected:
4609 #          B1-picked:
4610 #              folder/subdir/{a,b,c,d,Makefile_TOP_Merge1,newfile.c}
4611 #              folder/subdir/newsubdir/e_Merge1
4612 #              folder/subdir/tweaked/{h,Makefile_SUB_Merge1,newfile.py}
4613 #              folder/unchanged/<LOTS OF FILES>
4614 #          B2-picked:
4615 #              folder/subdir/{a,b,c,d,Makefile_TOP_Merge1,newfile.c,newfile.rs}
4616 #              folder/subdir/newsubdir/e_Merge2
4617 #              folder/subdir/tweaked/{h,Makefile_SUB_Merge1,newfile.py}
4618 #              folder/unchanged/<LOTS OF FILES>
4619 #
4620 # Notes: This testcase happens to exercise lots of the
4621 #        optimization-specific codepaths in merge-ort, and also
4622 #        demonstrated a failing of the directory rename detection algorithm
4623 #        in merge-recursive; newfile.c should not get pushed into
4624 #        folder/subdir/newsubdir/, yet merge-recursive put it there because
4625 #        the rename of dir/subdir/{a,b,c,d} -> folder/subdir/{a,b,c,d}
4626 #        looks like
4627 #            dir/ -> folder/,
4628 #        whereas the rename of dir/subdir/e -> folder/subdir/newsubdir/e
4629 #        looks like
4630 #            dir/subdir/ -> folder/subdir/newsubdir/
4631 #        and if we note that newfile.c is found in dir/subdir/, we might
4632 #        overlook the dir/ -> folder/ rule that has more weight.
4633
4634 test_setup_12f () {
4635         test_create_repo 12f &&
4636         (
4637                 cd 12f &&
4638
4639                 mkdir -p dir/unchanged &&
4640                 mkdir -p dir/subdir/tweaked &&
4641                 echo a >dir/subdir/a &&
4642                 echo b >dir/subdir/b &&
4643                 echo c >dir/subdir/c &&
4644                 echo d >dir/subdir/d &&
4645                 test_seq 1 10 >dir/subdir/e &&
4646                 test_seq 10 20 >dir/subdir/Makefile &&
4647                 echo f >dir/subdir/tweaked/f &&
4648                 echo g >dir/subdir/tweaked/g &&
4649                 echo h >dir/subdir/tweaked/h &&
4650                 test_seq 20 30 >dir/subdir/tweaked/Makefile &&
4651                 for i in `test_seq 1 88`; do
4652                         echo content $i >dir/unchanged/file_$i
4653                 done &&
4654                 git add . &&
4655                 git commit -m "O" &&
4656
4657                 git branch O &&
4658                 git branch A &&
4659                 git branch B &&
4660
4661                 git switch A &&
4662                 git rm dir/subdir/tweaked/f dir/subdir/tweaked/g &&
4663                 test_seq 2 10 >dir/subdir/e &&
4664                 test_seq 11 20 >dir/subdir/Makefile &&
4665                 test_seq 21 30 >dir/subdir/tweaked/Makefile &&
4666                 mkdir dir/subdir/newsubdir &&
4667                 git mv dir/subdir/e dir/subdir/newsubdir/ &&
4668                 git mv dir folder &&
4669                 git add . &&
4670                 git commit -m "A" &&
4671
4672                 git switch B &&
4673                 mkdir dir/subdir/newsubdir/ &&
4674                 echo c code >dir/subdir/newfile.c &&
4675                 echo python code >dir/subdir/newsubdir/newfile.py &&
4676                 test_seq 1 11 >dir/subdir/e &&
4677                 test_seq 10 21 >dir/subdir/Makefile &&
4678                 test_seq 20 31 >dir/subdir/tweaked/Makefile &&
4679                 git add . &&
4680                 git commit -m "B1" &&
4681
4682                 echo rust code >dir/subdir/newfile.rs &&
4683                 test_seq 1 12 >dir/subdir/e &&
4684                 git add . &&
4685                 git commit -m "B2"
4686         )
4687 }
4688
4689 test_expect_merge_algorithm failure success '12f: Trivial directory resolve, caching, all kinds of fun' '
4690         test_setup_12f &&
4691         (
4692                 cd 12f &&
4693
4694                 git checkout A^0 &&
4695                 git branch Bmod B &&
4696
4697                 git -c merge.directoryRenames=true rebase A Bmod &&
4698
4699                 echo Checking the pick of B1... &&
4700
4701                 test_must_fail git rev-parse Bmod~1:dir &&
4702
4703                 git ls-tree -r Bmod~1 >out &&
4704                 test_line_count = 98 out &&
4705
4706                 git diff --name-status A Bmod~1 >actual &&
4707                 q_to_tab >expect <<-\EOF &&
4708                 MQfolder/subdir/Makefile
4709                 AQfolder/subdir/newfile.c
4710                 MQfolder/subdir/newsubdir/e
4711                 AQfolder/subdir/newsubdir/newfile.py
4712                 MQfolder/subdir/tweaked/Makefile
4713                 EOF
4714                 test_cmp expect actual &&
4715
4716                 # Three-way merged files
4717                 test_seq  2 11 >e_Merge1 &&
4718                 test_seq 11 21 >Makefile_TOP &&
4719                 test_seq 21 31 >Makefile_SUB &&
4720                 git hash-object >expect      \
4721                         e_Merge1             \
4722                         Makefile_TOP         \
4723                         Makefile_SUB         &&
4724                 git rev-parse >actual              \
4725                         Bmod~1:folder/subdir/newsubdir/e     \
4726                         Bmod~1:folder/subdir/Makefile        \
4727                         Bmod~1:folder/subdir/tweaked/Makefile &&
4728                 test_cmp expect actual &&
4729
4730                 # New files showed up at the right location with right contents
4731                 git rev-parse >expect                \
4732                         B~1:dir/subdir/newfile.c            \
4733                         B~1:dir/subdir/newsubdir/newfile.py &&
4734                 git rev-parse >actual                      \
4735                         Bmod~1:folder/subdir/newfile.c            \
4736                         Bmod~1:folder/subdir/newsubdir/newfile.py &&
4737                 test_cmp expect actual &&
4738
4739                 # Removed files
4740                 test_path_is_missing folder/subdir/tweaked/f &&
4741                 test_path_is_missing folder/subdir/tweaked/g &&
4742
4743                 # Unchanged files or directories
4744                 git rev-parse >actual        \
4745                         Bmod~1:folder/subdir/a          \
4746                         Bmod~1:folder/subdir/b          \
4747                         Bmod~1:folder/subdir/c          \
4748                         Bmod~1:folder/subdir/d          \
4749                         Bmod~1:folder/unchanged         \
4750                         Bmod~1:folder/subdir/tweaked/h &&
4751                 git rev-parse >expect          \
4752                         O:dir/subdir/a         \
4753                         O:dir/subdir/b         \
4754                         O:dir/subdir/c         \
4755                         O:dir/subdir/d         \
4756                         O:dir/unchanged        \
4757                         O:dir/subdir/tweaked/h &&
4758                 test_cmp expect actual &&
4759
4760                 echo Checking the pick of B2... &&
4761
4762                 test_must_fail git rev-parse Bmod:dir &&
4763
4764                 git ls-tree -r Bmod >out &&
4765                 test_line_count = 99 out &&
4766
4767                 git diff --name-status Bmod~1 Bmod >actual &&
4768                 q_to_tab >expect <<-\EOF &&
4769                 AQfolder/subdir/newfile.rs
4770                 MQfolder/subdir/newsubdir/e
4771                 EOF
4772                 test_cmp expect actual &&
4773
4774                 # Three-way merged file
4775                 test_seq  2 12 >e_Merge2 &&
4776                 git hash-object e_Merge2 >expect &&
4777                 git rev-parse Bmod:folder/subdir/newsubdir/e >actual &&
4778                 test_cmp expect actual
4779         )
4780 '
4781
4782 ###########################################################################
4783 # SECTION 13: Checking informational and conflict messages
4784 #
4785 # A year after directory rename detection became the default, it was
4786 # instead decided to report conflicts on the pathname on the basis that
4787 # some users may expect the new files added or moved into a directory to
4788 # be unrelated to all the other files in that directory, and thus that
4789 # directory rename detection is unexpected.  Test that the messages printed
4790 # match our expectation.
4791 ###########################################################################
4792
4793 # Testcase 13a, Basic directory rename with newly added files
4794 #   Commit O: z/{b,c}
4795 #   Commit A: y/{b,c}
4796 #   Commit B: z/{b,c,d,e/f}
4797 #   Expected: y/{b,c,d,e/f}, with notices/conflicts for both y/d and y/e/f
4798
4799 test_setup_13a () {
4800         test_create_repo 13a_$1 &&
4801         (
4802                 cd 13a_$1 &&
4803
4804                 mkdir z &&
4805                 echo b >z/b &&
4806                 echo c >z/c &&
4807                 git add z &&
4808                 test_tick &&
4809                 git commit -m "O" &&
4810
4811                 git branch O &&
4812                 git branch A &&
4813                 git branch B &&
4814
4815                 git checkout A &&
4816                 git mv z y &&
4817                 test_tick &&
4818                 git commit -m "A" &&
4819
4820                 git checkout B &&
4821                 echo d >z/d &&
4822                 mkdir z/e &&
4823                 echo f >z/e/f &&
4824                 git add z/d z/e/f &&
4825                 test_tick &&
4826                 git commit -m "B"
4827         )
4828 }
4829
4830 test_expect_success '13a(conflict): messages for newly added files' '
4831         test_setup_13a conflict &&
4832         (
4833                 cd 13a_conflict &&
4834
4835                 git checkout A^0 &&
4836
4837                 test_must_fail git merge -s recursive B^0 >out 2>err &&
4838
4839                 test_i18ngrep CONFLICT..file.location.*z/e/f.added.in.B^0.*y/e/f out &&
4840                 test_i18ngrep CONFLICT..file.location.*z/d.added.in.B^0.*y/d out &&
4841
4842                 git ls-files >paths &&
4843                 ! grep z/ paths &&
4844                 grep "y/[de]" paths &&
4845
4846                 test_path_is_missing z/d &&
4847                 test_path_is_file    y/d &&
4848                 test_path_is_missing z/e/f &&
4849                 test_path_is_file    y/e/f
4850         )
4851 '
4852
4853 test_expect_success '13a(info): messages for newly added files' '
4854         test_setup_13a info &&
4855         (
4856                 cd 13a_info &&
4857
4858                 git reset --hard &&
4859                 git checkout A^0 &&
4860
4861                 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
4862
4863                 test_i18ngrep Path.updated:.*z/e/f.added.in.B^0.*y/e/f out &&
4864                 test_i18ngrep Path.updated:.*z/d.added.in.B^0.*y/d out &&
4865
4866                 git ls-files >paths &&
4867                 ! grep z/ paths &&
4868                 grep "y/[de]" paths &&
4869
4870                 test_path_is_missing z/d &&
4871                 test_path_is_file    y/d &&
4872                 test_path_is_missing z/e/f &&
4873                 test_path_is_file    y/e/f
4874         )
4875 '
4876
4877 # Testcase 13b, Transitive rename with conflicted content merge and default
4878 #               "conflict" setting
4879 #   (Related to testcase 1c, 9b)
4880 #   Commit O: z/{b,c},   x/d_1
4881 #   Commit A: y/{b,c},   x/d_2
4882 #   Commit B: z/{b,c,d_3}
4883 #   Expected: y/{b,c,d_merged}, with two conflict messages for y/d,
4884 #             one about content, and one about file location
4885
4886 test_setup_13b () {
4887         test_create_repo 13b_$1 &&
4888         (
4889                 cd 13b_$1 &&
4890
4891                 mkdir x &&
4892                 mkdir z &&
4893                 test_seq 1 10 >x/d &&
4894                 echo b >z/b &&
4895                 echo c >z/c &&
4896                 git add x z &&
4897                 test_tick &&
4898                 git commit -m "O" &&
4899
4900                 git branch O &&
4901                 git branch A &&
4902                 git branch B &&
4903
4904                 git checkout A &&
4905                 git mv z y &&
4906                 echo 11 >>x/d &&
4907                 git add x/d &&
4908                 test_tick &&
4909                 git commit -m "A" &&
4910
4911                 git checkout B &&
4912                 echo eleven >>x/d &&
4913                 git mv x/d z/d &&
4914                 git add z/d &&
4915                 test_tick &&
4916                 git commit -m "B"
4917         )
4918 }
4919
4920 test_expect_success '13b(conflict): messages for transitive rename with conflicted content' '
4921         test_setup_13b conflict &&
4922         (
4923                 cd 13b_conflict &&
4924
4925                 git checkout A^0 &&
4926
4927                 test_must_fail git merge -s recursive B^0 >out 2>err &&
4928
4929                 test_i18ngrep CONFLICT.*content.*Merge.conflict.in.y/d out &&
4930                 test_i18ngrep CONFLICT..file.location.*x/d.renamed.to.z/d.*moved.to.y/d out &&
4931
4932                 git ls-files >paths &&
4933                 ! grep z/ paths &&
4934                 grep "y/d" paths &&
4935
4936                 test_path_is_missing z/d &&
4937                 test_path_is_file    y/d
4938         )
4939 '
4940
4941 test_expect_success '13b(info): messages for transitive rename with conflicted content' '
4942         test_setup_13b info &&
4943         (
4944                 cd 13b_info &&
4945
4946                 git reset --hard &&
4947                 git checkout A^0 &&
4948
4949                 test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
4950
4951                 test_i18ngrep CONFLICT.*content.*Merge.conflict.in.y/d out &&
4952                 test_i18ngrep Path.updated:.*x/d.renamed.to.z/d.in.B^0.*moving.it.to.y/d out &&
4953
4954                 git ls-files >paths &&
4955                 ! grep z/ paths &&
4956                 grep "y/d" paths &&
4957
4958                 test_path_is_missing z/d &&
4959                 test_path_is_file    y/d
4960         )
4961 '
4962
4963 # Testcase 13c, Rename/rename(1to1) due to directory rename
4964 #   Commit O: z/{b,c},   x/{d,e}
4965 #   Commit A: y/{b,c,d}, x/e
4966 #   Commit B: z/{b,c,d}, x/e
4967 #   Expected: y/{b,c,d}, x/e, with info or conflict messages for d
4968 #             A: renamed x/d -> z/d; B: renamed z/ -> y/ AND renamed x/d to y/d
4969 #             One could argue A had partial knowledge of what was done with
4970 #             d and B had full knowledge, but that's a slippery slope as
4971 #             shown in testcase 13d.
4972
4973 test_setup_13c () {
4974         test_create_repo 13c_$1 &&
4975         (
4976                 cd 13c_$1 &&
4977
4978                 mkdir x &&
4979                 mkdir z &&
4980                 test_seq 1 10 >x/d &&
4981                 echo e >x/e &&
4982                 echo b >z/b &&
4983                 echo c >z/c &&
4984                 git add x z &&
4985                 test_tick &&
4986                 git commit -m "O" &&
4987
4988                 git branch O &&
4989                 git branch A &&
4990                 git branch B &&
4991
4992                 git checkout A &&
4993                 git mv z y &&
4994                 git mv x/d y/ &&
4995                 test_tick &&
4996                 git commit -m "A" &&
4997
4998                 git checkout B &&
4999                 git mv x/d z/d &&
5000                 git add z/d &&
5001                 test_tick &&
5002                 git commit -m "B"
5003         )
5004 }
5005
5006 test_expect_success '13c(conflict): messages for rename/rename(1to1) via transitive rename' '
5007         test_setup_13c conflict &&
5008         (
5009                 cd 13c_conflict &&
5010
5011                 git checkout A^0 &&
5012
5013                 test_must_fail git merge -s recursive B^0 >out 2>err &&
5014
5015                 test_i18ngrep CONFLICT..file.location.*x/d.renamed.to.z/d.*moved.to.y/d out &&
5016
5017                 git ls-files >paths &&
5018                 ! grep z/ paths &&
5019                 grep "y/d" paths &&
5020
5021                 test_path_is_missing z/d &&
5022                 test_path_is_file    y/d
5023         )
5024 '
5025
5026 test_expect_success '13c(info): messages for rename/rename(1to1) via transitive rename' '
5027         test_setup_13c info &&
5028         (
5029                 cd 13c_info &&
5030
5031                 git reset --hard &&
5032                 git checkout A^0 &&
5033
5034                 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
5035
5036                 test_i18ngrep Path.updated:.*x/d.renamed.to.z/d.in.B^0.*moving.it.to.y/d out &&
5037
5038                 git ls-files >paths &&
5039                 ! grep z/ paths &&
5040                 grep "y/d" paths &&
5041
5042                 test_path_is_missing z/d &&
5043                 test_path_is_file    y/d
5044         )
5045 '
5046
5047 # Testcase 13d, Rename/rename(1to1) due to directory rename on both sides
5048 #   Commit O: a/{z,y}, b/x,     c/w
5049 #   Commit A: a/z,     b/{y,x}, d/w
5050 #   Commit B: a/z,     d/x,     c/{y,w}
5051 #   Expected: a/z, d/{y,x,w} with no file location conflict for x
5052 #             Easy cases:
5053 #               * z is always in a; so it stays in a.
5054 #               * x starts in b, only modified on one side to move into d/
5055 #               * w starts in c, only modified on one side to move into d/
5056 #             Hard case:
5057 #               * A renames a/y to b/y, and B renames b/->d/ => a/y -> d/y
5058 #               * B renames a/y to c/y, and A renames c/->d/ => a/y -> d/y
5059 #               No conflict in where a/y ends up, so put it in d/y.
5060
5061 test_setup_13d () {
5062         test_create_repo 13d_$1 &&
5063         (
5064                 cd 13d_$1 &&
5065
5066                 mkdir a &&
5067                 mkdir b &&
5068                 mkdir c &&
5069                 echo z >a/z &&
5070                 echo y >a/y &&
5071                 echo x >b/x &&
5072                 echo w >c/w &&
5073                 git add a b c &&
5074                 test_tick &&
5075                 git commit -m "O" &&
5076
5077                 git branch O &&
5078                 git branch A &&
5079                 git branch B &&
5080
5081                 git checkout A &&
5082                 git mv a/y b/ &&
5083                 git mv c/ d/ &&
5084                 test_tick &&
5085                 git commit -m "A" &&
5086
5087                 git checkout B &&
5088                 git mv a/y c/ &&
5089                 git mv b/ d/ &&
5090                 test_tick &&
5091                 git commit -m "B"
5092         )
5093 }
5094
5095 test_expect_success '13d(conflict): messages for rename/rename(1to1) via dual transitive rename' '
5096         test_setup_13d conflict &&
5097         (
5098                 cd 13d_conflict &&
5099
5100                 git checkout A^0 &&
5101
5102                 test_must_fail git merge -s recursive B^0 >out 2>err &&
5103
5104                 test_i18ngrep CONFLICT..file.location.*a/y.renamed.to.b/y.*moved.to.d/y out &&
5105                 test_i18ngrep CONFLICT..file.location.*a/y.renamed.to.c/y.*moved.to.d/y out &&
5106
5107                 git ls-files >paths &&
5108                 ! grep b/ paths &&
5109                 ! grep c/ paths &&
5110                 grep "d/y" paths &&
5111
5112                 test_path_is_missing b/y &&
5113                 test_path_is_missing c/y &&
5114                 test_path_is_file    d/y
5115         )
5116 '
5117
5118 test_expect_success '13d(info): messages for rename/rename(1to1) via dual transitive rename' '
5119         test_setup_13d info &&
5120         (
5121                 cd 13d_info &&
5122
5123                 git reset --hard &&
5124                 git checkout A^0 &&
5125
5126                 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
5127
5128                 test_i18ngrep Path.updated.*a/y.renamed.to.b/y.*moving.it.to.d/y out &&
5129                 test_i18ngrep Path.updated.*a/y.renamed.to.c/y.*moving.it.to.d/y out &&
5130
5131                 git ls-files >paths &&
5132                 ! grep b/ paths &&
5133                 ! grep c/ paths &&
5134                 grep "d/y" paths &&
5135
5136                 test_path_is_missing b/y &&
5137                 test_path_is_missing c/y &&
5138                 test_path_is_file    d/y
5139         )
5140 '
5141
5142 # Testcase 13e, directory rename in virtual merge base
5143 #
5144 # This testcase has a slightly different setup than all the above cases, in
5145 # order to include a recursive case:
5146 #
5147 #      A   C
5148 #      o - o
5149 #     / \ / \
5150 #  O o   X   ?
5151 #     \ / \ /
5152 #      o   o
5153 #      B   D
5154 #
5155 #   Commit O: a/{z,y}
5156 #   Commit A: b/{z,y}
5157 #   Commit B: a/{z,y,x}
5158 #   Commit C: b/{z,y,x}
5159 #   Commit D: b/{z,y}, a/x
5160 #   Expected: b/{z,y,x}  (sort of; see below for why this might not be expected)
5161 #
5162 #   NOTES: 'X' represents a virtual merge base.  With the default of
5163 #          directory rename detection yielding conflicts, merging A and B
5164 #          results in a conflict complaining about whether 'x' should be
5165 #          under 'a/' or 'b/'.  However, when creating the virtual merge
5166 #          base 'X', since virtual merge bases need to be written out as a
5167 #          tree, we cannot have a conflict, so some resolution has to be
5168 #          picked.
5169 #
5170 #          In choosing the right resolution, it's worth noting here that
5171 #          commits C & D are merges of A & B that choose different
5172 #          locations for 'x' (i.e. they resolve the conflict differently),
5173 #          and so it would be nice when merging C & D if git could detect
5174 #          this difference of opinion and report a conflict.  But the only
5175 #          way to do so that I can think of would be to have the virtual
5176 #          merge base place 'x' in some directory other than either 'a/' or
5177 #          'b/', which seems a little weird -- especially since it'd result
5178 #          in a rename/rename(1to2) conflict with a source path that never
5179 #          existed in any version.
5180 #
5181 #          So, for now, when directory rename detection is set to
5182 #          'conflict' just avoid doing directory rename detection at all in
5183 #          the recursive case.  This will not allow us to detect a conflict
5184 #          in the outer merge for this special kind of setup, but it at
5185 #          least avoids hitting a BUG().
5186 #
5187 test_setup_13e () {
5188         test_create_repo 13e &&
5189         (
5190                 cd 13e &&
5191
5192                 mkdir a &&
5193                 echo z >a/z &&
5194                 echo y >a/y &&
5195                 git add a &&
5196                 test_tick &&
5197                 git commit -m "O" &&
5198
5199                 git branch O &&
5200                 git branch A &&
5201                 git branch B &&
5202
5203                 git checkout A &&
5204                 git mv a/ b/ &&
5205                 test_tick &&
5206                 git commit -m "A" &&
5207
5208                 git checkout B &&
5209                 echo x >a/x &&
5210                 git add a &&
5211                 test_tick &&
5212                 git commit -m "B" &&
5213
5214                 git branch C A &&
5215                 git branch D B &&
5216
5217                 git checkout C &&
5218                 test_must_fail git -c merge.directoryRenames=conflict merge B &&
5219                 git add b/x &&
5220                 test_tick &&
5221                 git commit -m "C" &&
5222
5223
5224                 git checkout D &&
5225                 test_must_fail git -c merge.directoryRenames=conflict merge A &&
5226                 git add b/x &&
5227                 mkdir a &&
5228                 git mv b/x a/x &&
5229                 test_tick &&
5230                 git commit -m "D"
5231         )
5232 }
5233
5234 test_expect_success '13e: directory rename detection in recursive case' '
5235         test_setup_13e &&
5236         (
5237                 cd 13e &&
5238
5239                 git checkout --quiet D^0 &&
5240
5241                 git -c merge.directoryRenames=conflict merge -s recursive C^0 >out 2>err &&
5242
5243                 test_i18ngrep ! CONFLICT out &&
5244                 test_i18ngrep ! BUG: err &&
5245                 test_i18ngrep ! core.dumped err &&
5246                 test_must_be_empty err &&
5247
5248                 git ls-files >paths &&
5249                 ! grep a/x paths &&
5250                 grep b/x paths
5251         )
5252 '
5253
5254 test_done