directory rename detection: tests for handling overwriting untracked files
[git] / t / t6043-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
30
31 ###########################################################################
32 # SECTION 1: Basic cases we should be able to handle
33 ###########################################################################
34
35 # Testcase 1a, Basic directory rename.
36 #   Commit O: z/{b,c}
37 #   Commit A: y/{b,c}
38 #   Commit B: z/{b,c,d,e/f}
39 #   Expected: y/{b,c,d,e/f}
40
41 test_expect_success '1a-setup: Simple directory rename detection' '
42         test_create_repo 1a &&
43         (
44                 cd 1a &&
45
46                 mkdir z &&
47                 echo b >z/b &&
48                 echo c >z/c &&
49                 git add z &&
50                 test_tick &&
51                 git commit -m "O" &&
52
53                 git branch O &&
54                 git branch A &&
55                 git branch B &&
56
57                 git checkout A &&
58                 git mv z y &&
59                 test_tick &&
60                 git commit -m "A" &&
61
62                 git checkout B &&
63                 echo d >z/d &&
64                 mkdir z/e &&
65                 echo f >z/e/f &&
66                 git add z/d z/e/f &&
67                 test_tick &&
68                 git commit -m "B"
69         )
70 '
71
72 test_expect_failure '1a-check: Simple directory rename detection' '
73         (
74                 cd 1a &&
75
76                 git checkout A^0 &&
77
78                 git merge -s recursive B^0 &&
79
80                 git ls-files -s >out &&
81                 test_line_count = 4 out &&
82
83                 git rev-parse >actual \
84                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e/f &&
85                 git rev-parse >expect \
86                         O:z/b    O:z/c    B:z/d    B:z/e/f &&
87                 test_cmp expect actual &&
88
89                 git hash-object y/d >actual &&
90                 git rev-parse B:z/d >expect &&
91                 test_cmp expect actual &&
92
93                 test_must_fail git rev-parse HEAD:z/d &&
94                 test_must_fail git rev-parse HEAD:z/e/f &&
95                 test_path_is_missing z/d &&
96                 test_path_is_missing z/e/f
97         )
98 '
99
100 # Testcase 1b, Merge a directory with another
101 #   Commit O: z/{b,c},   y/d
102 #   Commit A: z/{b,c,e}, y/d
103 #   Commit B: y/{b,c,d}
104 #   Expected: y/{b,c,d,e}
105
106 test_expect_success '1b-setup: Merge a directory with another' '
107         test_create_repo 1b &&
108         (
109                 cd 1b &&
110
111                 mkdir z &&
112                 echo b >z/b &&
113                 echo c >z/c &&
114                 mkdir y &&
115                 echo d >y/d &&
116                 git add z y &&
117                 test_tick &&
118                 git commit -m "O" &&
119
120                 git branch O &&
121                 git branch A &&
122                 git branch B &&
123
124                 git checkout A &&
125                 echo e >z/e &&
126                 git add z/e &&
127                 test_tick &&
128                 git commit -m "A" &&
129
130                 git checkout B &&
131                 git mv z/b y &&
132                 git mv z/c y &&
133                 rmdir z &&
134                 test_tick &&
135                 git commit -m "B"
136         )
137 '
138
139 test_expect_failure '1b-check: Merge a directory with another' '
140         (
141                 cd 1b &&
142
143                 git checkout A^0 &&
144
145                 git merge -s recursive B^0 &&
146
147                 git ls-files -s >out &&
148                 test_line_count = 4 out &&
149
150                 git rev-parse >actual \
151                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e &&
152                 git rev-parse >expect \
153                         O:z/b    O:z/c    O:y/d    A:z/e &&
154                 test_cmp expect actual &&
155                 test_must_fail git rev-parse HEAD:z/e
156         )
157 '
158
159 # Testcase 1c, Transitive renaming
160 #   (Related to testcases 3a and 6d -- when should a transitive rename apply?)
161 #   (Related to testcases 9c and 9d -- can transitivity repeat?)
162 #   Commit O: z/{b,c},   x/d
163 #   Commit A: y/{b,c},   x/d
164 #   Commit B: z/{b,c,d}
165 #   Expected: y/{b,c,d}  (because x/d -> z/d -> y/d)
166
167 test_expect_success '1c-setup: Transitive renaming' '
168         test_create_repo 1c &&
169         (
170                 cd 1c &&
171
172                 mkdir z &&
173                 echo b >z/b &&
174                 echo c >z/c &&
175                 mkdir x &&
176                 echo d >x/d &&
177                 git add z x &&
178                 test_tick &&
179                 git commit -m "O" &&
180
181                 git branch O &&
182                 git branch A &&
183                 git branch B &&
184
185                 git checkout A &&
186                 git mv z y &&
187                 test_tick &&
188                 git commit -m "A" &&
189
190                 git checkout B &&
191                 git mv x/d z/d &&
192                 test_tick &&
193                 git commit -m "B"
194         )
195 '
196
197 test_expect_failure '1c-check: Transitive renaming' '
198         (
199                 cd 1c &&
200
201                 git checkout A^0 &&
202
203                 git merge -s recursive B^0 &&
204
205                 git ls-files -s >out &&
206                 test_line_count = 3 out &&
207
208                 git rev-parse >actual \
209                         HEAD:y/b HEAD:y/c HEAD:y/d &&
210                 git rev-parse >expect \
211                         O:z/b    O:z/c    O:x/d &&
212                 test_cmp expect actual &&
213                 test_must_fail git rev-parse HEAD:x/d &&
214                 test_must_fail git rev-parse HEAD:z/d &&
215                 test_path_is_missing z/d
216         )
217 '
218
219 # Testcase 1d, Directory renames (merging two directories into one new one)
220 #              cause a rename/rename(2to1) conflict
221 #   (Related to testcases 1c and 7b)
222 #   Commit O. z/{b,c},        y/{d,e}
223 #   Commit A. x/{b,c},        y/{d,e,m,wham_1}
224 #   Commit B. z/{b,c,n,wham_2}, x/{d,e}
225 #   Expected: x/{b,c,d,e,m,n}, CONFLICT:(y/wham_1 & z/wham_2 -> x/wham)
226 #   Note: y/m & z/n should definitely move into x.  By the same token, both
227 #         y/wham_1 & z/wham_2 should too...giving us a conflict.
228
229 test_expect_success '1d-setup: Directory renames cause a rename/rename(2to1) conflict' '
230         test_create_repo 1d &&
231         (
232                 cd 1d &&
233
234                 mkdir z &&
235                 echo b >z/b &&
236                 echo c >z/c &&
237                 mkdir y &&
238                 echo d >y/d &&
239                 echo e >y/e &&
240                 git add z y &&
241                 test_tick &&
242                 git commit -m "O" &&
243
244                 git branch O &&
245                 git branch A &&
246                 git branch B &&
247
248                 git checkout A &&
249                 git mv z x &&
250                 echo m >y/m &&
251                 echo wham1 >y/wham &&
252                 git add y &&
253                 test_tick &&
254                 git commit -m "A" &&
255
256                 git checkout B &&
257                 git mv y x &&
258                 echo n >z/n &&
259                 echo wham2 >z/wham &&
260                 git add z &&
261                 test_tick &&
262                 git commit -m "B"
263         )
264 '
265
266 test_expect_failure '1d-check: Directory renames cause a rename/rename(2to1) conflict' '
267         (
268                 cd 1d &&
269
270                 git checkout A^0 &&
271
272                 test_must_fail git merge -s recursive B^0 >out &&
273                 test_i18ngrep "CONFLICT (rename/rename)" out &&
274
275                 git ls-files -s >out &&
276                 test_line_count = 8 out &&
277                 git ls-files -u >out &&
278                 test_line_count = 2 out &&
279                 git ls-files -o >out &&
280                 test_line_count = 3 out &&
281
282                 git rev-parse >actual \
283                         :0:x/b :0:x/c :0:x/d :0:x/e :0:x/m :0:x/n &&
284                 git rev-parse >expect \
285                          O:z/b  O:z/c  O:y/d  O:y/e  A:y/m  B:z/n &&
286                 test_cmp expect actual &&
287
288                 test_must_fail git rev-parse :0:x/wham &&
289                 git rev-parse >actual \
290                         :2:x/wham :3:x/wham &&
291                 git rev-parse >expect \
292                          A:y/wham  B:z/wham &&
293                 test_cmp expect actual &&
294
295                 test_path_is_missing x/wham &&
296                 test_path_is_file x/wham~HEAD &&
297                 test_path_is_file x/wham~B^0 &&
298
299                 git hash-object >actual \
300                         x/wham~HEAD x/wham~B^0 &&
301                 git rev-parse >expect \
302                         A:y/wham    B:z/wham &&
303                 test_cmp expect actual
304         )
305 '
306
307 # Testcase 1e, Renamed directory, with all filenames being renamed too
308 #   (Related to testcases 9f & 9g)
309 #   Commit O: z/{oldb,oldc}
310 #   Commit A: y/{newb,newc}
311 #   Commit B: z/{oldb,oldc,d}
312 #   Expected: y/{newb,newc,d}
313
314 test_expect_success '1e-setup: Renamed directory, with all files being renamed too' '
315         test_create_repo 1e &&
316         (
317                 cd 1e &&
318
319                 mkdir z &&
320                 echo b >z/oldb &&
321                 echo c >z/oldc &&
322                 git add z &&
323                 test_tick &&
324                 git commit -m "O" &&
325
326                 git branch O &&
327                 git branch A &&
328                 git branch B &&
329
330                 git checkout A &&
331                 mkdir y &&
332                 git mv z/oldb y/newb &&
333                 git mv z/oldc y/newc &&
334                 test_tick &&
335                 git commit -m "A" &&
336
337                 git checkout B &&
338                 echo d >z/d &&
339                 git add z/d &&
340                 test_tick &&
341                 git commit -m "B"
342         )
343 '
344
345 test_expect_failure '1e-check: Renamed directory, with all files being renamed too' '
346         (
347                 cd 1e &&
348
349                 git checkout A^0 &&
350
351                 git merge -s recursive B^0 &&
352
353                 git ls-files -s >out &&
354                 test_line_count = 3 out &&
355
356                 git rev-parse >actual \
357                         HEAD:y/newb HEAD:y/newc HEAD:y/d &&
358                 git rev-parse >expect \
359                         O:z/oldb    O:z/oldc    B:z/d &&
360                 test_cmp expect actual &&
361                 test_must_fail git rev-parse HEAD:z/d
362         )
363 '
364
365 # Testcase 1f, Split a directory into two other directories
366 #   (Related to testcases 3a, all of section 2, and all of section 4)
367 #   Commit O: z/{b,c,d,e,f}
368 #   Commit A: z/{b,c,d,e,f,g}
369 #   Commit B: y/{b,c}, x/{d,e,f}
370 #   Expected: y/{b,c}, x/{d,e,f,g}
371
372 test_expect_success '1f-setup: Split a directory into two other directories' '
373         test_create_repo 1f &&
374         (
375                 cd 1f &&
376
377                 mkdir z &&
378                 echo b >z/b &&
379                 echo c >z/c &&
380                 echo d >z/d &&
381                 echo e >z/e &&
382                 echo f >z/f &&
383                 git add z &&
384                 test_tick &&
385                 git commit -m "O" &&
386
387                 git branch O &&
388                 git branch A &&
389                 git branch B &&
390
391                 git checkout A &&
392                 echo g >z/g &&
393                 git add z/g &&
394                 test_tick &&
395                 git commit -m "A" &&
396
397                 git checkout B &&
398                 mkdir y &&
399                 mkdir x &&
400                 git mv z/b y/ &&
401                 git mv z/c y/ &&
402                 git mv z/d x/ &&
403                 git mv z/e x/ &&
404                 git mv z/f x/ &&
405                 rmdir z &&
406                 test_tick &&
407                 git commit -m "B"
408         )
409 '
410
411 test_expect_failure '1f-check: Split a directory into two other directories' '
412         (
413                 cd 1f &&
414
415                 git checkout A^0 &&
416
417                 git merge -s recursive B^0 &&
418
419                 git ls-files -s >out &&
420                 test_line_count = 6 out &&
421
422                 git rev-parse >actual \
423                         HEAD:y/b HEAD:y/c HEAD:x/d HEAD:x/e HEAD:x/f HEAD:x/g &&
424                 git rev-parse >expect \
425                         O:z/b    O:z/c    O:z/d    O:z/e    O:z/f    A:z/g &&
426                 test_cmp expect actual &&
427                 test_path_is_missing z/g &&
428                 test_must_fail git rev-parse HEAD:z/g
429         )
430 '
431
432 ###########################################################################
433 # Rules suggested by testcases in section 1:
434 #
435 #   We should still detect the directory rename even if it wasn't just
436 #   the directory renamed, but the files within it. (see 1b)
437 #
438 #   If renames split a directory into two or more others, the directory
439 #   with the most renames, "wins" (see 1c).  However, see the testcases
440 #   in section 2, plus testcases 3a and 4a.
441 ###########################################################################
442
443
444 ###########################################################################
445 # SECTION 2: Split into multiple directories, with equal number of paths
446 #
447 # Explore the splitting-a-directory rules a bit; what happens in the
448 # edge cases?
449 #
450 # Note that there is a closely related case of a directory not being
451 # split on either side of history, but being renamed differently on
452 # each side.  See testcase 8e for that.
453 ###########################################################################
454
455 # Testcase 2a, Directory split into two on one side, with equal numbers of paths
456 #   Commit O: z/{b,c}
457 #   Commit A: y/b, w/c
458 #   Commit B: z/{b,c,d}
459 #   Expected: y/b, w/c, z/d, with warning about z/ -> (y/ vs. w/) conflict
460 test_expect_success '2a-setup: Directory split into two on one side, with equal numbers of paths' '
461         test_create_repo 2a &&
462         (
463                 cd 2a &&
464
465                 mkdir z &&
466                 echo b >z/b &&
467                 echo c >z/c &&
468                 git add z &&
469                 test_tick &&
470                 git commit -m "O" &&
471
472                 git branch O &&
473                 git branch A &&
474                 git branch B &&
475
476                 git checkout A &&
477                 mkdir y &&
478                 mkdir w &&
479                 git mv z/b y/ &&
480                 git mv z/c w/ &&
481                 test_tick &&
482                 git commit -m "A" &&
483
484                 git checkout B &&
485                 echo d >z/d &&
486                 git add z/d &&
487                 test_tick &&
488                 git commit -m "B"
489         )
490 '
491
492 test_expect_failure '2a-check: Directory split into two on one side, with equal numbers of paths' '
493         (
494                 cd 2a &&
495
496                 git checkout A^0 &&
497
498                 test_must_fail git merge -s recursive B^0 >out &&
499                 test_i18ngrep "CONFLICT.*directory rename split" out &&
500
501                 git ls-files -s >out &&
502                 test_line_count = 3 out &&
503                 git ls-files -u >out &&
504                 test_line_count = 0 out &&
505                 git ls-files -o >out &&
506                 test_line_count = 1 out &&
507
508                 git rev-parse >actual \
509                         :0:y/b :0:w/c :0:z/d &&
510                 git rev-parse >expect \
511                          O:z/b  O:z/c  B:z/d &&
512                 test_cmp expect actual
513         )
514 '
515
516 # Testcase 2b, Directory split into two on one side, with equal numbers of paths
517 #   Commit O: z/{b,c}
518 #   Commit A: y/b, w/c
519 #   Commit B: z/{b,c}, x/d
520 #   Expected: y/b, w/c, x/d; No warning about z/ -> (y/ vs. w/) conflict
521 test_expect_success '2b-setup: Directory split into two on one side, with equal numbers of paths' '
522         test_create_repo 2b &&
523         (
524                 cd 2b &&
525
526                 mkdir z &&
527                 echo b >z/b &&
528                 echo c >z/c &&
529                 git add z &&
530                 test_tick &&
531                 git commit -m "O" &&
532
533                 git branch O &&
534                 git branch A &&
535                 git branch B &&
536
537                 git checkout A &&
538                 mkdir y &&
539                 mkdir w &&
540                 git mv z/b y/ &&
541                 git mv z/c w/ &&
542                 test_tick &&
543                 git commit -m "A" &&
544
545                 git checkout B &&
546                 mkdir x &&
547                 echo d >x/d &&
548                 git add x/d &&
549                 test_tick &&
550                 git commit -m "B"
551         )
552 '
553
554 test_expect_success '2b-check: Directory split into two on one side, with equal numbers of paths' '
555         (
556                 cd 2b &&
557
558                 git checkout A^0 &&
559
560                 git merge -s recursive B^0 >out &&
561
562                 git ls-files -s >out &&
563                 test_line_count = 3 out &&
564                 git ls-files -u >out &&
565                 test_line_count = 0 out &&
566                 git ls-files -o >out &&
567                 test_line_count = 1 out &&
568
569                 git rev-parse >actual \
570                         :0:y/b :0:w/c :0:x/d &&
571                 git rev-parse >expect \
572                          O:z/b  O:z/c  B:x/d &&
573                 test_cmp expect actual &&
574                 test_i18ngrep ! "CONFLICT.*directory rename split" out
575         )
576 '
577
578 ###########################################################################
579 # Rules suggested by section 2:
580 #
581 #   None; the rule was already covered in section 1.  These testcases are
582 #   here just to make sure the conflict resolution and necessary warning
583 #   messages are handled correctly.
584 ###########################################################################
585
586
587 ###########################################################################
588 # SECTION 3: Path in question is the source path for some rename already
589 #
590 # Combining cases from Section 1 and trying to handle them could lead to
591 # directory renaming detection being over-applied.  So, this section
592 # provides some good testcases to check that the implementation doesn't go
593 # too far.
594 ###########################################################################
595
596 # Testcase 3a, Avoid implicit rename if involved as source on other side
597 #   (Related to testcases 1c, 1f, and 9h)
598 #   Commit O: z/{b,c,d}
599 #   Commit A: z/{b,c,d} (no change)
600 #   Commit B: y/{b,c}, x/d
601 #   Expected: y/{b,c}, x/d
602 test_expect_success '3a-setup: Avoid implicit rename if involved as source on other side' '
603         test_create_repo 3a &&
604         (
605                 cd 3a &&
606
607                 mkdir z &&
608                 echo b >z/b &&
609                 echo c >z/c &&
610                 echo d >z/d &&
611                 git add z &&
612                 test_tick &&
613                 git commit -m "O" &&
614
615                 git branch O &&
616                 git branch A &&
617                 git branch B &&
618
619                 git checkout A &&
620                 test_tick &&
621                 git commit --allow-empty -m "A" &&
622
623                 git checkout B &&
624                 mkdir y &&
625                 mkdir x &&
626                 git mv z/b y/ &&
627                 git mv z/c y/ &&
628                 git mv z/d x/ &&
629                 rmdir z &&
630                 test_tick &&
631                 git commit -m "B"
632         )
633 '
634
635 test_expect_success '3a-check: Avoid implicit rename if involved as source on other side' '
636         (
637                 cd 3a &&
638
639                 git checkout A^0 &&
640
641                 git merge -s recursive B^0 &&
642
643                 git ls-files -s >out &&
644                 test_line_count = 3 out &&
645
646                 git rev-parse >actual \
647                         HEAD:y/b HEAD:y/c HEAD:x/d &&
648                 git rev-parse >expect \
649                         O:z/b    O:z/c    O:z/d &&
650                 test_cmp expect actual
651         )
652 '
653
654 # Testcase 3b, Avoid implicit rename if involved as source on other side
655 #   (Related to testcases 5c and 7c, also kind of 1e and 1f)
656 #   Commit O: z/{b,c,d}
657 #   Commit A: y/{b,c}, x/d
658 #   Commit B: z/{b,c}, w/d
659 #   Expected: y/{b,c}, CONFLICT:(z/d -> x/d vs. w/d)
660 #   NOTE: We're particularly checking that since z/d is already involved as
661 #         a source in a file rename on the same side of history, that we don't
662 #         get it involved in directory rename detection.  If it were, we might
663 #         end up with CONFLICT:(z/d -> y/d vs. x/d vs. w/d), i.e. a
664 #         rename/rename/rename(1to3) conflict, which is just weird.
665 test_expect_success '3b-setup: Avoid implicit rename if involved as source on current side' '
666         test_create_repo 3b &&
667         (
668                 cd 3b &&
669
670                 mkdir z &&
671                 echo b >z/b &&
672                 echo c >z/c &&
673                 echo d >z/d &&
674                 git add z &&
675                 test_tick &&
676                 git commit -m "O" &&
677
678                 git branch O &&
679                 git branch A &&
680                 git branch B &&
681
682                 git checkout A &&
683                 mkdir y &&
684                 mkdir x &&
685                 git mv z/b y/ &&
686                 git mv z/c y/ &&
687                 git mv z/d x/ &&
688                 rmdir z &&
689                 test_tick &&
690                 git commit -m "A" &&
691
692                 git checkout B &&
693                 mkdir w &&
694                 git mv z/d w/ &&
695                 test_tick &&
696                 git commit -m "B"
697         )
698 '
699
700 test_expect_success '3b-check: Avoid implicit rename if involved as source on current side' '
701         (
702                 cd 3b &&
703
704                 git checkout A^0 &&
705
706                 test_must_fail git merge -s recursive B^0 >out &&
707                 test_i18ngrep CONFLICT.*rename/rename.*z/d.*x/d.*w/d out &&
708                 test_i18ngrep ! CONFLICT.*rename/rename.*y/d out &&
709
710                 git ls-files -s >out &&
711                 test_line_count = 5 out &&
712                 git ls-files -u >out &&
713                 test_line_count = 3 out &&
714                 git ls-files -o >out &&
715                 test_line_count = 1 out &&
716
717                 git rev-parse >actual \
718                         :0:y/b :0:y/c :1:z/d :2:x/d :3:w/d &&
719                 git rev-parse >expect \
720                          O:z/b  O:z/c  O:z/d  O:z/d  O:z/d &&
721                 test_cmp expect actual &&
722
723                 test_path_is_missing z/d &&
724                 git hash-object >actual \
725                         x/d   w/d &&
726                 git rev-parse >expect \
727                         O:z/d O:z/d &&
728                 test_cmp expect actual
729         )
730 '
731
732 ###########################################################################
733 # Rules suggested by section 3:
734 #
735 #   Avoid directory-rename-detection for a path, if that path is the source
736 #   of a rename on either side of a merge.
737 ###########################################################################
738
739
740 ###########################################################################
741 # SECTION 4: Partially renamed directory; still exists on both sides of merge
742 #
743 # What if we were to attempt to do directory rename detection when someone
744 # "mostly" moved a directory but still left some files around, or,
745 # equivalently, fully renamed a directory in one commmit and then recreated
746 # that directory in a later commit adding some new files and then tried to
747 # merge?
748 #
749 # It's hard to divine user intent in these cases, because you can make an
750 # argument that, depending on the intermediate history of the side being
751 # merged, that some users will want files in that directory to
752 # automatically be detected and renamed, while users with a different
753 # intermediate history wouldn't want that rename to happen.
754 #
755 # I think that it is best to simply not have directory rename detection
756 # apply to such cases.  My reasoning for this is four-fold: (1) it's
757 # easiest for users in general to figure out what happened if we don't
758 # apply directory rename detection in any such case, (2) it's an easy rule
759 # to explain ["We don't do directory rename detection if the directory
760 # still exists on both sides of the merge"], (3) we can get some hairy
761 # edge/corner cases that would be really confusing and possibly not even
762 # representable in the index if we were to even try, and [related to 3] (4)
763 # attempting to resolve this issue of divining user intent by examining
764 # intermediate history goes against the spirit of three-way merges and is a
765 # path towards crazy corner cases that are far more complex than what we're
766 # already dealing with.
767 #
768 # Note that the wording of the rule ("We don't do directory rename
769 # detection if the directory still exists on both sides of the merge.")
770 # also excludes "renaming" of a directory into a subdirectory of itself
771 # (e.g. /some/dir/* -> /some/dir/subdir/*).  It may be possible to carve
772 # out an exception for "renaming"-beneath-itself cases without opening
773 # weird edge/corner cases for other partial directory renames, but for now
774 # we are keeping the rule simple.
775 #
776 # This section contains a test for a partially-renamed-directory case.
777 ###########################################################################
778
779 # Testcase 4a, Directory split, with original directory still present
780 #   (Related to testcase 1f)
781 #   Commit O: z/{b,c,d,e}
782 #   Commit A: y/{b,c,d}, z/e
783 #   Commit B: z/{b,c,d,e,f}
784 #   Expected: y/{b,c,d}, z/{e,f}
785 #   NOTE: Even though most files from z moved to y, we don't want f to follow.
786
787 test_expect_success '4a-setup: Directory split, with original directory still present' '
788         test_create_repo 4a &&
789         (
790                 cd 4a &&
791
792                 mkdir z &&
793                 echo b >z/b &&
794                 echo c >z/c &&
795                 echo d >z/d &&
796                 echo e >z/e &&
797                 git add z &&
798                 test_tick &&
799                 git commit -m "O" &&
800
801                 git branch O &&
802                 git branch A &&
803                 git branch B &&
804
805                 git checkout A &&
806                 mkdir y &&
807                 git mv z/b y/ &&
808                 git mv z/c y/ &&
809                 git mv z/d y/ &&
810                 test_tick &&
811                 git commit -m "A" &&
812
813                 git checkout B &&
814                 echo f >z/f &&
815                 git add z/f &&
816                 test_tick &&
817                 git commit -m "B"
818         )
819 '
820
821 test_expect_success '4a-check: Directory split, with original directory still present' '
822         (
823                 cd 4a &&
824
825                 git checkout A^0 &&
826
827                 git merge -s recursive B^0 &&
828
829                 git ls-files -s >out &&
830                 test_line_count = 5 out &&
831                 git ls-files -u >out &&
832                 test_line_count = 0 out &&
833                 git ls-files -o >out &&
834                 test_line_count = 1 out &&
835
836                 git rev-parse >actual \
837                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/e HEAD:z/f &&
838                 git rev-parse >expect \
839                         O:z/b    O:z/c    O:z/d    O:z/e    B:z/f &&
840                 test_cmp expect actual
841         )
842 '
843
844 ###########################################################################
845 # Rules suggested by section 4:
846 #
847 #   Directory-rename-detection should be turned off for any directories (as
848 #   a source for renames) that exist on both sides of the merge.  (The "as
849 #   a source for renames" clarification is due to cases like 1c where
850 #   the target directory exists on both sides and we do want the rename
851 #   detection.)  But, sadly, see testcase 8b.
852 ###########################################################################
853
854
855 ###########################################################################
856 # SECTION 5: Files/directories in the way of subset of to-be-renamed paths
857 #
858 # Implicitly renaming files due to a detected directory rename could run
859 # into problems if there are files or directories in the way of the paths
860 # we want to rename.  Explore such cases in this section.
861 ###########################################################################
862
863 # Testcase 5a, Merge directories, other side adds files to original and target
864 #   Commit O: z/{b,c},       y/d
865 #   Commit A: z/{b,c,e_1,f}, y/{d,e_2}
866 #   Commit B: y/{b,c,d}
867 #   Expected: z/e_1, y/{b,c,d,e_2,f} + CONFLICT warning
868 #   NOTE: While directory rename detection is active here causing z/f to
869 #         become y/f, we did not apply this for z/e_1 because that would
870 #         give us an add/add conflict for y/e_1 vs y/e_2.  This problem with
871 #         this add/add, is that both versions of y/e are from the same side
872 #         of history, giving us no way to represent this conflict in the
873 #         index.
874
875 test_expect_success '5a-setup: Merge directories, other side adds files to original and target' '
876         test_create_repo 5a &&
877         (
878                 cd 5a &&
879
880                 mkdir z &&
881                 echo b >z/b &&
882                 echo c >z/c &&
883                 mkdir y &&
884                 echo d >y/d &&
885                 git add z y &&
886                 test_tick &&
887                 git commit -m "O" &&
888
889                 git branch O &&
890                 git branch A &&
891                 git branch B &&
892
893                 git checkout A &&
894                 echo e1 >z/e &&
895                 echo f >z/f &&
896                 echo e2 >y/e &&
897                 git add z/e z/f y/e &&
898                 test_tick &&
899                 git commit -m "A" &&
900
901                 git checkout B &&
902                 git mv z/b y/ &&
903                 git mv z/c y/ &&
904                 rmdir z &&
905                 test_tick &&
906                 git commit -m "B"
907         )
908 '
909
910 test_expect_failure '5a-check: Merge directories, other side adds files to original and target' '
911         (
912                 cd 5a &&
913
914                 git checkout A^0 &&
915
916                 test_must_fail git merge -s recursive B^0 >out &&
917                 test_i18ngrep "CONFLICT.*implicit dir rename" out &&
918
919                 git ls-files -s >out &&
920                 test_line_count = 6 out &&
921                 git ls-files -u >out &&
922                 test_line_count = 0 out &&
923                 git ls-files -o >out &&
924                 test_line_count = 1 out &&
925
926                 git rev-parse >actual \
927                         :0:y/b :0:y/c :0:y/d :0:y/e :0:z/e :0:y/f &&
928                 git rev-parse >expect \
929                          O:z/b  O:z/c  O:y/d  A:y/e  A:z/e  A:z/f &&
930                 test_cmp expect actual
931         )
932 '
933
934 # Testcase 5b, Rename/delete in order to get add/add/add conflict
935 #   (Related to testcase 8d; these may appear slightly inconsistent to users;
936 #    Also related to testcases 7d and 7e)
937 #   Commit O: z/{b,c,d_1}
938 #   Commit A: y/{b,c,d_2}
939 #   Commit B: z/{b,c,d_1,e}, y/d_3
940 #   Expected: y/{b,c,e}, CONFLICT(add/add: y/d_2 vs. y/d_3)
941 #   NOTE: If z/d_1 in commit B were to be involved in dir rename detection, as
942 #         we normaly would since z/ is being renamed to y/, then this would be
943 #         a rename/delete (z/d_1 -> y/d_1 vs. deleted) AND an add/add/add
944 #         conflict of y/d_1 vs. y/d_2 vs. y/d_3.  Add/add/add is not
945 #         representable in the index, so the existence of y/d_3 needs to
946 #         cause us to bail on directory rename detection for that path, falling
947 #         back to git behavior without the directory rename detection.
948
949 test_expect_success '5b-setup: Rename/delete in order to get add/add/add conflict' '
950         test_create_repo 5b &&
951         (
952                 cd 5b &&
953
954                 mkdir z &&
955                 echo b >z/b &&
956                 echo c >z/c &&
957                 echo d1 >z/d &&
958                 git add z &&
959                 test_tick &&
960                 git commit -m "O" &&
961
962                 git branch O &&
963                 git branch A &&
964                 git branch B &&
965
966                 git checkout A &&
967                 git rm z/d &&
968                 git mv z y &&
969                 echo d2 >y/d &&
970                 git add y/d &&
971                 test_tick &&
972                 git commit -m "A" &&
973
974                 git checkout B &&
975                 mkdir y &&
976                 echo d3 >y/d &&
977                 echo e >z/e &&
978                 git add y/d z/e &&
979                 test_tick &&
980                 git commit -m "B"
981         )
982 '
983
984 test_expect_failure '5b-check: Rename/delete in order to get add/add/add conflict' '
985         (
986                 cd 5b &&
987
988                 git checkout A^0 &&
989
990                 test_must_fail git merge -s recursive B^0 >out &&
991                 test_i18ngrep "CONFLICT (add/add).* y/d" out &&
992
993                 git ls-files -s >out &&
994                 test_line_count = 5 out &&
995                 git ls-files -u >out &&
996                 test_line_count = 2 out &&
997                 git ls-files -o >out &&
998                 test_line_count = 1 out &&
999
1000                 git rev-parse >actual \
1001                         :0:y/b :0:y/c :0:y/e :2:y/d :3:y/d &&
1002                 git rev-parse >expect \
1003                          O:z/b  O:z/c  B:z/e  A:y/d  B:y/d &&
1004                 test_cmp expect actual &&
1005
1006                 test_must_fail git rev-parse :1:y/d &&
1007                 test_path_is_file y/d
1008         )
1009 '
1010
1011 # Testcase 5c, Transitive rename would cause rename/rename/rename/add/add/add
1012 #   (Directory rename detection would result in transitive rename vs.
1013 #    rename/rename(1to2) and turn it into a rename/rename(1to3).  Further,
1014 #    rename paths conflict with separate adds on the other side)
1015 #   (Related to testcases 3b and 7c)
1016 #   Commit O: z/{b,c}, x/d_1
1017 #   Commit A: y/{b,c,d_2}, w/d_1
1018 #   Commit B: z/{b,c,d_1,e}, w/d_3, y/d_4
1019 #   Expected: A mess, but only a rename/rename(1to2)/add/add mess.  Use the
1020 #             presence of y/d_4 in B to avoid doing transitive rename of
1021 #             x/d_1 -> z/d_1 -> y/d_1, so that the only paths we have at
1022 #             y/d are y/d_2 and y/d_4.  We still do the move from z/e to y/e,
1023 #             though, because it doesn't have anything in the way.
1024
1025 test_expect_success '5c-setup: Transitive rename would cause rename/rename/rename/add/add/add' '
1026         test_create_repo 5c &&
1027         (
1028                 cd 5c &&
1029
1030                 mkdir z &&
1031                 echo b >z/b &&
1032                 echo c >z/c &&
1033                 mkdir x &&
1034                 echo d1 >x/d &&
1035                 git add z x &&
1036                 test_tick &&
1037                 git commit -m "O" &&
1038
1039                 git branch O &&
1040                 git branch A &&
1041                 git branch B &&
1042
1043                 git checkout A &&
1044                 git mv z y &&
1045                 echo d2 >y/d &&
1046                 git add y/d &&
1047                 git mv x w &&
1048                 test_tick &&
1049                 git commit -m "A" &&
1050
1051                 git checkout B &&
1052                 git mv x/d z/ &&
1053                 mkdir w &&
1054                 mkdir y &&
1055                 echo d3 >w/d &&
1056                 echo d4 >y/d &&
1057                 echo e >z/e &&
1058                 git add w/ y/ z/e &&
1059                 test_tick &&
1060                 git commit -m "B"
1061         )
1062 '
1063
1064 test_expect_failure '5c-check: Transitive rename would cause rename/rename/rename/add/add/add' '
1065         (
1066                 cd 5c &&
1067
1068                 git checkout A^0 &&
1069
1070                 test_must_fail git merge -s recursive B^0 >out &&
1071                 test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*z/d" out &&
1072                 test_i18ngrep "CONFLICT (add/add).* y/d" out &&
1073
1074                 git ls-files -s >out &&
1075                 test_line_count = 9 out &&
1076                 git ls-files -u >out &&
1077                 test_line_count = 6 out &&
1078                 git ls-files -o >out &&
1079                 test_line_count = 3 out &&
1080
1081                 git rev-parse >actual \
1082                         :0:y/b :0:y/c :0:y/e &&
1083                 git rev-parse >expect \
1084                          O:z/b  O:z/c  B:z/e &&
1085                 test_cmp expect actual &&
1086
1087                 test_must_fail git rev-parse :1:y/d &&
1088                 git rev-parse >actual \
1089                         :2:w/d :3:w/d :1:x/d :2:y/d :3:y/d :3:z/d &&
1090                 git rev-parse >expect \
1091                          O:x/d  B:w/d  O:x/d  A:y/d  B:y/d  O:x/d &&
1092                 test_cmp expect actual &&
1093
1094                 git hash-object >actual \
1095                         w/d~HEAD w/d~B^0 z/d &&
1096                 git rev-parse >expect \
1097                         O:x/d    B:w/d   O:x/d &&
1098                 test_cmp expect actual &&
1099                 test_path_is_missing x/d &&
1100                 test_path_is_file y/d &&
1101                 grep -q "<<<<" y/d  # conflict markers should be present
1102         )
1103 '
1104
1105 # Testcase 5d, Directory/file/file conflict due to directory rename
1106 #   Commit O: z/{b,c}
1107 #   Commit A: y/{b,c,d_1}
1108 #   Commit B: z/{b,c,d_2,f}, y/d/e
1109 #   Expected: y/{b,c,d/e,f}, z/d_2, CONFLICT(file/directory), y/d_1~HEAD
1110 #   Note: The fact that y/d/ exists in B makes us bail on directory rename
1111 #         detection for z/d_2, but that doesn't prevent us from applying the
1112 #         directory rename detection for z/f -> y/f.
1113
1114 test_expect_success '5d-setup: Directory/file/file conflict due to directory rename' '
1115         test_create_repo 5d &&
1116         (
1117                 cd 5d &&
1118
1119                 mkdir z &&
1120                 echo b >z/b &&
1121                 echo c >z/c &&
1122                 git add z &&
1123                 test_tick &&
1124                 git commit -m "O" &&
1125
1126                 git branch O &&
1127                 git branch A &&
1128                 git branch B &&
1129
1130                 git checkout A &&
1131                 git mv z y &&
1132                 echo d1 >y/d &&
1133                 git add y/d &&
1134                 test_tick &&
1135                 git commit -m "A" &&
1136
1137                 git checkout B &&
1138                 mkdir -p y/d &&
1139                 echo e >y/d/e &&
1140                 echo d2 >z/d &&
1141                 echo f >z/f &&
1142                 git add y/d/e z/d z/f &&
1143                 test_tick &&
1144                 git commit -m "B"
1145         )
1146 '
1147
1148 test_expect_failure '5d-check: Directory/file/file conflict due to directory rename' '
1149         (
1150                 cd 5d &&
1151
1152                 git checkout A^0 &&
1153
1154                 test_must_fail git merge -s recursive B^0 >out &&
1155                 test_i18ngrep "CONFLICT (file/directory).*y/d" out &&
1156
1157                 git ls-files -s >out &&
1158                 test_line_count = 6 out &&
1159                 git ls-files -u >out &&
1160                 test_line_count = 1 out &&
1161                 git ls-files -o >out &&
1162                 test_line_count = 2 out &&
1163
1164                 git rev-parse >actual \
1165                         :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d :0:y/d/e &&
1166                 git rev-parse >expect \
1167                          O:z/b  O:z/c  B:z/d  B:z/f  A:y/d  B:y/d/e &&
1168                 test_cmp expect actual &&
1169
1170                 git hash-object y/d~HEAD >actual &&
1171                 git rev-parse A:y/d >expect &&
1172                 test_cmp expect actual
1173         )
1174 '
1175
1176 ###########################################################################
1177 # Rules suggested by section 5:
1178 #
1179 #   If a subset of to-be-renamed files have a file or directory in the way,
1180 #   "turn off" the directory rename for those specific sub-paths, falling
1181 #   back to old handling.  But, sadly, see testcases 8a and 8b.
1182 ###########################################################################
1183
1184
1185 ###########################################################################
1186 # SECTION 6: Same side of the merge was the one that did the rename
1187 #
1188 # It may sound obvious that you only want to apply implicit directory
1189 # renames to directories if the _other_ side of history did the renaming.
1190 # If you did make an implementation that didn't explicitly enforce this
1191 # rule, the majority of cases that would fall under this section would
1192 # also be solved by following the rules from the above sections.  But
1193 # there are still a few that stick out, so this section covers them just
1194 # to make sure we also get them right.
1195 ###########################################################################
1196
1197 # Testcase 6a, Tricky rename/delete
1198 #   Commit O: z/{b,c,d}
1199 #   Commit A: z/b
1200 #   Commit B: y/{b,c}, z/d
1201 #   Expected: y/b, CONFLICT(rename/delete, z/c -> y/c vs. NULL)
1202 #   Note: We're just checking here that the rename of z/b and z/c to put
1203 #         them under y/ doesn't accidentally catch z/d and make it look like
1204 #         it is also involved in a rename/delete conflict.
1205
1206 test_expect_success '6a-setup: Tricky rename/delete' '
1207         test_create_repo 6a &&
1208         (
1209                 cd 6a &&
1210
1211                 mkdir z &&
1212                 echo b >z/b &&
1213                 echo c >z/c &&
1214                 echo d >z/d &&
1215                 git add z &&
1216                 test_tick &&
1217                 git commit -m "O" &&
1218
1219                 git branch O &&
1220                 git branch A &&
1221                 git branch B &&
1222
1223                 git checkout A &&
1224                 git rm z/c &&
1225                 git rm z/d &&
1226                 test_tick &&
1227                 git commit -m "A" &&
1228
1229                 git checkout B &&
1230                 mkdir y &&
1231                 git mv z/b y/ &&
1232                 git mv z/c y/ &&
1233                 test_tick &&
1234                 git commit -m "B"
1235         )
1236 '
1237
1238 test_expect_success '6a-check: Tricky rename/delete' '
1239         (
1240                 cd 6a &&
1241
1242                 git checkout A^0 &&
1243
1244                 test_must_fail git merge -s recursive B^0 >out &&
1245                 test_i18ngrep "CONFLICT (rename/delete).*z/c.*y/c" out &&
1246
1247                 git ls-files -s >out &&
1248                 test_line_count = 2 out &&
1249                 git ls-files -u >out &&
1250                 test_line_count = 1 out &&
1251                 git ls-files -o >out &&
1252                 test_line_count = 1 out &&
1253
1254                 git rev-parse >actual \
1255                         :0:y/b :3:y/c &&
1256                 git rev-parse >expect \
1257                          O:z/b  O:z/c &&
1258                 test_cmp expect actual
1259         )
1260 '
1261
1262 # Testcase 6b, Same rename done on both sides
1263 #   (Related to testcases 6c and 8e)
1264 #   Commit O: z/{b,c}
1265 #   Commit A: y/{b,c}
1266 #   Commit B: y/{b,c}, z/d
1267 #   Expected: y/{b,c}, z/d
1268 #   Note: If we did directory rename detection here, we'd move z/d into y/,
1269 #         but B did that rename and still decided to put the file into z/,
1270 #         so we probably shouldn't apply directory rename detection for it.
1271
1272 test_expect_success '6b-setup: Same rename done on both sides' '
1273         test_create_repo 6b &&
1274         (
1275                 cd 6b &&
1276
1277                 mkdir z &&
1278                 echo b >z/b &&
1279                 echo c >z/c &&
1280                 git add z &&
1281                 test_tick &&
1282                 git commit -m "O" &&
1283
1284                 git branch O &&
1285                 git branch A &&
1286                 git branch B &&
1287
1288                 git checkout A &&
1289                 git mv z y &&
1290                 test_tick &&
1291                 git commit -m "A" &&
1292
1293                 git checkout B &&
1294                 git mv z y &&
1295                 mkdir z &&
1296                 echo d >z/d &&
1297                 git add z/d &&
1298                 test_tick &&
1299                 git commit -m "B"
1300         )
1301 '
1302
1303 test_expect_success '6b-check: Same rename done on both sides' '
1304         (
1305                 cd 6b &&
1306
1307                 git checkout A^0 &&
1308
1309                 git merge -s recursive B^0 &&
1310
1311                 git ls-files -s >out &&
1312                 test_line_count = 3 out &&
1313                 git ls-files -u >out &&
1314                 test_line_count = 0 out &&
1315                 git ls-files -o >out &&
1316                 test_line_count = 1 out &&
1317
1318                 git rev-parse >actual \
1319                         HEAD:y/b HEAD:y/c HEAD:z/d &&
1320                 git rev-parse >expect \
1321                         O:z/b    O:z/c    B:z/d &&
1322                 test_cmp expect actual
1323         )
1324 '
1325
1326 # Testcase 6c, Rename only done on same side
1327 #   (Related to testcases 6b and 8e)
1328 #   Commit O: z/{b,c}
1329 #   Commit A: z/{b,c} (no change)
1330 #   Commit B: y/{b,c}, z/d
1331 #   Expected: y/{b,c}, z/d
1332 #   NOTE: Seems obvious, but just checking that the implementation doesn't
1333 #         "accidentally detect a rename" and give us y/{b,c,d}.
1334
1335 test_expect_success '6c-setup: Rename only done on same side' '
1336         test_create_repo 6c &&
1337         (
1338                 cd 6c &&
1339
1340                 mkdir z &&
1341                 echo b >z/b &&
1342                 echo c >z/c &&
1343                 git add z &&
1344                 test_tick &&
1345                 git commit -m "O" &&
1346
1347                 git branch O &&
1348                 git branch A &&
1349                 git branch B &&
1350
1351                 git checkout A &&
1352                 test_tick &&
1353                 git commit --allow-empty -m "A" &&
1354
1355                 git checkout B &&
1356                 git mv z y &&
1357                 mkdir z &&
1358                 echo d >z/d &&
1359                 git add z/d &&
1360                 test_tick &&
1361                 git commit -m "B"
1362         )
1363 '
1364
1365 test_expect_success '6c-check: Rename only done on same side' '
1366         (
1367                 cd 6c &&
1368
1369                 git checkout A^0 &&
1370
1371                 git merge -s recursive B^0 &&
1372
1373                 git ls-files -s >out &&
1374                 test_line_count = 3 out &&
1375                 git ls-files -u >out &&
1376                 test_line_count = 0 out &&
1377                 git ls-files -o >out &&
1378                 test_line_count = 1 out &&
1379
1380                 git rev-parse >actual \
1381                         HEAD:y/b HEAD:y/c HEAD:z/d &&
1382                 git rev-parse >expect \
1383                         O:z/b    O:z/c    B:z/d &&
1384                 test_cmp expect actual
1385         )
1386 '
1387
1388 # Testcase 6d, We don't always want transitive renaming
1389 #   (Related to testcase 1c)
1390 #   Commit O: z/{b,c}, x/d
1391 #   Commit A: z/{b,c}, x/d (no change)
1392 #   Commit B: y/{b,c}, z/d
1393 #   Expected: y/{b,c}, z/d
1394 #   NOTE: Again, this seems obvious but just checking that the implementation
1395 #         doesn't "accidentally detect a rename" and give us y/{b,c,d}.
1396
1397 test_expect_success '6d-setup: We do not always want transitive renaming' '
1398         test_create_repo 6d &&
1399         (
1400                 cd 6d &&
1401
1402                 mkdir z &&
1403                 echo b >z/b &&
1404                 echo c >z/c &&
1405                 mkdir x &&
1406                 echo d >x/d &&
1407                 git add z x &&
1408                 test_tick &&
1409                 git commit -m "O" &&
1410
1411                 git branch O &&
1412                 git branch A &&
1413                 git branch B &&
1414
1415                 git checkout A &&
1416                 test_tick &&
1417                 git commit --allow-empty -m "A" &&
1418
1419                 git checkout B &&
1420                 git mv z y &&
1421                 git mv x z &&
1422                 test_tick &&
1423                 git commit -m "B"
1424         )
1425 '
1426
1427 test_expect_success '6d-check: We do not always want transitive renaming' '
1428         (
1429                 cd 6d &&
1430
1431                 git checkout A^0 &&
1432
1433                 git merge -s recursive B^0 &&
1434
1435                 git ls-files -s >out &&
1436                 test_line_count = 3 out &&
1437                 git ls-files -u >out &&
1438                 test_line_count = 0 out &&
1439                 git ls-files -o >out &&
1440                 test_line_count = 1 out &&
1441
1442                 git rev-parse >actual \
1443                         HEAD:y/b HEAD:y/c HEAD:z/d &&
1444                 git rev-parse >expect \
1445                         O:z/b    O:z/c    O:x/d &&
1446                 test_cmp expect actual
1447         )
1448 '
1449
1450 # Testcase 6e, Add/add from one-side
1451 #   Commit O: z/{b,c}
1452 #   Commit A: z/{b,c} (no change)
1453 #   Commit B: y/{b,c,d_1}, z/d_2
1454 #   Expected: y/{b,c,d_1}, z/d_2
1455 #   NOTE: Again, this seems obvious but just checking that the implementation
1456 #         doesn't "accidentally detect a rename" and give us y/{b,c} +
1457 #         add/add conflict on y/d_1 vs y/d_2.
1458
1459 test_expect_success '6e-setup: Add/add from one side' '
1460         test_create_repo 6e &&
1461         (
1462                 cd 6e &&
1463
1464                 mkdir z &&
1465                 echo b >z/b &&
1466                 echo c >z/c &&
1467                 git add z &&
1468                 test_tick &&
1469                 git commit -m "O" &&
1470
1471                 git branch O &&
1472                 git branch A &&
1473                 git branch B &&
1474
1475                 git checkout A &&
1476                 test_tick &&
1477                 git commit --allow-empty -m "A" &&
1478
1479                 git checkout B &&
1480                 git mv z y &&
1481                 echo d1 > y/d &&
1482                 mkdir z &&
1483                 echo d2 > z/d &&
1484                 git add y/d z/d &&
1485                 test_tick &&
1486                 git commit -m "B"
1487         )
1488 '
1489
1490 test_expect_success '6e-check: Add/add from one side' '
1491         (
1492                 cd 6e &&
1493
1494                 git checkout A^0 &&
1495
1496                 git merge -s recursive B^0 &&
1497
1498                 git ls-files -s >out &&
1499                 test_line_count = 4 out &&
1500                 git ls-files -u >out &&
1501                 test_line_count = 0 out &&
1502                 git ls-files -o >out &&
1503                 test_line_count = 1 out &&
1504
1505                 git rev-parse >actual \
1506                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/d &&
1507                 git rev-parse >expect \
1508                         O:z/b    O:z/c    B:y/d    B:z/d &&
1509                 test_cmp expect actual
1510         )
1511 '
1512
1513 ###########################################################################
1514 # Rules suggested by section 6:
1515 #
1516 #   Only apply implicit directory renames to directories if the other
1517 #   side of history is the one doing the renaming.
1518 ###########################################################################
1519
1520
1521 ###########################################################################
1522 # SECTION 7: More involved Edge/Corner cases
1523 #
1524 # The ruleset we have generated in the above sections seems to provide
1525 # well-defined merges.  But can we find edge/corner cases that either (a)
1526 # are harder for users to understand, or (b) have a resolution that is
1527 # non-intuitive or suboptimal?
1528 #
1529 # The testcases in this section dive into cases that I've tried to craft in
1530 # a way to find some that might be surprising to users or difficult for
1531 # them to understand (the next section will look at non-intuitive or
1532 # suboptimal merge results).  Some of the testcases are similar to ones
1533 # from past sections, but have been simplified to try to highlight error
1534 # messages using a "modified" path (due to the directory rename).  Are
1535 # users okay with these?
1536 #
1537 # In my opinion, testcases that are difficult to understand from this
1538 # section is due to difficulty in the testcase rather than the directory
1539 # renaming (similar to how t6042 and t6036 have difficult resolutions due
1540 # to the problem setup itself being complex).  And I don't think the
1541 # error messages are a problem.
1542 #
1543 # On the other hand, the testcases in section 8 worry me slightly more...
1544 ###########################################################################
1545
1546 # Testcase 7a, rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file
1547 #   Commit O: z/{b,c}
1548 #   Commit A: y/{b,c}
1549 #   Commit B: w/b, x/c, z/d
1550 #   Expected: y/d, CONFLICT(rename/rename for both z/b and z/c)
1551 #   NOTE: There's a rename of z/ here, y/ has more renames, so z/d -> y/d.
1552
1553 test_expect_success '7a-setup: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file' '
1554         test_create_repo 7a &&
1555         (
1556                 cd 7a &&
1557
1558                 mkdir z &&
1559                 echo b >z/b &&
1560                 echo c >z/c &&
1561                 git add z &&
1562                 test_tick &&
1563                 git commit -m "O" &&
1564
1565                 git branch O &&
1566                 git branch A &&
1567                 git branch B &&
1568
1569                 git checkout A &&
1570                 git mv z y &&
1571                 test_tick &&
1572                 git commit -m "A" &&
1573
1574                 git checkout B &&
1575                 mkdir w &&
1576                 mkdir x &&
1577                 git mv z/b w/ &&
1578                 git mv z/c x/ &&
1579                 echo d > z/d &&
1580                 git add z/d &&
1581                 test_tick &&
1582                 git commit -m "B"
1583         )
1584 '
1585
1586 test_expect_failure '7a-check: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file' '
1587         (
1588                 cd 7a &&
1589
1590                 git checkout A^0 &&
1591
1592                 test_must_fail git merge -s recursive B^0 >out &&
1593                 test_i18ngrep "CONFLICT (rename/rename).*z/b.*y/b.*w/b" out &&
1594                 test_i18ngrep "CONFLICT (rename/rename).*z/c.*y/c.*x/c" out &&
1595
1596                 git ls-files -s >out &&
1597                 test_line_count = 7 out &&
1598                 git ls-files -u >out &&
1599                 test_line_count = 6 out &&
1600                 git ls-files -o >out &&
1601                 test_line_count = 1 out &&
1602
1603                 git rev-parse >actual \
1604                         :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:x/c :0:y/d &&
1605                 git rev-parse >expect \
1606                          O:z/b  O:z/b  O:z/b  O:z/c  O:z/c  O:z/c  B:z/d &&
1607                 test_cmp expect actual &&
1608
1609                 git hash-object >actual \
1610                         y/b   w/b   y/c   x/c &&
1611                 git rev-parse >expect \
1612                         O:z/b O:z/b O:z/c O:z/c &&
1613                 test_cmp expect actual
1614         )
1615 '
1616
1617 # Testcase 7b, rename/rename(2to1), but only due to transitive rename
1618 #   (Related to testcase 1d)
1619 #   Commit O: z/{b,c},     x/d_1, w/d_2
1620 #   Commit A: y/{b,c,d_2}, x/d_1
1621 #   Commit B: z/{b,c,d_1},        w/d_2
1622 #   Expected: y/{b,c}, CONFLICT(rename/rename(2to1): x/d_1, w/d_2 -> y_d)
1623
1624 test_expect_success '7b-setup: rename/rename(2to1), but only due to transitive rename' '
1625         test_create_repo 7b &&
1626         (
1627                 cd 7b &&
1628
1629                 mkdir z &&
1630                 mkdir x &&
1631                 mkdir w &&
1632                 echo b >z/b &&
1633                 echo c >z/c &&
1634                 echo d1 > x/d &&
1635                 echo d2 > w/d &&
1636                 git add z x w &&
1637                 test_tick &&
1638                 git commit -m "O" &&
1639
1640                 git branch O &&
1641                 git branch A &&
1642                 git branch B &&
1643
1644                 git checkout A &&
1645                 git mv z y &&
1646                 git mv w/d y/ &&
1647                 test_tick &&
1648                 git commit -m "A" &&
1649
1650                 git checkout B &&
1651                 git mv x/d z/ &&
1652                 rmdir x &&
1653                 test_tick &&
1654                 git commit -m "B"
1655         )
1656 '
1657
1658 test_expect_failure '7b-check: rename/rename(2to1), but only due to transitive rename' '
1659         (
1660                 cd 7b &&
1661
1662                 git checkout A^0 &&
1663
1664                 test_must_fail git merge -s recursive B^0 >out &&
1665                 test_i18ngrep "CONFLICT (rename/rename)" out &&
1666
1667                 git ls-files -s >out &&
1668                 test_line_count = 4 out &&
1669                 git ls-files -u >out &&
1670                 test_line_count = 2 out &&
1671                 git ls-files -o >out &&
1672                 test_line_count = 3 out &&
1673
1674                 git rev-parse >actual \
1675                         :0:y/b :0:y/c :2:y/d :3:y/d &&
1676                 git rev-parse >expect \
1677                          O:z/b  O:z/c  O:w/d  O:x/d &&
1678                 test_cmp expect actual &&
1679
1680                 test_path_is_missing y/d &&
1681                 test_path_is_file y/d~HEAD &&
1682                 test_path_is_file y/d~B^0 &&
1683
1684                 git hash-object >actual \
1685                         y/d~HEAD y/d~B^0 &&
1686                 git rev-parse >expect \
1687                         O:w/d    O:x/d &&
1688                 test_cmp expect actual
1689         )
1690 '
1691
1692 # Testcase 7c, rename/rename(1to...2or3); transitive rename may add complexity
1693 #   (Related to testcases 3b and 5c)
1694 #   Commit O: z/{b,c}, x/d
1695 #   Commit A: y/{b,c}, w/d
1696 #   Commit B: z/{b,c,d}
1697 #   Expected: y/{b,c}, CONFLICT(x/d -> w/d vs. y/d)
1698 #   NOTE: z/ was renamed to y/ so we do want to report
1699 #         neither CONFLICT(x/d -> w/d vs. z/d)
1700 #         nor CONFLiCT x/d -> w/d vs. y/d vs. z/d)
1701
1702 test_expect_success '7c-setup: rename/rename(1to...2or3); transitive rename may add complexity' '
1703         test_create_repo 7c &&
1704         (
1705                 cd 7c &&
1706
1707                 mkdir z &&
1708                 echo b >z/b &&
1709                 echo c >z/c &&
1710                 mkdir x &&
1711                 echo d >x/d &&
1712                 git add z x &&
1713                 test_tick &&
1714                 git commit -m "O" &&
1715
1716                 git branch O &&
1717                 git branch A &&
1718                 git branch B &&
1719
1720                 git checkout A &&
1721                 git mv z y &&
1722                 git mv x w &&
1723                 test_tick &&
1724                 git commit -m "A" &&
1725
1726                 git checkout B &&
1727                 git mv x/d z/ &&
1728                 rmdir x &&
1729                 test_tick &&
1730                 git commit -m "B"
1731         )
1732 '
1733
1734 test_expect_failure '7c-check: rename/rename(1to...2or3); transitive rename may add complexity' '
1735         (
1736                 cd 7c &&
1737
1738                 git checkout A^0 &&
1739
1740                 test_must_fail git merge -s recursive B^0 >out &&
1741                 test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*y/d" out &&
1742
1743                 git ls-files -s >out &&
1744                 test_line_count = 5 out &&
1745                 git ls-files -u >out &&
1746                 test_line_count = 3 out &&
1747                 git ls-files -o >out &&
1748                 test_line_count = 1 out &&
1749
1750                 git rev-parse >actual \
1751                         :0:y/b :0:y/c :1:x/d :2:w/d :3:y/d &&
1752                 git rev-parse >expect \
1753                          O:z/b  O:z/c  O:x/d  O:x/d  O:x/d &&
1754                 test_cmp expect actual
1755         )
1756 '
1757
1758 # Testcase 7d, transitive rename involved in rename/delete; how is it reported?
1759 #   (Related somewhat to testcases 5b and 8d)
1760 #   Commit O: z/{b,c}, x/d
1761 #   Commit A: y/{b,c}
1762 #   Commit B: z/{b,c,d}
1763 #   Expected: y/{b,c}, CONFLICT(delete x/d vs rename to y/d)
1764 #   NOTE: z->y so NOT CONFLICT(delete x/d vs rename to z/d)
1765
1766 test_expect_success '7d-setup: transitive rename involved in rename/delete; how is it reported?' '
1767         test_create_repo 7d &&
1768         (
1769                 cd 7d &&
1770
1771                 mkdir z &&
1772                 echo b >z/b &&
1773                 echo c >z/c &&
1774                 mkdir x &&
1775                 echo d >x/d &&
1776                 git add z x &&
1777                 test_tick &&
1778                 git commit -m "O" &&
1779
1780                 git branch O &&
1781                 git branch A &&
1782                 git branch B &&
1783
1784                 git checkout A &&
1785                 git mv z y &&
1786                 git rm -rf x &&
1787                 test_tick &&
1788                 git commit -m "A" &&
1789
1790                 git checkout B &&
1791                 git mv x/d z/ &&
1792                 rmdir x &&
1793                 test_tick &&
1794                 git commit -m "B"
1795         )
1796 '
1797
1798 test_expect_failure '7d-check: transitive rename involved in rename/delete; how is it reported?' '
1799         (
1800                 cd 7d &&
1801
1802                 git checkout A^0 &&
1803
1804                 test_must_fail git merge -s recursive B^0 >out &&
1805                 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1806
1807                 git ls-files -s >out &&
1808                 test_line_count = 3 out &&
1809                 git ls-files -u >out &&
1810                 test_line_count = 1 out &&
1811                 git ls-files -o >out &&
1812                 test_line_count = 1 out &&
1813
1814                 git rev-parse >actual \
1815                         :0:y/b :0:y/c :3:y/d &&
1816                 git rev-parse >expect \
1817                          O:z/b  O:z/c  O:x/d &&
1818                 test_cmp expect actual
1819         )
1820 '
1821
1822 # Testcase 7e, transitive rename in rename/delete AND dirs in the way
1823 #   (Very similar to 'both rename source and destination involved in D/F conflict' from t6022-merge-rename.sh)
1824 #   (Also related to testcases 9c and 9d)
1825 #   Commit O: z/{b,c},     x/d_1
1826 #   Commit A: y/{b,c,d/g}, x/d/f
1827 #   Commit B: z/{b,c,d_1}
1828 #   Expected: rename/delete(x/d_1->y/d_1 vs. None) + D/F conflict on y/d
1829 #             y/{b,c,d/g}, y/d_1~B^0, x/d/f
1830
1831 #   NOTE: The main path of interest here is d_1 and where it ends up, but
1832 #         this is actually a case that has two potential directory renames
1833 #         involved and D/F conflict(s), so it makes sense to walk through
1834 #         each step.
1835 #
1836 #         Commit A renames z/ -> y/.  Thus everything that B adds to z/
1837 #         should be instead moved to y/.  This gives us the D/F conflict on
1838 #         y/d because x/d_1 -> z/d_1 -> y/d_1 conflicts with y/d/g.
1839 #
1840 #         Further, commit B renames x/ -> z/, thus everything A adds to x/
1841 #         should instead be moved to z/...BUT we removed z/ and renamed it
1842 #         to y/, so maybe everything should move not from x/ to z/, but
1843 #         from x/ to z/ to y/.  Doing so might make sense from the logic so
1844 #         far, but note that commit A had both an x/ and a y/; it did the
1845 #         renaming of z/ to y/ and created x/d/f and it clearly made these
1846 #         things separate, so it doesn't make much sense to push these
1847 #         together.  Doing so is what I'd call a doubly transitive rename;
1848 #         see testcases 9c and 9d for further discussion of this issue and
1849 #         how it's resolved.
1850
1851 test_expect_success '7e-setup: transitive rename in rename/delete AND dirs in the way' '
1852         test_create_repo 7e &&
1853         (
1854                 cd 7e &&
1855
1856                 mkdir z &&
1857                 echo b >z/b &&
1858                 echo c >z/c &&
1859                 mkdir x &&
1860                 echo d1 >x/d &&
1861                 git add z x &&
1862                 test_tick &&
1863                 git commit -m "O" &&
1864
1865                 git branch O &&
1866                 git branch A &&
1867                 git branch B &&
1868
1869                 git checkout A &&
1870                 git mv z y &&
1871                 git rm x/d &&
1872                 mkdir -p x/d &&
1873                 mkdir -p y/d &&
1874                 echo f >x/d/f &&
1875                 echo g >y/d/g &&
1876                 git add x/d/f y/d/g &&
1877                 test_tick &&
1878                 git commit -m "A" &&
1879
1880                 git checkout B &&
1881                 git mv x/d z/ &&
1882                 rmdir x &&
1883                 test_tick &&
1884                 git commit -m "B"
1885         )
1886 '
1887
1888 test_expect_failure '7e-check: transitive rename in rename/delete AND dirs in the way' '
1889         (
1890                 cd 7e &&
1891
1892                 git checkout A^0 &&
1893
1894                 test_must_fail git merge -s recursive B^0 >out &&
1895                 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1896
1897                 git ls-files -s >out &&
1898                 test_line_count = 5 out &&
1899                 git ls-files -u >out &&
1900                 test_line_count = 1 out &&
1901                 git ls-files -o >out &&
1902                 test_line_count = 2 out &&
1903
1904                 git rev-parse >actual \
1905                         :0:x/d/f :0:y/d/g :0:y/b :0:y/c :3:y/d &&
1906                 git rev-parse >expect \
1907                          A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d &&
1908                 test_cmp expect actual &&
1909
1910                 git hash-object y/d~B^0 >actual &&
1911                 git rev-parse O:x/d >expect &&
1912                 test_cmp expect actual
1913         )
1914 '
1915
1916 ###########################################################################
1917 # SECTION 8: Suboptimal merges
1918 #
1919 # As alluded to in the last section, the ruleset we have built up for
1920 # detecting directory renames unfortunately has some special cases where it
1921 # results in slightly suboptimal or non-intuitive behavior.  This section
1922 # explores these cases.
1923 #
1924 # To be fair, we already had non-intuitive or suboptimal behavior for most
1925 # of these cases in git before introducing implicit directory rename
1926 # detection, but it'd be nice if there was a modified ruleset out there
1927 # that handled these cases a bit better.
1928 ###########################################################################
1929
1930 # Testcase 8a, Dual-directory rename, one into the others' way
1931 #   Commit O. x/{a,b},   y/{c,d}
1932 #   Commit A. x/{a,b,e}, y/{c,d,f}
1933 #   Commit B. y/{a,b},   z/{c,d}
1934 #
1935 # Possible Resolutions:
1936 #   w/o dir-rename detection: y/{a,b,f},   z/{c,d},   x/e
1937 #   Currently expected:       y/{a,b,e,f}, z/{c,d}
1938 #   Optimal:                  y/{a,b,e},   z/{c,d,f}
1939 #
1940 # Note: Both x and y got renamed and it'd be nice to detect both, and we do
1941 # better with directory rename detection than git did without, but the
1942 # simple rule from section 5 prevents me from handling this as optimally as
1943 # we potentially could.
1944
1945 test_expect_success '8a-setup: Dual-directory rename, one into the others way' '
1946         test_create_repo 8a &&
1947         (
1948                 cd 8a &&
1949
1950                 mkdir x &&
1951                 mkdir y &&
1952                 echo a >x/a &&
1953                 echo b >x/b &&
1954                 echo c >y/c &&
1955                 echo d >y/d &&
1956                 git add x y &&
1957                 test_tick &&
1958                 git commit -m "O" &&
1959
1960                 git branch O &&
1961                 git branch A &&
1962                 git branch B &&
1963
1964                 git checkout A &&
1965                 echo e >x/e &&
1966                 echo f >y/f &&
1967                 git add x/e y/f &&
1968                 test_tick &&
1969                 git commit -m "A" &&
1970
1971                 git checkout B &&
1972                 git mv y z &&
1973                 git mv x y &&
1974                 test_tick &&
1975                 git commit -m "B"
1976         )
1977 '
1978
1979 test_expect_failure '8a-check: Dual-directory rename, one into the others way' '
1980         (
1981                 cd 8a &&
1982
1983                 git checkout A^0 &&
1984
1985                 git merge -s recursive B^0 &&
1986
1987                 git ls-files -s >out &&
1988                 test_line_count = 6 out &&
1989                 git ls-files -u >out &&
1990                 test_line_count = 0 out &&
1991                 git ls-files -o >out &&
1992                 test_line_count = 1 out &&
1993
1994                 git rev-parse >actual \
1995                         HEAD:y/a HEAD:y/b HEAD:y/e HEAD:y/f HEAD:z/c HEAD:z/d &&
1996                 git rev-parse >expect \
1997                         O:x/a    O:x/b    A:x/e    A:y/f    O:y/c    O:y/d &&
1998                 test_cmp expect actual
1999         )
2000 '
2001
2002 # Testcase 8b, Dual-directory rename, one into the others' way, with conflicting filenames
2003 #   Commit O. x/{a_1,b_1},     y/{a_2,b_2}
2004 #   Commit A. x/{a_1,b_1,e_1}, y/{a_2,b_2,e_2}
2005 #   Commit B. y/{a_1,b_1},     z/{a_2,b_2}
2006 #
2007 #   w/o dir-rename detection: y/{a_1,b_1,e_2}, z/{a_2,b_2}, x/e_1
2008 #   Currently expected:       <same>
2009 #   Scary:                    y/{a_1,b_1},     z/{a_2,b_2}, CONFLICT(add/add, e_1 vs. e_2)
2010 #   Optimal:                  y/{a_1,b_1,e_1}, z/{a_2,b_2,e_2}
2011 #
2012 # Note: Very similar to 8a, except instead of 'e' and 'f' in directories x and
2013 # y, both are named 'e'.  Without directory rename detection, neither file
2014 # moves directories.  Implement directory rename detection suboptimally, and
2015 # you get an add/add conflict, but both files were added in commit A, so this
2016 # is an add/add conflict where one side of history added both files --
2017 # something we can't represent in the index.  Obviously, we'd prefer the last
2018 # resolution, but our previous rules are too coarse to allow it.  Using both
2019 # the rules from section 4 and section 5 save us from the Scary resolution,
2020 # making us fall back to pre-directory-rename-detection behavior for both
2021 # e_1 and e_2.
2022
2023 test_expect_success '8b-setup: Dual-directory rename, one into the others way, with conflicting filenames' '
2024         test_create_repo 8b &&
2025         (
2026                 cd 8b &&
2027
2028                 mkdir x &&
2029                 mkdir y &&
2030                 echo a1 >x/a &&
2031                 echo b1 >x/b &&
2032                 echo a2 >y/a &&
2033                 echo b2 >y/b &&
2034                 git add x y &&
2035                 test_tick &&
2036                 git commit -m "O" &&
2037
2038                 git branch O &&
2039                 git branch A &&
2040                 git branch B &&
2041
2042                 git checkout A &&
2043                 echo e1 >x/e &&
2044                 echo e2 >y/e &&
2045                 git add x/e y/e &&
2046                 test_tick &&
2047                 git commit -m "A" &&
2048
2049                 git checkout B &&
2050                 git mv y z &&
2051                 git mv x y &&
2052                 test_tick &&
2053                 git commit -m "B"
2054         )
2055 '
2056
2057 test_expect_success '8b-check: Dual-directory rename, one into the others way, with conflicting filenames' '
2058         (
2059                 cd 8b &&
2060
2061                 git checkout A^0 &&
2062
2063                 git merge -s recursive B^0 &&
2064
2065                 git ls-files -s >out &&
2066                 test_line_count = 6 out &&
2067                 git ls-files -u >out &&
2068                 test_line_count = 0 out &&
2069                 git ls-files -o >out &&
2070                 test_line_count = 1 out &&
2071
2072                 git rev-parse >actual \
2073                         HEAD:y/a HEAD:y/b HEAD:z/a HEAD:z/b HEAD:x/e HEAD:y/e &&
2074                 git rev-parse >expect \
2075                         O:x/a    O:x/b    O:y/a    O:y/b    A:x/e    A:y/e &&
2076                 test_cmp expect actual
2077         )
2078 '
2079
2080 # Testcase 8c, rename+modify/delete
2081 #   (Related to testcases 5b and 8d)
2082 #   Commit O: z/{b,c,d}
2083 #   Commit A: y/{b,c}
2084 #   Commit B: z/{b,c,d_modified,e}
2085 #   Expected: y/{b,c,e}, CONFLICT(rename+modify/delete: x/d -> y/d or deleted)
2086 #
2087 #   Note: This testcase doesn't present any concerns for me...until you
2088 #         compare it with testcases 5b and 8d.  See notes in 8d for more
2089 #         details.
2090
2091 test_expect_success '8c-setup: rename+modify/delete' '
2092         test_create_repo 8c &&
2093         (
2094                 cd 8c &&
2095
2096                 mkdir z &&
2097                 echo b >z/b &&
2098                 echo c >z/c &&
2099                 test_seq 1 10 >z/d &&
2100                 git add z &&
2101                 test_tick &&
2102                 git commit -m "O" &&
2103
2104                 git branch O &&
2105                 git branch A &&
2106                 git branch B &&
2107
2108                 git checkout A &&
2109                 git rm z/d &&
2110                 git mv z y &&
2111                 test_tick &&
2112                 git commit -m "A" &&
2113
2114                 git checkout B &&
2115                 echo 11 >z/d &&
2116                 test_chmod +x z/d &&
2117                 echo e >z/e &&
2118                 git add z/d z/e &&
2119                 test_tick &&
2120                 git commit -m "B"
2121         )
2122 '
2123
2124 test_expect_failure '8c-check: rename+modify/delete' '
2125         (
2126                 cd 8c &&
2127
2128                 git checkout A^0 &&
2129
2130                 test_must_fail git merge -s recursive B^0 >out &&
2131                 test_i18ngrep "CONFLICT (rename/delete).* z/d.*y/d" out &&
2132
2133                 git ls-files -s >out &&
2134                 test_line_count = 4 out &&
2135                 git ls-files -u >out &&
2136                 test_line_count = 1 out &&
2137                 git ls-files -o >out &&
2138                 test_line_count = 1 out &&
2139
2140                 git rev-parse >actual \
2141                         :0:y/b :0:y/c :0:y/e :3:y/d &&
2142                 git rev-parse >expect \
2143                          O:z/b  O:z/c  B:z/e  B:z/d &&
2144                 test_cmp expect actual &&
2145
2146                 test_must_fail git rev-parse :1:y/d &&
2147                 test_must_fail git rev-parse :2:y/d &&
2148                 git ls-files -s y/d | grep ^100755 &&
2149                 test_path_is_file y/d
2150         )
2151 '
2152
2153 # Testcase 8d, rename/delete...or not?
2154 #   (Related to testcase 5b; these may appear slightly inconsistent to users;
2155 #    Also related to testcases 7d and 7e)
2156 #   Commit O: z/{b,c,d}
2157 #   Commit A: y/{b,c}
2158 #   Commit B: z/{b,c,d,e}
2159 #   Expected: y/{b,c,e}
2160 #
2161 #   Note: It would also be somewhat reasonable to resolve this as
2162 #             y/{b,c,e}, CONFLICT(rename/delete: x/d -> y/d or deleted)
2163 #   The logic being that the only difference between this testcase and 8c
2164 #   is that there is no modification to d.  That suggests that instead of a
2165 #   rename/modify vs. delete conflict, we should just have a rename/delete
2166 #   conflict, otherwise we are being inconsistent.
2167 #
2168 #   However...as far as consistency goes, we didn't report a conflict for
2169 #   path d_1 in testcase 5b due to a different file being in the way.  So,
2170 #   we seem to be forced to have cases where users can change things
2171 #   slightly and get what they may perceive as inconsistent results.  It
2172 #   would be nice to avoid that, but I'm not sure I see how.
2173 #
2174 #   In this case, I'm leaning towards: commit A was the one that deleted z/d
2175 #   and it did the rename of z to y, so the two "conflicts" (rename vs.
2176 #   delete) are both coming from commit A, which is illogical.  Conflicts
2177 #   during merging are supposed to be about opposite sides doing things
2178 #   differently.
2179
2180 test_expect_success '8d-setup: rename/delete...or not?' '
2181         test_create_repo 8d &&
2182         (
2183                 cd 8d &&
2184
2185                 mkdir z &&
2186                 echo b >z/b &&
2187                 echo c >z/c &&
2188                 test_seq 1 10 >z/d &&
2189                 git add z &&
2190                 test_tick &&
2191                 git commit -m "O" &&
2192
2193                 git branch O &&
2194                 git branch A &&
2195                 git branch B &&
2196
2197                 git checkout A &&
2198                 git rm z/d &&
2199                 git mv z y &&
2200                 test_tick &&
2201                 git commit -m "A" &&
2202
2203                 git checkout B &&
2204                 echo e >z/e &&
2205                 git add z/e &&
2206                 test_tick &&
2207                 git commit -m "B"
2208         )
2209 '
2210
2211 test_expect_failure '8d-check: rename/delete...or not?' '
2212         (
2213                 cd 8d &&
2214
2215                 git checkout A^0 &&
2216
2217                 git merge -s recursive B^0 &&
2218
2219                 git ls-files -s >out &&
2220                 test_line_count = 3 out &&
2221
2222                 git rev-parse >actual \
2223                         HEAD:y/b HEAD:y/c HEAD:y/e &&
2224                 git rev-parse >expect \
2225                         O:z/b    O:z/c    B:z/e &&
2226                 test_cmp expect actual
2227         )
2228 '
2229
2230 # Testcase 8e, Both sides rename, one side adds to original directory
2231 #   Commit O: z/{b,c}
2232 #   Commit A: y/{b,c}
2233 #   Commit B: w/{b,c}, z/d
2234 #
2235 # Possible Resolutions:
2236 #   w/o dir-rename detection: z/d, CONFLICT(z/b -> y/b vs. w/b),
2237 #                                  CONFLICT(z/c -> y/c vs. w/c)
2238 #   Currently expected:       y/d, CONFLICT(z/b -> y/b vs. w/b),
2239 #                                  CONFLICT(z/c -> y/c vs. w/c)
2240 #   Optimal:                  ??
2241 #
2242 # Notes: In commit A, directory z got renamed to y.  In commit B, directory z
2243 #        did NOT get renamed; the directory is still present; instead it is
2244 #        considered to have just renamed a subset of paths in directory z
2245 #        elsewhere.  Therefore, the directory rename done in commit A to z/
2246 #        applies to z/d and maps it to y/d.
2247 #
2248 #        It's possible that users would get confused about this, but what
2249 #        should we do instead?  Silently leaving at z/d seems just as bad or
2250 #        maybe even worse.  Perhaps we could print a big warning about z/d
2251 #        and how we're moving to y/d in this case, but when I started thinking
2252 #        about the ramifications of doing that, I didn't know how to rule out
2253 #        that opening other weird edge and corner cases so I just punted.
2254
2255 test_expect_success '8e-setup: Both sides rename, one side adds to original directory' '
2256         test_create_repo 8e &&
2257         (
2258                 cd 8e &&
2259
2260                 mkdir z &&
2261                 echo b >z/b &&
2262                 echo c >z/c &&
2263                 git add z &&
2264                 test_tick &&
2265                 git commit -m "O" &&
2266
2267                 git branch O &&
2268                 git branch A &&
2269                 git branch B &&
2270
2271                 git checkout A &&
2272                 git mv z y &&
2273                 test_tick &&
2274                 git commit -m "A" &&
2275
2276                 git checkout B &&
2277                 git mv z w &&
2278                 mkdir z &&
2279                 echo d >z/d &&
2280                 git add z/d &&
2281                 test_tick &&
2282                 git commit -m "B"
2283         )
2284 '
2285
2286 test_expect_failure '8e-check: Both sides rename, one side adds to original directory' '
2287         (
2288                 cd 8e &&
2289
2290                 git checkout A^0 &&
2291
2292                 test_must_fail git merge -s recursive B^0 >out 2>err &&
2293                 test_i18ngrep CONFLICT.*rename/rename.*z/c.*y/c.*w/c out &&
2294                 test_i18ngrep CONFLICT.*rename/rename.*z/b.*y/b.*w/b out &&
2295
2296                 git ls-files -s >out &&
2297                 test_line_count = 7 out &&
2298                 git ls-files -u >out &&
2299                 test_line_count = 6 out &&
2300                 git ls-files -o >out &&
2301                 test_line_count = 2 out &&
2302
2303                 git rev-parse >actual \
2304                         :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:w/c :0:y/d &&
2305                 git rev-parse >expect \
2306                          O:z/b  O:z/b  O:z/b  O:z/c  O:z/c  O:z/c  B:z/d &&
2307                 test_cmp expect actual &&
2308
2309                 git hash-object >actual \
2310                         y/b   w/b   y/c   w/c &&
2311                 git rev-parse >expect \
2312                         O:z/b O:z/b O:z/c O:z/c &&
2313                 test_cmp expect actual &&
2314
2315                 test_path_is_missing z/b &&
2316                 test_path_is_missing z/c
2317         )
2318 '
2319
2320 ###########################################################################
2321 # SECTION 9: Other testcases
2322 #
2323 # This section consists of miscellaneous testcases I thought of during
2324 # the implementation which round out the testing.
2325 ###########################################################################
2326
2327 # Testcase 9a, Inner renamed directory within outer renamed directory
2328 #   (Related to testcase 1f)
2329 #   Commit O: z/{b,c,d/{e,f,g}}
2330 #   Commit A: y/{b,c}, x/w/{e,f,g}
2331 #   Commit B: z/{b,c,d/{e,f,g,h},i}
2332 #   Expected: y/{b,c,i}, x/w/{e,f,g,h}
2333 #   NOTE: The only reason this one is interesting is because when a directory
2334 #         is split into multiple other directories, we determine by the weight
2335 #         of which one had the most paths going to it.  A naive implementation
2336 #         of that could take the new file in commit B at z/i to x/w/i or x/i.
2337
2338 test_expect_success '9a-setup: Inner renamed directory within outer renamed directory' '
2339         test_create_repo 9a &&
2340         (
2341                 cd 9a &&
2342
2343                 mkdir -p z/d &&
2344                 echo b >z/b &&
2345                 echo c >z/c &&
2346                 echo e >z/d/e &&
2347                 echo f >z/d/f &&
2348                 echo g >z/d/g &&
2349                 git add z &&
2350                 test_tick &&
2351                 git commit -m "O" &&
2352
2353                 git branch O &&
2354                 git branch A &&
2355                 git branch B &&
2356
2357                 git checkout A &&
2358                 mkdir x &&
2359                 git mv z/d x/w &&
2360                 git mv z y &&
2361                 test_tick &&
2362                 git commit -m "A" &&
2363
2364                 git checkout B &&
2365                 echo h >z/d/h &&
2366                 echo i >z/i &&
2367                 git add z &&
2368                 test_tick &&
2369                 git commit -m "B"
2370         )
2371 '
2372
2373 test_expect_failure '9a-check: Inner renamed directory within outer renamed directory' '
2374         (
2375                 cd 9a &&
2376
2377                 git checkout A^0 &&
2378
2379                 git merge -s recursive B^0 &&
2380
2381                 git ls-files -s >out &&
2382                 test_line_count = 7 out &&
2383                 git ls-files -u >out &&
2384                 test_line_count = 0 out &&
2385                 git ls-files -o >out &&
2386                 test_line_count = 1 out &&
2387
2388                 git rev-parse >actual \
2389                         HEAD:y/b HEAD:y/c HEAD:y/i &&
2390                 git rev-parse >expect \
2391                         O:z/b    O:z/c    B:z/i &&
2392                 test_cmp expect actual &&
2393
2394                 git rev-parse >actual \
2395                         HEAD:x/w/e HEAD:x/w/f HEAD:x/w/g HEAD:x/w/h &&
2396                 git rev-parse >expect \
2397                         O:z/d/e    O:z/d/f    O:z/d/g    B:z/d/h &&
2398                 test_cmp expect actual
2399         )
2400 '
2401
2402 # Testcase 9b, Transitive rename with content merge
2403 #   (Related to testcase 1c)
2404 #   Commit O: z/{b,c},   x/d_1
2405 #   Commit A: y/{b,c},   x/d_2
2406 #   Commit B: z/{b,c,d_3}
2407 #   Expected: y/{b,c,d_merged}
2408
2409 test_expect_success '9b-setup: Transitive rename with content merge' '
2410         test_create_repo 9b &&
2411         (
2412                 cd 9b &&
2413
2414                 mkdir z &&
2415                 echo b >z/b &&
2416                 echo c >z/c &&
2417                 mkdir x &&
2418                 test_seq 1 10 >x/d &&
2419                 git add z x &&
2420                 test_tick &&
2421                 git commit -m "O" &&
2422
2423                 git branch O &&
2424                 git branch A &&
2425                 git branch B &&
2426
2427                 git checkout A &&
2428                 git mv z y &&
2429                 test_seq 1 11 >x/d &&
2430                 git add x/d &&
2431                 test_tick &&
2432                 git commit -m "A" &&
2433
2434                 git checkout B &&
2435                 test_seq 0 10 >x/d &&
2436                 git mv x/d z/d &&
2437                 git add z/d &&
2438                 test_tick &&
2439                 git commit -m "B"
2440         )
2441 '
2442
2443 test_expect_failure '9b-check: Transitive rename with content merge' '
2444         (
2445                 cd 9b &&
2446
2447                 git checkout A^0 &&
2448
2449                 git merge -s recursive B^0 &&
2450
2451                 git ls-files -s >out &&
2452                 test_line_count = 3 out &&
2453
2454                 test_seq 0 11 >expected &&
2455                 test_cmp expected y/d &&
2456                 git add expected &&
2457                 git rev-parse >actual \
2458                         HEAD:y/b HEAD:y/c HEAD:y/d &&
2459                 git rev-parse >expect \
2460                         O:z/b    O:z/c    :0:expected &&
2461                 test_cmp expect actual &&
2462                 test_must_fail git rev-parse HEAD:x/d &&
2463                 test_must_fail git rev-parse HEAD:z/d &&
2464                 test_path_is_missing z/d &&
2465
2466                 test $(git rev-parse HEAD:y/d) != $(git rev-parse O:x/d) &&
2467                 test $(git rev-parse HEAD:y/d) != $(git rev-parse A:x/d) &&
2468                 test $(git rev-parse HEAD:y/d) != $(git rev-parse B:z/d)
2469         )
2470 '
2471
2472 # Testcase 9c, Doubly transitive rename?
2473 #   (Related to testcase 1c, 7e, and 9d)
2474 #   Commit O: z/{b,c},     x/{d,e},    w/f
2475 #   Commit A: y/{b,c},     x/{d,e,f,g}
2476 #   Commit B: z/{b,c,d,e},             w/f
2477 #   Expected: y/{b,c,d,e}, x/{f,g}
2478 #
2479 #   NOTE: x/f and x/g may be slightly confusing here.  The rename from w/f to
2480 #         x/f is clear.  Let's look beyond that.  Here's the logic:
2481 #            Commit B renamed x/ -> z/
2482 #            Commit A renamed z/ -> y/
2483 #         So, we could possibly further rename x/f to z/f to y/f, a doubly
2484 #         transient rename.  However, where does it end?  We can chain these
2485 #         indefinitely (see testcase 9d).  What if there is a D/F conflict
2486 #         at z/f/ or y/f/?  Or just another file conflict at one of those
2487 #         paths?  In the case of an N-long chain of transient renamings,
2488 #         where do we "abort" the rename at?  Can the user make sense of
2489 #         the resulting conflict and resolve it?
2490 #
2491 #         To avoid this confusion I use the simple rule that if the other side
2492 #         of history did a directory rename to a path that your side renamed
2493 #         away, then ignore that particular rename from the other side of
2494 #         history for any implicit directory renames.
2495
2496 test_expect_success '9c-setup: Doubly transitive rename?' '
2497         test_create_repo 9c &&
2498         (
2499                 cd 9c &&
2500
2501                 mkdir z &&
2502                 echo b >z/b &&
2503                 echo c >z/c &&
2504                 mkdir x &&
2505                 echo d >x/d &&
2506                 echo e >x/e &&
2507                 mkdir w &&
2508                 echo f >w/f &&
2509                 git add z x w &&
2510                 test_tick &&
2511                 git commit -m "O" &&
2512
2513                 git branch O &&
2514                 git branch A &&
2515                 git branch B &&
2516
2517                 git checkout A &&
2518                 git mv z y &&
2519                 git mv w/f x/ &&
2520                 echo g >x/g &&
2521                 git add x/g &&
2522                 test_tick &&
2523                 git commit -m "A" &&
2524
2525                 git checkout B &&
2526                 git mv x/d z/d &&
2527                 git mv x/e z/e &&
2528                 test_tick &&
2529                 git commit -m "B"
2530         )
2531 '
2532
2533 test_expect_failure '9c-check: Doubly transitive rename?' '
2534         (
2535                 cd 9c &&
2536
2537                 git checkout A^0 &&
2538
2539                 git merge -s recursive B^0 >out &&
2540                 test_i18ngrep "WARNING: Avoiding applying x -> z rename to x/f" out &&
2541
2542                 git ls-files -s >out &&
2543                 test_line_count = 6 out &&
2544                 git ls-files -o >out &&
2545                 test_line_count = 1 out &&
2546
2547                 git rev-parse >actual \
2548                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e HEAD:x/f HEAD:x/g &&
2549                 git rev-parse >expect \
2550                         O:z/b    O:z/c    O:x/d    O:x/e    O:w/f    A:x/g &&
2551                 test_cmp expect actual
2552         )
2553 '
2554
2555 # Testcase 9d, N-fold transitive rename?
2556 #   (Related to testcase 9c...and 1c and 7e)
2557 #   Commit O: z/a, y/b, x/c, w/d, v/e, u/f
2558 #   Commit A:  y/{a,b},  w/{c,d},  u/{e,f}
2559 #   Commit B: z/{a,t}, x/{b,c}, v/{d,e}, u/f
2560 #   Expected: <see NOTE first>
2561 #
2562 #   NOTE: z/ -> y/ (in commit A)
2563 #         y/ -> x/ (in commit B)
2564 #         x/ -> w/ (in commit A)
2565 #         w/ -> v/ (in commit B)
2566 #         v/ -> u/ (in commit A)
2567 #         So, if we add a file to z, say z/t, where should it end up?  In u?
2568 #         What if there's another file or directory named 't' in one of the
2569 #         intervening directories and/or in u itself?  Also, shouldn't the
2570 #         same logic that places 't' in u/ also move ALL other files to u/?
2571 #         What if there are file or directory conflicts in any of them?  If
2572 #         we attempted to do N-way (N-fold? N-ary? N-uple?) transitive renames
2573 #         like this, would the user have any hope of understanding any
2574 #         conflicts or how their working tree ended up?  I think not, so I'm
2575 #         ruling out N-ary transitive renames for N>1.
2576 #
2577 #   Therefore our expected result is:
2578 #     z/t, y/a, x/b, w/c, u/d, u/e, u/f
2579 #   The reason that v/d DOES get transitively renamed to u/d is that u/ isn't
2580 #   renamed somewhere.  A slightly sub-optimal result, but it uses fairly
2581 #   simple rules that are consistent with what we need for all the other
2582 #   testcases and simplifies things for the user.
2583
2584 test_expect_success '9d-setup: N-way transitive rename?' '
2585         test_create_repo 9d &&
2586         (
2587                 cd 9d &&
2588
2589                 mkdir z y x w v u &&
2590                 echo a >z/a &&
2591                 echo b >y/b &&
2592                 echo c >x/c &&
2593                 echo d >w/d &&
2594                 echo e >v/e &&
2595                 echo f >u/f &&
2596                 git add z y x w v u &&
2597                 test_tick &&
2598                 git commit -m "O" &&
2599
2600                 git branch O &&
2601                 git branch A &&
2602                 git branch B &&
2603
2604                 git checkout A &&
2605                 git mv z/a y/ &&
2606                 git mv x/c w/ &&
2607                 git mv v/e u/ &&
2608                 test_tick &&
2609                 git commit -m "A" &&
2610
2611                 git checkout B &&
2612                 echo t >z/t &&
2613                 git mv y/b x/ &&
2614                 git mv w/d v/ &&
2615                 git add z/t &&
2616                 test_tick &&
2617                 git commit -m "B"
2618         )
2619 '
2620
2621 test_expect_failure '9d-check: N-way transitive rename?' '
2622         (
2623                 cd 9d &&
2624
2625                 git checkout A^0 &&
2626
2627                 git merge -s recursive B^0 >out &&
2628                 test_i18ngrep "WARNING: Avoiding applying z -> y rename to z/t" out &&
2629                 test_i18ngrep "WARNING: Avoiding applying y -> x rename to y/a" out &&
2630                 test_i18ngrep "WARNING: Avoiding applying x -> w rename to x/b" out &&
2631                 test_i18ngrep "WARNING: Avoiding applying w -> v rename to w/c" out &&
2632
2633                 git ls-files -s >out &&
2634                 test_line_count = 7 out &&
2635                 git ls-files -o >out &&
2636                 test_line_count = 1 out &&
2637
2638                 git rev-parse >actual \
2639                         HEAD:z/t \
2640                         HEAD:y/a HEAD:x/b HEAD:w/c \
2641                         HEAD:u/d HEAD:u/e HEAD:u/f &&
2642                 git rev-parse >expect \
2643                         B:z/t    \
2644                         O:z/a    O:y/b    O:x/c    \
2645                         O:w/d    O:v/e    A:u/f &&
2646                 test_cmp expect actual
2647         )
2648 '
2649
2650 # Testcase 9e, N-to-1 whammo
2651 #   (Related to testcase 9c...and 1c and 7e)
2652 #   Commit O: dir1/{a,b}, dir2/{d,e}, dir3/{g,h}, dirN/{j,k}
2653 #   Commit A: dir1/{a,b,c,yo}, dir2/{d,e,f,yo}, dir3/{g,h,i,yo}, dirN/{j,k,l,yo}
2654 #   Commit B: combined/{a,b,d,e,g,h,j,k}
2655 #   Expected: combined/{a,b,c,d,e,f,g,h,i,j,k,l}, CONFLICT(Nto1) warnings,
2656 #             dir1/yo, dir2/yo, dir3/yo, dirN/yo
2657
2658 test_expect_success '9e-setup: N-to-1 whammo' '
2659         test_create_repo 9e &&
2660         (
2661                 cd 9e &&
2662
2663                 mkdir dir1 dir2 dir3 dirN &&
2664                 echo a >dir1/a &&
2665                 echo b >dir1/b &&
2666                 echo d >dir2/d &&
2667                 echo e >dir2/e &&
2668                 echo g >dir3/g &&
2669                 echo h >dir3/h &&
2670                 echo j >dirN/j &&
2671                 echo k >dirN/k &&
2672                 git add dir* &&
2673                 test_tick &&
2674                 git commit -m "O" &&
2675
2676                 git branch O &&
2677                 git branch A &&
2678                 git branch B &&
2679
2680                 git checkout A &&
2681                 echo c  >dir1/c &&
2682                 echo yo >dir1/yo &&
2683                 echo f  >dir2/f &&
2684                 echo yo >dir2/yo &&
2685                 echo i  >dir3/i &&
2686                 echo yo >dir3/yo &&
2687                 echo l  >dirN/l &&
2688                 echo yo >dirN/yo &&
2689                 git add dir* &&
2690                 test_tick &&
2691                 git commit -m "A" &&
2692
2693                 git checkout B &&
2694                 git mv dir1 combined &&
2695                 git mv dir2/* combined/ &&
2696                 git mv dir3/* combined/ &&
2697                 git mv dirN/* combined/ &&
2698                 test_tick &&
2699                 git commit -m "B"
2700         )
2701 '
2702
2703 test_expect_failure C_LOCALE_OUTPUT '9e-check: N-to-1 whammo' '
2704         (
2705                 cd 9e &&
2706
2707                 git checkout A^0 &&
2708
2709                 test_must_fail git merge -s recursive B^0 >out &&
2710                 grep "CONFLICT (implicit dir rename): Cannot map more than one path to combined/yo" out >error_line &&
2711                 grep -q dir1/yo error_line &&
2712                 grep -q dir2/yo error_line &&
2713                 grep -q dir3/yo error_line &&
2714                 grep -q dirN/yo error_line &&
2715
2716                 git ls-files -s >out &&
2717                 test_line_count = 16 out &&
2718                 git ls-files -u >out &&
2719                 test_line_count = 0 out &&
2720                 git ls-files -o >out &&
2721                 test_line_count = 2 out &&
2722
2723                 git rev-parse >actual \
2724                         :0:combined/a :0:combined/b :0:combined/c \
2725                         :0:combined/d :0:combined/e :0:combined/f \
2726                         :0:combined/g :0:combined/h :0:combined/i \
2727                         :0:combined/j :0:combined/k :0:combined/l &&
2728                 git rev-parse >expect \
2729                          O:dir1/a      O:dir1/b      A:dir1/c \
2730                          O:dir2/d      O:dir2/e      A:dir2/f \
2731                          O:dir3/g      O:dir3/h      A:dir3/i \
2732                          O:dirN/j      O:dirN/k      A:dirN/l &&
2733                 test_cmp expect actual &&
2734
2735                 git rev-parse >actual \
2736                         :0:dir1/yo :0:dir2/yo :0:dir3/yo :0:dirN/yo &&
2737                 git rev-parse >expect \
2738                          A:dir1/yo  A:dir2/yo  A:dir3/yo  A:dirN/yo &&
2739                 test_cmp expect actual
2740         )
2741 '
2742
2743 # Testcase 9f, Renamed directory that only contained immediate subdirs
2744 #   (Related to testcases 1e & 9g)
2745 #   Commit O: goal/{a,b}/$more_files
2746 #   Commit A: priority/{a,b}/$more_files
2747 #   Commit B: goal/{a,b}/$more_files, goal/c
2748 #   Expected: priority/{a,b}/$more_files, priority/c
2749
2750 test_expect_success '9f-setup: Renamed directory that only contained immediate subdirs' '
2751         test_create_repo 9f &&
2752         (
2753                 cd 9f &&
2754
2755                 mkdir -p goal/a &&
2756                 mkdir -p goal/b &&
2757                 echo foo >goal/a/foo &&
2758                 echo bar >goal/b/bar &&
2759                 echo baz >goal/b/baz &&
2760                 git add goal &&
2761                 test_tick &&
2762                 git commit -m "O" &&
2763
2764                 git branch O &&
2765                 git branch A &&
2766                 git branch B &&
2767
2768                 git checkout A &&
2769                 git mv goal/ priority &&
2770                 test_tick &&
2771                 git commit -m "A" &&
2772
2773                 git checkout B &&
2774                 echo c >goal/c &&
2775                 git add goal/c &&
2776                 test_tick &&
2777                 git commit -m "B"
2778         )
2779 '
2780
2781 test_expect_failure '9f-check: Renamed directory that only contained immediate subdirs' '
2782         (
2783                 cd 9f &&
2784
2785                 git checkout A^0 &&
2786
2787                 git merge -s recursive B^0 &&
2788
2789                 git ls-files -s >out &&
2790                 test_line_count = 4 out &&
2791
2792                 git rev-parse >actual \
2793                         HEAD:priority/a/foo \
2794                         HEAD:priority/b/bar \
2795                         HEAD:priority/b/baz \
2796                         HEAD:priority/c &&
2797                 git rev-parse >expect \
2798                         O:goal/a/foo \
2799                         O:goal/b/bar \
2800                         O:goal/b/baz \
2801                         B:goal/c &&
2802                 test_cmp expect actual &&
2803                 test_must_fail git rev-parse HEAD:goal/c
2804         )
2805 '
2806
2807 # Testcase 9g, Renamed directory that only contained immediate subdirs, immediate subdirs renamed
2808 #   (Related to testcases 1e & 9f)
2809 #   Commit O: goal/{a,b}/$more_files
2810 #   Commit A: priority/{alpha,bravo}/$more_files
2811 #   Commit B: goal/{a,b}/$more_files, goal/c
2812 #   Expected: priority/{alpha,bravo}/$more_files, priority/c
2813
2814 test_expect_success '9g-setup: Renamed directory that only contained immediate subdirs, immediate subdirs renamed' '
2815         test_create_repo 9g &&
2816         (
2817                 cd 9g &&
2818
2819                 mkdir -p goal/a &&
2820                 mkdir -p goal/b &&
2821                 echo foo >goal/a/foo &&
2822                 echo bar >goal/b/bar &&
2823                 echo baz >goal/b/baz &&
2824                 git add goal &&
2825                 test_tick &&
2826                 git commit -m "O" &&
2827
2828                 git branch O &&
2829                 git branch A &&
2830                 git branch B &&
2831
2832                 git checkout A &&
2833                 mkdir priority &&
2834                 git mv goal/a/ priority/alpha &&
2835                 git mv goal/b/ priority/beta &&
2836                 rmdir goal/ &&
2837                 test_tick &&
2838                 git commit -m "A" &&
2839
2840                 git checkout B &&
2841                 echo c >goal/c &&
2842                 git add goal/c &&
2843                 test_tick &&
2844                 git commit -m "B"
2845         )
2846 '
2847
2848 test_expect_failure '9g-check: Renamed directory that only contained immediate subdirs, immediate subdirs renamed' '
2849         (
2850                 cd 9g &&
2851
2852                 git checkout A^0 &&
2853
2854                 git merge -s recursive B^0 &&
2855
2856                 git ls-files -s >out &&
2857                 test_line_count = 4 out &&
2858
2859                 git rev-parse >actual \
2860                         HEAD:priority/alpha/foo \
2861                         HEAD:priority/beta/bar  \
2862                         HEAD:priority/beta/baz  \
2863                         HEAD:priority/c &&
2864                 git rev-parse >expect \
2865                         O:goal/a/foo \
2866                         O:goal/b/bar \
2867                         O:goal/b/baz \
2868                         B:goal/c &&
2869                 test_cmp expect actual &&
2870                 test_must_fail git rev-parse HEAD:goal/c
2871         )
2872 '
2873
2874 ###########################################################################
2875 # Rules suggested by section 9:
2876 #
2877 #   If the other side of history did a directory rename to a path that your
2878 #   side renamed away, then ignore that particular rename from the other
2879 #   side of history for any implicit directory renames.
2880 ###########################################################################
2881
2882 ###########################################################################
2883 # SECTION 10: Handling untracked files
2884 #
2885 # unpack_trees(), upon which the recursive merge algorithm is based, aborts
2886 # the operation if untracked or dirty files would be deleted or overwritten
2887 # by the merge.  Unfortunately, unpack_trees() does not understand renames,
2888 # and if it doesn't abort, then it muddies up the working directory before
2889 # we even get to the point of detecting renames, so we need some special
2890 # handling, at least in the case of directory renames.
2891 ###########################################################################
2892
2893 # Testcase 10a, Overwrite untracked: normal rename/delete
2894 #   Commit O: z/{b,c_1}
2895 #   Commit A: z/b + untracked z/c + untracked z/d
2896 #   Commit B: z/{b,d_1}
2897 #   Expected: Aborted Merge +
2898 #       ERROR_MSG(untracked working tree files would be overwritten by merge)
2899
2900 test_expect_success '10a-setup: Overwrite untracked with normal rename/delete' '
2901         test_create_repo 10a &&
2902         (
2903                 cd 10a &&
2904
2905                 mkdir z &&
2906                 echo b >z/b &&
2907                 echo c >z/c &&
2908                 git add z &&
2909                 test_tick &&
2910                 git commit -m "O" &&
2911
2912                 git branch O &&
2913                 git branch A &&
2914                 git branch B &&
2915
2916                 git checkout A &&
2917                 git rm z/c &&
2918                 test_tick &&
2919                 git commit -m "A" &&
2920
2921                 git checkout B &&
2922                 git mv z/c z/d &&
2923                 test_tick &&
2924                 git commit -m "B"
2925         )
2926 '
2927
2928 test_expect_success '10a-check: Overwrite untracked with normal rename/delete' '
2929         (
2930                 cd 10a &&
2931
2932                 git checkout A^0 &&
2933                 echo very >z/c &&
2934                 echo important >z/d &&
2935
2936                 test_must_fail git merge -s recursive B^0 >out 2>err &&
2937                 test_i18ngrep "The following untracked working tree files would be overwritten by merge" err &&
2938
2939                 git ls-files -s >out &&
2940                 test_line_count = 1 out &&
2941                 git ls-files -o >out &&
2942                 test_line_count = 4 out &&
2943
2944                 echo very >expect &&
2945                 test_cmp expect z/c &&
2946
2947                 echo important >expect &&
2948                 test_cmp expect z/d &&
2949
2950                 git rev-parse HEAD:z/b >actual &&
2951                 git rev-parse O:z/b >expect &&
2952                 test_cmp expect actual
2953         )
2954 '
2955
2956 # Testcase 10b, Overwrite untracked: dir rename + delete
2957 #   Commit O: z/{b,c_1}
2958 #   Commit A: y/b + untracked y/{c,d,e}
2959 #   Commit B: z/{b,d_1,e}
2960 #   Expected: Failed Merge; y/b + untracked y/c + untracked y/d on disk +
2961 #             z/c_1 -> z/d_1 rename recorded at stage 3 for y/d +
2962 #       ERROR_MSG(refusing to lose untracked file at 'y/d')
2963
2964 test_expect_success '10b-setup: Overwrite untracked with dir rename + delete' '
2965         test_create_repo 10b &&
2966         (
2967                 cd 10b &&
2968
2969                 mkdir z &&
2970                 echo b >z/b &&
2971                 echo c >z/c &&
2972                 git add z &&
2973                 test_tick &&
2974                 git commit -m "O" &&
2975
2976                 git branch O &&
2977                 git branch A &&
2978                 git branch B &&
2979
2980                 git checkout A &&
2981                 git rm z/c &&
2982                 git mv z/ y/ &&
2983                 test_tick &&
2984                 git commit -m "A" &&
2985
2986                 git checkout B &&
2987                 git mv z/c z/d &&
2988                 echo e >z/e &&
2989                 git add z/e &&
2990                 test_tick &&
2991                 git commit -m "B"
2992         )
2993 '
2994
2995 test_expect_failure '10b-check: Overwrite untracked with dir rename + delete' '
2996         (
2997                 cd 10b &&
2998
2999                 git checkout A^0 &&
3000                 echo very >y/c &&
3001                 echo important >y/d &&
3002                 echo contents >y/e &&
3003
3004                 test_must_fail git merge -s recursive B^0 >out 2>err &&
3005                 test_i18ngrep "CONFLICT (rename/delete).*Version B\^0 of y/d left in tree at y/d~B\^0" out &&
3006                 test_i18ngrep "Error: Refusing to lose untracked file at y/e; writing to y/e~B\^0 instead" out &&
3007
3008                 git ls-files -s >out &&
3009                 test_line_count = 3 out &&
3010                 git ls-files -u >out &&
3011                 test_line_count = 2 out &&
3012                 git ls-files -o >out &&
3013                 test_line_count = 5 out &&
3014
3015                 git rev-parse >actual \
3016                         :0:y/b :3:y/d :3:y/e &&
3017                 git rev-parse >expect \
3018                         O:z/b  O:z/c  B:z/e &&
3019                 test_cmp expect actual &&
3020
3021                 echo very >expect &&
3022                 test_cmp expect y/c &&
3023
3024                 echo important >expect &&
3025                 test_cmp expect y/d &&
3026
3027                 echo contents >expect &&
3028                 test_cmp expect y/e
3029         )
3030 '
3031
3032 # Testcase 10c, Overwrite untracked: dir rename/rename(1to2)
3033 #   Commit O: z/{a,b}, x/{c,d}
3034 #   Commit A: y/{a,b}, w/c, x/d + different untracked y/c
3035 #   Commit B: z/{a,b,c}, x/d
3036 #   Expected: Failed Merge; y/{a,b} + x/d + untracked y/c +
3037 #             CONFLICT(rename/rename) x/c -> w/c vs y/c +
3038 #             y/c~B^0 +
3039 #             ERROR_MSG(Refusing to lose untracked file at y/c)
3040
3041 test_expect_success '10c-setup: Overwrite untracked with dir rename/rename(1to2)' '
3042         test_create_repo 10c &&
3043         (
3044                 cd 10c &&
3045
3046                 mkdir z x &&
3047                 echo a >z/a &&
3048                 echo b >z/b &&
3049                 echo c >x/c &&
3050                 echo d >x/d &&
3051                 git add z x &&
3052                 test_tick &&
3053                 git commit -m "O" &&
3054
3055                 git branch O &&
3056                 git branch A &&
3057                 git branch B &&
3058
3059                 git checkout A &&
3060                 mkdir w &&
3061                 git mv x/c w/c &&
3062                 git mv z/ y/ &&
3063                 test_tick &&
3064                 git commit -m "A" &&
3065
3066                 git checkout B &&
3067                 git mv x/c z/ &&
3068                 test_tick &&
3069                 git commit -m "B"
3070         )
3071 '
3072
3073 test_expect_failure '10c-check: Overwrite untracked with dir rename/rename(1to2)' '
3074         (
3075                 cd 10c &&
3076
3077                 git checkout A^0 &&
3078                 echo important >y/c &&
3079
3080                 test_must_fail git merge -s recursive B^0 >out 2>err &&
3081                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3082                 test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~B\^0 instead" out &&
3083
3084                 git ls-files -s >out &&
3085                 test_line_count = 6 out &&
3086                 git ls-files -u >out &&
3087                 test_line_count = 3 out &&
3088                 git ls-files -o >out &&
3089                 test_line_count = 3 out &&
3090
3091                 git rev-parse >actual \
3092                         :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :3:y/c &&
3093                 git rev-parse >expect \
3094                          O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&
3095                 test_cmp expect actual &&
3096
3097                 git hash-object y/c~B^0 >actual &&
3098                 git rev-parse O:x/c >expect &&
3099                 test_cmp expect actual &&
3100
3101                 echo important >expect &&
3102                 test_cmp expect y/c
3103         )
3104 '
3105
3106 # Testcase 10d, Delete untracked w/ dir rename/rename(2to1)
3107 #   Commit O: z/{a,b,c_1},        x/{d,e,f_2}
3108 #   Commit A: y/{a,b},            x/{d,e,f_2,wham_1} + untracked y/wham
3109 #   Commit B: z/{a,b,c_1,wham_2}, y/{d,e}
3110 #   Expected: Failed Merge; y/{a,b,d,e} + untracked y/{wham,wham~B^0,wham~HEAD}+
3111 #             CONFLICT(rename/rename) z/c_1 vs x/f_2 -> y/wham
3112 #             ERROR_MSG(Refusing to lose untracked file at y/wham)
3113
3114 test_expect_success '10d-setup: Delete untracked with dir rename/rename(2to1)' '
3115         test_create_repo 10d &&
3116         (
3117                 cd 10d &&
3118
3119                 mkdir z x &&
3120                 echo a >z/a &&
3121                 echo b >z/b &&
3122                 echo c >z/c &&
3123                 echo d >x/d &&
3124                 echo e >x/e &&
3125                 echo f >x/f &&
3126                 git add z x &&
3127                 test_tick &&
3128                 git commit -m "O" &&
3129
3130                 git branch O &&
3131                 git branch A &&
3132                 git branch B &&
3133
3134                 git checkout A &&
3135                 git mv z/c x/wham &&
3136                 git mv z/ y/ &&
3137                 test_tick &&
3138                 git commit -m "A" &&
3139
3140                 git checkout B &&
3141                 git mv x/f z/wham &&
3142                 git mv x/ y/ &&
3143                 test_tick &&
3144                 git commit -m "B"
3145         )
3146 '
3147
3148 test_expect_failure '10d-check: Delete untracked with dir rename/rename(2to1)' '
3149         (
3150                 cd 10d &&
3151
3152                 git checkout A^0 &&
3153                 echo important >y/wham &&
3154
3155                 test_must_fail git merge -s recursive B^0 >out 2>err &&
3156                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3157                 test_i18ngrep "Refusing to lose untracked file at y/wham" out &&
3158
3159                 git ls-files -s >out &&
3160                 test_line_count = 6 out &&
3161                 git ls-files -u >out &&
3162                 test_line_count = 2 out &&
3163                 git ls-files -o >out &&
3164                 test_line_count = 4 out &&
3165
3166                 git rev-parse >actual \
3167                         :0:y/a :0:y/b :0:y/d :0:y/e :2:y/wham :3:y/wham &&
3168                 git rev-parse >expect \
3169                          O:z/a  O:z/b  O:x/d  O:x/e  O:z/c     O:x/f &&
3170                 test_cmp expect actual &&
3171
3172                 test_must_fail git rev-parse :1:y/wham &&
3173
3174                 echo important >expect &&
3175                 test_cmp expect y/wham &&
3176
3177                 git hash-object >actual \
3178                         y/wham~B^0 y/wham~HEAD &&
3179                 git rev-parse >expect \
3180                         O:x/f      O:z/c &&
3181                 test_cmp expect actual
3182         )
3183 '
3184
3185 # Testcase 10e, Does git complain about untracked file that's not in the way?
3186 #   Commit O: z/{a,b}
3187 #   Commit A: y/{a,b} + untracked z/c
3188 #   Commit B: z/{a,b,c}
3189 #   Expected: y/{a,b,c} + untracked z/c
3190
3191 test_expect_success '10e-setup: Does git complain about untracked file that is not really in the way?' '
3192         test_create_repo 10e &&
3193         (
3194                 cd 10e &&
3195
3196                 mkdir z &&
3197                 echo a >z/a &&
3198                 echo b >z/b &&
3199                 git add z &&
3200                 test_tick &&
3201                 git commit -m "O" &&
3202
3203                 git branch O &&
3204                 git branch A &&
3205                 git branch B &&
3206
3207                 git checkout A &&
3208                 git mv z/ y/ &&
3209                 test_tick &&
3210                 git commit -m "A" &&
3211
3212                 git checkout B &&
3213                 echo c >z/c &&
3214                 git add z/c &&
3215                 test_tick &&
3216                 git commit -m "B"
3217         )
3218 '
3219
3220 test_expect_failure '10e-check: Does git complain about untracked file that is not really in the way?' '
3221         (
3222                 cd 10e &&
3223
3224                 git checkout A^0 &&
3225                 mkdir z &&
3226                 echo random >z/c &&
3227
3228                 git merge -s recursive B^0 >out 2>err &&
3229                 test_i18ngrep ! "following untracked working tree files would be overwritten by merge" err &&
3230
3231                 git ls-files -s >out &&
3232                 test_line_count = 3 out &&
3233                 git ls-files -u >out &&
3234                 test_line_count = 0 out &&
3235                 git ls-files -o >out &&
3236                 test_line_count = 3 out &&
3237
3238                 git rev-parse >actual \
3239                         :0:y/a :0:y/b :0:y/c &&
3240                 git rev-parse >expect \
3241                          O:z/a  O:z/b  B:z/c &&
3242                 test_cmp expect actual &&
3243
3244                 echo random >expect &&
3245                 test_cmp expect z/c
3246         )
3247 '
3248
3249 test_done