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