Merge branch 'en/rename-directory-detection-reboot'
[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_success '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_success '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 #   (Related to testcase 12b -- joint-transitivity?)
163 #   Commit O: z/{b,c},   x/d
164 #   Commit A: y/{b,c},   x/d
165 #   Commit B: z/{b,c,d}
166 #   Expected: y/{b,c,d}  (because x/d -> z/d -> y/d)
167
168 test_expect_success '1c-setup: Transitive renaming' '
169         test_create_repo 1c &&
170         (
171                 cd 1c &&
172
173                 mkdir z &&
174                 echo b >z/b &&
175                 echo c >z/c &&
176                 mkdir x &&
177                 echo d >x/d &&
178                 git add z x &&
179                 test_tick &&
180                 git commit -m "O" &&
181
182                 git branch O &&
183                 git branch A &&
184                 git branch B &&
185
186                 git checkout A &&
187                 git mv z y &&
188                 test_tick &&
189                 git commit -m "A" &&
190
191                 git checkout B &&
192                 git mv x/d z/d &&
193                 test_tick &&
194                 git commit -m "B"
195         )
196 '
197
198 test_expect_success '1c-check: Transitive renaming' '
199         (
200                 cd 1c &&
201
202                 git checkout A^0 &&
203
204                 git merge -s recursive B^0 &&
205
206                 git ls-files -s >out &&
207                 test_line_count = 3 out &&
208
209                 git rev-parse >actual \
210                         HEAD:y/b HEAD:y/c HEAD:y/d &&
211                 git rev-parse >expect \
212                         O:z/b    O:z/c    O:x/d &&
213                 test_cmp expect actual &&
214                 test_must_fail git rev-parse HEAD:x/d &&
215                 test_must_fail git rev-parse HEAD:z/d &&
216                 test_path_is_missing z/d
217         )
218 '
219
220 # Testcase 1d, Directory renames (merging two directories into one new one)
221 #              cause a rename/rename(2to1) conflict
222 #   (Related to testcases 1c and 7b)
223 #   Commit O. z/{b,c},        y/{d,e}
224 #   Commit A. x/{b,c},        y/{d,e,m,wham_1}
225 #   Commit B. z/{b,c,n,wham_2}, x/{d,e}
226 #   Expected: x/{b,c,d,e,m,n}, CONFLICT:(y/wham_1 & z/wham_2 -> x/wham)
227 #   Note: y/m & z/n should definitely move into x.  By the same token, both
228 #         y/wham_1 & z/wham_2 should too...giving us a conflict.
229
230 test_expect_success '1d-setup: Directory renames cause a rename/rename(2to1) conflict' '
231         test_create_repo 1d &&
232         (
233                 cd 1d &&
234
235                 mkdir z &&
236                 echo b >z/b &&
237                 echo c >z/c &&
238                 mkdir y &&
239                 echo d >y/d &&
240                 echo e >y/e &&
241                 git add z y &&
242                 test_tick &&
243                 git commit -m "O" &&
244
245                 git branch O &&
246                 git branch A &&
247                 git branch B &&
248
249                 git checkout A &&
250                 git mv z x &&
251                 echo m >y/m &&
252                 echo wham1 >y/wham &&
253                 git add y &&
254                 test_tick &&
255                 git commit -m "A" &&
256
257                 git checkout B &&
258                 git mv y x &&
259                 echo n >z/n &&
260                 echo wham2 >z/wham &&
261                 git add z &&
262                 test_tick &&
263                 git commit -m "B"
264         )
265 '
266
267 test_expect_success '1d-check: Directory renames cause a rename/rename(2to1) conflict' '
268         (
269                 cd 1d &&
270
271                 git checkout A^0 &&
272
273                 test_must_fail git merge -s recursive B^0 >out &&
274                 test_i18ngrep "CONFLICT (rename/rename)" out &&
275
276                 git ls-files -s >out &&
277                 test_line_count = 8 out &&
278                 git ls-files -u >out &&
279                 test_line_count = 2 out &&
280                 git ls-files -o >out &&
281                 test_line_count = 3 out &&
282
283                 git rev-parse >actual \
284                         :0:x/b :0:x/c :0:x/d :0:x/e :0:x/m :0:x/n &&
285                 git rev-parse >expect \
286                          O:z/b  O:z/c  O:y/d  O:y/e  A:y/m  B:z/n &&
287                 test_cmp expect actual &&
288
289                 test_must_fail git rev-parse :0:x/wham &&
290                 git rev-parse >actual \
291                         :2:x/wham :3:x/wham &&
292                 git rev-parse >expect \
293                          A:y/wham  B:z/wham &&
294                 test_cmp expect actual &&
295
296                 test_path_is_missing x/wham &&
297                 test_path_is_file x/wham~HEAD &&
298                 test_path_is_file x/wham~B^0 &&
299
300                 git hash-object >actual \
301                         x/wham~HEAD x/wham~B^0 &&
302                 git rev-parse >expect \
303                         A:y/wham    B:z/wham &&
304                 test_cmp expect actual
305         )
306 '
307
308 # Testcase 1e, Renamed directory, with all filenames being renamed too
309 #   (Related to testcases 9f & 9g)
310 #   Commit O: z/{oldb,oldc}
311 #   Commit A: y/{newb,newc}
312 #   Commit B: z/{oldb,oldc,d}
313 #   Expected: y/{newb,newc,d}
314
315 test_expect_success '1e-setup: Renamed directory, with all files being renamed too' '
316         test_create_repo 1e &&
317         (
318                 cd 1e &&
319
320                 mkdir z &&
321                 echo b >z/oldb &&
322                 echo c >z/oldc &&
323                 git add z &&
324                 test_tick &&
325                 git commit -m "O" &&
326
327                 git branch O &&
328                 git branch A &&
329                 git branch B &&
330
331                 git checkout A &&
332                 mkdir y &&
333                 git mv z/oldb y/newb &&
334                 git mv z/oldc y/newc &&
335                 test_tick &&
336                 git commit -m "A" &&
337
338                 git checkout B &&
339                 echo d >z/d &&
340                 git add z/d &&
341                 test_tick &&
342                 git commit -m "B"
343         )
344 '
345
346 test_expect_success '1e-check: Renamed directory, with all files being renamed too' '
347         (
348                 cd 1e &&
349
350                 git checkout A^0 &&
351
352                 git merge -s recursive B^0 &&
353
354                 git ls-files -s >out &&
355                 test_line_count = 3 out &&
356
357                 git rev-parse >actual \
358                         HEAD:y/newb HEAD:y/newc HEAD:y/d &&
359                 git rev-parse >expect \
360                         O:z/oldb    O:z/oldc    B:z/d &&
361                 test_cmp expect actual &&
362                 test_must_fail git rev-parse HEAD:z/d
363         )
364 '
365
366 # Testcase 1f, Split a directory into two other directories
367 #   (Related to testcases 3a, all of section 2, and all of section 4)
368 #   Commit O: z/{b,c,d,e,f}
369 #   Commit A: z/{b,c,d,e,f,g}
370 #   Commit B: y/{b,c}, x/{d,e,f}
371 #   Expected: y/{b,c}, x/{d,e,f,g}
372
373 test_expect_success '1f-setup: Split a directory into two other directories' '
374         test_create_repo 1f &&
375         (
376                 cd 1f &&
377
378                 mkdir z &&
379                 echo b >z/b &&
380                 echo c >z/c &&
381                 echo d >z/d &&
382                 echo e >z/e &&
383                 echo f >z/f &&
384                 git add z &&
385                 test_tick &&
386                 git commit -m "O" &&
387
388                 git branch O &&
389                 git branch A &&
390                 git branch B &&
391
392                 git checkout A &&
393                 echo g >z/g &&
394                 git add z/g &&
395                 test_tick &&
396                 git commit -m "A" &&
397
398                 git checkout B &&
399                 mkdir y &&
400                 mkdir x &&
401                 git mv z/b y/ &&
402                 git mv z/c y/ &&
403                 git mv z/d x/ &&
404                 git mv z/e x/ &&
405                 git mv z/f x/ &&
406                 rmdir z &&
407                 test_tick &&
408                 git commit -m "B"
409         )
410 '
411
412 test_expect_success '1f-check: Split a directory into two other directories' '
413         (
414                 cd 1f &&
415
416                 git checkout A^0 &&
417
418                 git merge -s recursive B^0 &&
419
420                 git ls-files -s >out &&
421                 test_line_count = 6 out &&
422
423                 git rev-parse >actual \
424                         HEAD:y/b HEAD:y/c HEAD:x/d HEAD:x/e HEAD:x/f HEAD:x/g &&
425                 git rev-parse >expect \
426                         O:z/b    O:z/c    O:z/d    O:z/e    O:z/f    A:z/g &&
427                 test_cmp expect actual &&
428                 test_path_is_missing z/g &&
429                 test_must_fail git rev-parse HEAD:z/g
430         )
431 '
432
433 ###########################################################################
434 # Rules suggested by testcases in section 1:
435 #
436 #   We should still detect the directory rename even if it wasn't just
437 #   the directory renamed, but the files within it. (see 1b)
438 #
439 #   If renames split a directory into two or more others, the directory
440 #   with the most renames, "wins" (see 1c).  However, see the testcases
441 #   in section 2, plus testcases 3a and 4a.
442 ###########################################################################
443
444
445 ###########################################################################
446 # SECTION 2: Split into multiple directories, with equal number of paths
447 #
448 # Explore the splitting-a-directory rules a bit; what happens in the
449 # edge cases?
450 #
451 # Note that there is a closely related case of a directory not being
452 # split on either side of history, but being renamed differently on
453 # each side.  See testcase 8e for that.
454 ###########################################################################
455
456 # Testcase 2a, Directory split into two on one side, with equal numbers of paths
457 #   Commit O: z/{b,c}
458 #   Commit A: y/b, w/c
459 #   Commit B: z/{b,c,d}
460 #   Expected: y/b, w/c, z/d, with warning about z/ -> (y/ vs. w/) conflict
461 test_expect_success '2a-setup: Directory split into two on one side, with equal numbers of paths' '
462         test_create_repo 2a &&
463         (
464                 cd 2a &&
465
466                 mkdir z &&
467                 echo b >z/b &&
468                 echo c >z/c &&
469                 git add z &&
470                 test_tick &&
471                 git commit -m "O" &&
472
473                 git branch O &&
474                 git branch A &&
475                 git branch B &&
476
477                 git checkout A &&
478                 mkdir y &&
479                 mkdir w &&
480                 git mv z/b y/ &&
481                 git mv z/c w/ &&
482                 test_tick &&
483                 git commit -m "A" &&
484
485                 git checkout B &&
486                 echo d >z/d &&
487                 git add z/d &&
488                 test_tick &&
489                 git commit -m "B"
490         )
491 '
492
493 test_expect_success '2a-check: Directory split into two on one side, with equal numbers of paths' '
494         (
495                 cd 2a &&
496
497                 git checkout A^0 &&
498
499                 test_must_fail git merge -s recursive B^0 >out &&
500                 test_i18ngrep "CONFLICT.*directory rename split" out &&
501
502                 git ls-files -s >out &&
503                 test_line_count = 3 out &&
504                 git ls-files -u >out &&
505                 test_line_count = 0 out &&
506                 git ls-files -o >out &&
507                 test_line_count = 1 out &&
508
509                 git rev-parse >actual \
510                         :0:y/b :0:w/c :0:z/d &&
511                 git rev-parse >expect \
512                          O:z/b  O:z/c  B:z/d &&
513                 test_cmp expect actual
514         )
515 '
516
517 # Testcase 2b, Directory split into two on one side, with equal numbers of paths
518 #   Commit O: z/{b,c}
519 #   Commit A: y/b, w/c
520 #   Commit B: z/{b,c}, x/d
521 #   Expected: y/b, w/c, x/d; No warning about z/ -> (y/ vs. w/) conflict
522 test_expect_success '2b-setup: Directory split into two on one side, with equal numbers of paths' '
523         test_create_repo 2b &&
524         (
525                 cd 2b &&
526
527                 mkdir z &&
528                 echo b >z/b &&
529                 echo c >z/c &&
530                 git add z &&
531                 test_tick &&
532                 git commit -m "O" &&
533
534                 git branch O &&
535                 git branch A &&
536                 git branch B &&
537
538                 git checkout A &&
539                 mkdir y &&
540                 mkdir w &&
541                 git mv z/b y/ &&
542                 git mv z/c w/ &&
543                 test_tick &&
544                 git commit -m "A" &&
545
546                 git checkout B &&
547                 mkdir x &&
548                 echo d >x/d &&
549                 git add x/d &&
550                 test_tick &&
551                 git commit -m "B"
552         )
553 '
554
555 test_expect_success '2b-check: Directory split into two on one side, with equal numbers of paths' '
556         (
557                 cd 2b &&
558
559                 git checkout A^0 &&
560
561                 git merge -s recursive B^0 >out &&
562
563                 git ls-files -s >out &&
564                 test_line_count = 3 out &&
565                 git ls-files -u >out &&
566                 test_line_count = 0 out &&
567                 git ls-files -o >out &&
568                 test_line_count = 1 out &&
569
570                 git rev-parse >actual \
571                         :0:y/b :0:w/c :0:x/d &&
572                 git rev-parse >expect \
573                          O:z/b  O:z/c  B:x/d &&
574                 test_cmp expect actual &&
575                 test_i18ngrep ! "CONFLICT.*directory rename split" out
576         )
577 '
578
579 ###########################################################################
580 # Rules suggested by section 2:
581 #
582 #   None; the rule was already covered in section 1.  These testcases are
583 #   here just to make sure the conflict resolution and necessary warning
584 #   messages are handled correctly.
585 ###########################################################################
586
587
588 ###########################################################################
589 # SECTION 3: Path in question is the source path for some rename already
590 #
591 # Combining cases from Section 1 and trying to handle them could lead to
592 # directory renaming detection being over-applied.  So, this section
593 # provides some good testcases to check that the implementation doesn't go
594 # too far.
595 ###########################################################################
596
597 # Testcase 3a, Avoid implicit rename if involved as source on other side
598 #   (Related to testcases 1c, 1f, and 9h)
599 #   Commit O: z/{b,c,d}
600 #   Commit A: z/{b,c,d} (no change)
601 #   Commit B: y/{b,c}, x/d
602 #   Expected: y/{b,c}, x/d
603 test_expect_success '3a-setup: Avoid implicit rename if involved as source on other side' '
604         test_create_repo 3a &&
605         (
606                 cd 3a &&
607
608                 mkdir z &&
609                 echo b >z/b &&
610                 echo c >z/c &&
611                 echo d >z/d &&
612                 git add z &&
613                 test_tick &&
614                 git commit -m "O" &&
615
616                 git branch O &&
617                 git branch A &&
618                 git branch B &&
619
620                 git checkout A &&
621                 test_tick &&
622                 git commit --allow-empty -m "A" &&
623
624                 git checkout B &&
625                 mkdir y &&
626                 mkdir x &&
627                 git mv z/b y/ &&
628                 git mv z/c y/ &&
629                 git mv z/d x/ &&
630                 rmdir z &&
631                 test_tick &&
632                 git commit -m "B"
633         )
634 '
635
636 test_expect_success '3a-check: Avoid implicit rename if involved as source on other side' '
637         (
638                 cd 3a &&
639
640                 git checkout A^0 &&
641
642                 git merge -s recursive B^0 &&
643
644                 git ls-files -s >out &&
645                 test_line_count = 3 out &&
646
647                 git rev-parse >actual \
648                         HEAD:y/b HEAD:y/c HEAD:x/d &&
649                 git rev-parse >expect \
650                         O:z/b    O:z/c    O:z/d &&
651                 test_cmp expect actual
652         )
653 '
654
655 # Testcase 3b, Avoid implicit rename if involved as source on other side
656 #   (Related to testcases 5c and 7c, also kind of 1e and 1f)
657 #   Commit O: z/{b,c,d}
658 #   Commit A: y/{b,c}, x/d
659 #   Commit B: z/{b,c}, w/d
660 #   Expected: y/{b,c}, CONFLICT:(z/d -> x/d vs. w/d)
661 #   NOTE: We're particularly checking that since z/d is already involved as
662 #         a source in a file rename on the same side of history, that we don't
663 #         get it involved in directory rename detection.  If it were, we might
664 #         end up with CONFLICT:(z/d -> y/d vs. x/d vs. w/d), i.e. a
665 #         rename/rename/rename(1to3) conflict, which is just weird.
666 test_expect_success '3b-setup: Avoid implicit rename if involved as source on current side' '
667         test_create_repo 3b &&
668         (
669                 cd 3b &&
670
671                 mkdir z &&
672                 echo b >z/b &&
673                 echo c >z/c &&
674                 echo d >z/d &&
675                 git add z &&
676                 test_tick &&
677                 git commit -m "O" &&
678
679                 git branch O &&
680                 git branch A &&
681                 git branch B &&
682
683                 git checkout A &&
684                 mkdir y &&
685                 mkdir x &&
686                 git mv z/b y/ &&
687                 git mv z/c y/ &&
688                 git mv z/d x/ &&
689                 rmdir z &&
690                 test_tick &&
691                 git commit -m "A" &&
692
693                 git checkout B &&
694                 mkdir w &&
695                 git mv z/d w/ &&
696                 test_tick &&
697                 git commit -m "B"
698         )
699 '
700
701 test_expect_success '3b-check: Avoid implicit rename if involved as source on current side' '
702         (
703                 cd 3b &&
704
705                 git checkout A^0 &&
706
707                 test_must_fail git merge -s recursive B^0 >out &&
708                 test_i18ngrep CONFLICT.*rename/rename.*z/d.*x/d.*w/d out &&
709                 test_i18ngrep ! CONFLICT.*rename/rename.*y/d out &&
710
711                 git ls-files -s >out &&
712                 test_line_count = 5 out &&
713                 git ls-files -u >out &&
714                 test_line_count = 3 out &&
715                 git ls-files -o >out &&
716                 test_line_count = 1 out &&
717
718                 git rev-parse >actual \
719                         :0:y/b :0:y/c :1:z/d :2:x/d :3:w/d &&
720                 git rev-parse >expect \
721                          O:z/b  O:z/c  O:z/d  O:z/d  O:z/d &&
722                 test_cmp expect actual &&
723
724                 test_path_is_missing z/d &&
725                 git hash-object >actual \
726                         x/d   w/d &&
727                 git rev-parse >expect \
728                         O:z/d O:z/d &&
729                 test_cmp expect actual
730         )
731 '
732
733 ###########################################################################
734 # Rules suggested by section 3:
735 #
736 #   Avoid directory-rename-detection for a path, if that path is the source
737 #   of a rename on either side of a merge.
738 ###########################################################################
739
740
741 ###########################################################################
742 # SECTION 4: Partially renamed directory; still exists on both sides of merge
743 #
744 # What if we were to attempt to do directory rename detection when someone
745 # "mostly" moved a directory but still left some files around, or,
746 # equivalently, fully renamed a directory in one commmit and then recreated
747 # that directory in a later commit adding some new files and then tried to
748 # merge?
749 #
750 # It's hard to divine user intent in these cases, because you can make an
751 # argument that, depending on the intermediate history of the side being
752 # merged, that some users will want files in that directory to
753 # automatically be detected and renamed, while users with a different
754 # intermediate history wouldn't want that rename to happen.
755 #
756 # I think that it is best to simply not have directory rename detection
757 # apply to such cases.  My reasoning for this is four-fold: (1) it's
758 # easiest for users in general to figure out what happened if we don't
759 # apply directory rename detection in any such case, (2) it's an easy rule
760 # to explain ["We don't do directory rename detection if the directory
761 # still exists on both sides of the merge"], (3) we can get some hairy
762 # edge/corner cases that would be really confusing and possibly not even
763 # representable in the index if we were to even try, and [related to 3] (4)
764 # attempting to resolve this issue of divining user intent by examining
765 # intermediate history goes against the spirit of three-way merges and is a
766 # path towards crazy corner cases that are far more complex than what we're
767 # already dealing with.
768 #
769 # Note that the wording of the rule ("We don't do directory rename
770 # detection if the directory still exists on both sides of the merge.")
771 # also excludes "renaming" of a directory into a subdirectory of itself
772 # (e.g. /some/dir/* -> /some/dir/subdir/*).  It may be possible to carve
773 # out an exception for "renaming"-beneath-itself cases without opening
774 # weird edge/corner cases for other partial directory renames, but for now
775 # we are keeping the rule simple.
776 #
777 # This section contains a test for a partially-renamed-directory case.
778 ###########################################################################
779
780 # Testcase 4a, Directory split, with original directory still present
781 #   (Related to testcase 1f)
782 #   Commit O: z/{b,c,d,e}
783 #   Commit A: y/{b,c,d}, z/e
784 #   Commit B: z/{b,c,d,e,f}
785 #   Expected: y/{b,c,d}, z/{e,f}
786 #   NOTE: Even though most files from z moved to y, we don't want f to follow.
787
788 test_expect_success '4a-setup: Directory split, with original directory still present' '
789         test_create_repo 4a &&
790         (
791                 cd 4a &&
792
793                 mkdir z &&
794                 echo b >z/b &&
795                 echo c >z/c &&
796                 echo d >z/d &&
797                 echo e >z/e &&
798                 git add z &&
799                 test_tick &&
800                 git commit -m "O" &&
801
802                 git branch O &&
803                 git branch A &&
804                 git branch B &&
805
806                 git checkout A &&
807                 mkdir y &&
808                 git mv z/b y/ &&
809                 git mv z/c y/ &&
810                 git mv z/d y/ &&
811                 test_tick &&
812                 git commit -m "A" &&
813
814                 git checkout B &&
815                 echo f >z/f &&
816                 git add z/f &&
817                 test_tick &&
818                 git commit -m "B"
819         )
820 '
821
822 test_expect_success '4a-check: Directory split, with original directory still present' '
823         (
824                 cd 4a &&
825
826                 git checkout A^0 &&
827
828                 git merge -s recursive B^0 &&
829
830                 git ls-files -s >out &&
831                 test_line_count = 5 out &&
832                 git ls-files -u >out &&
833                 test_line_count = 0 out &&
834                 git ls-files -o >out &&
835                 test_line_count = 1 out &&
836
837                 git rev-parse >actual \
838                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/e HEAD:z/f &&
839                 git rev-parse >expect \
840                         O:z/b    O:z/c    O:z/d    O:z/e    B:z/f &&
841                 test_cmp expect actual
842         )
843 '
844
845 ###########################################################################
846 # Rules suggested by section 4:
847 #
848 #   Directory-rename-detection should be turned off for any directories (as
849 #   a source for renames) that exist on both sides of the merge.  (The "as
850 #   a source for renames" clarification is due to cases like 1c where
851 #   the target directory exists on both sides and we do want the rename
852 #   detection.)  But, sadly, see testcase 8b.
853 ###########################################################################
854
855
856 ###########################################################################
857 # SECTION 5: Files/directories in the way of subset of to-be-renamed paths
858 #
859 # Implicitly renaming files due to a detected directory rename could run
860 # into problems if there are files or directories in the way of the paths
861 # we want to rename.  Explore such cases in this section.
862 ###########################################################################
863
864 # Testcase 5a, Merge directories, other side adds files to original and target
865 #   Commit O: z/{b,c},       y/d
866 #   Commit A: z/{b,c,e_1,f}, y/{d,e_2}
867 #   Commit B: y/{b,c,d}
868 #   Expected: z/e_1, y/{b,c,d,e_2,f} + CONFLICT warning
869 #   NOTE: While directory rename detection is active here causing z/f to
870 #         become y/f, we did not apply this for z/e_1 because that would
871 #         give us an add/add conflict for y/e_1 vs y/e_2.  This problem with
872 #         this add/add, is that both versions of y/e are from the same side
873 #         of history, giving us no way to represent this conflict in the
874 #         index.
875
876 test_expect_success '5a-setup: Merge directories, other side adds files to original and target' '
877         test_create_repo 5a &&
878         (
879                 cd 5a &&
880
881                 mkdir z &&
882                 echo b >z/b &&
883                 echo c >z/c &&
884                 mkdir y &&
885                 echo d >y/d &&
886                 git add z y &&
887                 test_tick &&
888                 git commit -m "O" &&
889
890                 git branch O &&
891                 git branch A &&
892                 git branch B &&
893
894                 git checkout A &&
895                 echo e1 >z/e &&
896                 echo f >z/f &&
897                 echo e2 >y/e &&
898                 git add z/e z/f y/e &&
899                 test_tick &&
900                 git commit -m "A" &&
901
902                 git checkout B &&
903                 git mv z/b y/ &&
904                 git mv z/c y/ &&
905                 rmdir z &&
906                 test_tick &&
907                 git commit -m "B"
908         )
909 '
910
911 test_expect_success '5a-check: Merge directories, other side adds files to original and target' '
912         (
913                 cd 5a &&
914
915                 git checkout A^0 &&
916
917                 test_must_fail git merge -s recursive B^0 >out &&
918                 test_i18ngrep "CONFLICT.*implicit dir rename" out &&
919
920                 git ls-files -s >out &&
921                 test_line_count = 6 out &&
922                 git ls-files -u >out &&
923                 test_line_count = 0 out &&
924                 git ls-files -o >out &&
925                 test_line_count = 1 out &&
926
927                 git rev-parse >actual \
928                         :0:y/b :0:y/c :0:y/d :0:y/e :0:z/e :0:y/f &&
929                 git rev-parse >expect \
930                          O:z/b  O:z/c  O:y/d  A:y/e  A:z/e  A:z/f &&
931                 test_cmp expect actual
932         )
933 '
934
935 # Testcase 5b, Rename/delete in order to get add/add/add conflict
936 #   (Related to testcase 8d; these may appear slightly inconsistent to users;
937 #    Also related to testcases 7d and 7e)
938 #   Commit O: z/{b,c,d_1}
939 #   Commit A: y/{b,c,d_2}
940 #   Commit B: z/{b,c,d_1,e}, y/d_3
941 #   Expected: y/{b,c,e}, CONFLICT(add/add: y/d_2 vs. y/d_3)
942 #   NOTE: If z/d_1 in commit B were to be involved in dir rename detection, as
943 #         we normaly would since z/ is being renamed to y/, then this would be
944 #         a rename/delete (z/d_1 -> y/d_1 vs. deleted) AND an add/add/add
945 #         conflict of y/d_1 vs. y/d_2 vs. y/d_3.  Add/add/add is not
946 #         representable in the index, so the existence of y/d_3 needs to
947 #         cause us to bail on directory rename detection for that path, falling
948 #         back to git behavior without the directory rename detection.
949
950 test_expect_success '5b-setup: Rename/delete in order to get add/add/add conflict' '
951         test_create_repo 5b &&
952         (
953                 cd 5b &&
954
955                 mkdir z &&
956                 echo b >z/b &&
957                 echo c >z/c &&
958                 echo d1 >z/d &&
959                 git add z &&
960                 test_tick &&
961                 git commit -m "O" &&
962
963                 git branch O &&
964                 git branch A &&
965                 git branch B &&
966
967                 git checkout A &&
968                 git rm z/d &&
969                 git mv z y &&
970                 echo d2 >y/d &&
971                 git add y/d &&
972                 test_tick &&
973                 git commit -m "A" &&
974
975                 git checkout B &&
976                 mkdir y &&
977                 echo d3 >y/d &&
978                 echo e >z/e &&
979                 git add y/d z/e &&
980                 test_tick &&
981                 git commit -m "B"
982         )
983 '
984
985 test_expect_success '5b-check: Rename/delete in order to get add/add/add conflict' '
986         (
987                 cd 5b &&
988
989                 git checkout A^0 &&
990
991                 test_must_fail git merge -s recursive B^0 >out &&
992                 test_i18ngrep "CONFLICT (add/add).* y/d" out &&
993
994                 git ls-files -s >out &&
995                 test_line_count = 5 out &&
996                 git ls-files -u >out &&
997                 test_line_count = 2 out &&
998                 git ls-files -o >out &&
999                 test_line_count = 1 out &&
1000
1001                 git rev-parse >actual \
1002                         :0:y/b :0:y/c :0:y/e :2:y/d :3:y/d &&
1003                 git rev-parse >expect \
1004                          O:z/b  O:z/c  B:z/e  A:y/d  B:y/d &&
1005                 test_cmp expect actual &&
1006
1007                 test_must_fail git rev-parse :1:y/d &&
1008                 test_path_is_file y/d
1009         )
1010 '
1011
1012 # Testcase 5c, Transitive rename would cause rename/rename/rename/add/add/add
1013 #   (Directory rename detection would result in transitive rename vs.
1014 #    rename/rename(1to2) and turn it into a rename/rename(1to3).  Further,
1015 #    rename paths conflict with separate adds on the other side)
1016 #   (Related to testcases 3b and 7c)
1017 #   Commit O: z/{b,c}, x/d_1
1018 #   Commit A: y/{b,c,d_2}, w/d_1
1019 #   Commit B: z/{b,c,d_1,e}, w/d_3, y/d_4
1020 #   Expected: A mess, but only a rename/rename(1to2)/add/add mess.  Use the
1021 #             presence of y/d_4 in B to avoid doing transitive rename of
1022 #             x/d_1 -> z/d_1 -> y/d_1, so that the only paths we have at
1023 #             y/d are y/d_2 and y/d_4.  We still do the move from z/e to y/e,
1024 #             though, because it doesn't have anything in the way.
1025
1026 test_expect_success '5c-setup: Transitive rename would cause rename/rename/rename/add/add/add' '
1027         test_create_repo 5c &&
1028         (
1029                 cd 5c &&
1030
1031                 mkdir z &&
1032                 echo b >z/b &&
1033                 echo c >z/c &&
1034                 mkdir x &&
1035                 echo d1 >x/d &&
1036                 git add z x &&
1037                 test_tick &&
1038                 git commit -m "O" &&
1039
1040                 git branch O &&
1041                 git branch A &&
1042                 git branch B &&
1043
1044                 git checkout A &&
1045                 git mv z y &&
1046                 echo d2 >y/d &&
1047                 git add y/d &&
1048                 git mv x w &&
1049                 test_tick &&
1050                 git commit -m "A" &&
1051
1052                 git checkout B &&
1053                 git mv x/d z/ &&
1054                 mkdir w &&
1055                 mkdir y &&
1056                 echo d3 >w/d &&
1057                 echo d4 >y/d &&
1058                 echo e >z/e &&
1059                 git add w/ y/ z/e &&
1060                 test_tick &&
1061                 git commit -m "B"
1062         )
1063 '
1064
1065 test_expect_success '5c-check: Transitive rename would cause rename/rename/rename/add/add/add' '
1066         (
1067                 cd 5c &&
1068
1069                 git checkout A^0 &&
1070
1071                 test_must_fail git merge -s recursive B^0 >out &&
1072                 test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*z/d" out &&
1073                 test_i18ngrep "CONFLICT (add/add).* y/d" out &&
1074
1075                 git ls-files -s >out &&
1076                 test_line_count = 9 out &&
1077                 git ls-files -u >out &&
1078                 test_line_count = 6 out &&
1079                 git ls-files -o >out &&
1080                 test_line_count = 3 out &&
1081
1082                 git rev-parse >actual \
1083                         :0:y/b :0:y/c :0:y/e &&
1084                 git rev-parse >expect \
1085                          O:z/b  O:z/c  B:z/e &&
1086                 test_cmp expect actual &&
1087
1088                 test_must_fail git rev-parse :1:y/d &&
1089                 git rev-parse >actual \
1090                         :2:w/d :3:w/d :1:x/d :2:y/d :3:y/d :3:z/d &&
1091                 git rev-parse >expect \
1092                          O:x/d  B:w/d  O:x/d  A:y/d  B:y/d  O:x/d &&
1093                 test_cmp expect actual &&
1094
1095                 git hash-object >actual \
1096                         w/d~HEAD w/d~B^0 z/d &&
1097                 git rev-parse >expect \
1098                         O:x/d    B:w/d   O:x/d &&
1099                 test_cmp expect actual &&
1100                 test_path_is_missing x/d &&
1101                 test_path_is_file y/d &&
1102                 grep -q "<<<<" y/d  # conflict markers should be present
1103         )
1104 '
1105
1106 # Testcase 5d, Directory/file/file conflict due to directory rename
1107 #   Commit O: z/{b,c}
1108 #   Commit A: y/{b,c,d_1}
1109 #   Commit B: z/{b,c,d_2,f}, y/d/e
1110 #   Expected: y/{b,c,d/e,f}, z/d_2, CONFLICT(file/directory), y/d_1~HEAD
1111 #   Note: The fact that y/d/ exists in B makes us bail on directory rename
1112 #         detection for z/d_2, but that doesn't prevent us from applying the
1113 #         directory rename detection for z/f -> y/f.
1114
1115 test_expect_success '5d-setup: Directory/file/file conflict due to directory rename' '
1116         test_create_repo 5d &&
1117         (
1118                 cd 5d &&
1119
1120                 mkdir z &&
1121                 echo b >z/b &&
1122                 echo c >z/c &&
1123                 git add z &&
1124                 test_tick &&
1125                 git commit -m "O" &&
1126
1127                 git branch O &&
1128                 git branch A &&
1129                 git branch B &&
1130
1131                 git checkout A &&
1132                 git mv z y &&
1133                 echo d1 >y/d &&
1134                 git add y/d &&
1135                 test_tick &&
1136                 git commit -m "A" &&
1137
1138                 git checkout B &&
1139                 mkdir -p y/d &&
1140                 echo e >y/d/e &&
1141                 echo d2 >z/d &&
1142                 echo f >z/f &&
1143                 git add y/d/e z/d z/f &&
1144                 test_tick &&
1145                 git commit -m "B"
1146         )
1147 '
1148
1149 test_expect_success '5d-check: Directory/file/file conflict due to directory rename' '
1150         (
1151                 cd 5d &&
1152
1153                 git checkout A^0 &&
1154
1155                 test_must_fail git merge -s recursive B^0 >out &&
1156                 test_i18ngrep "CONFLICT (file/directory).*y/d" out &&
1157
1158                 git ls-files -s >out &&
1159                 test_line_count = 6 out &&
1160                 git ls-files -u >out &&
1161                 test_line_count = 1 out &&
1162                 git ls-files -o >out &&
1163                 test_line_count = 2 out &&
1164
1165                 git rev-parse >actual \
1166                         :0:y/b :0:y/c :0:z/d :0:y/f :2:y/d :0:y/d/e &&
1167                 git rev-parse >expect \
1168                          O:z/b  O:z/c  B:z/d  B:z/f  A:y/d  B:y/d/e &&
1169                 test_cmp expect actual &&
1170
1171                 git hash-object y/d~HEAD >actual &&
1172                 git rev-parse A:y/d >expect &&
1173                 test_cmp expect actual
1174         )
1175 '
1176
1177 ###########################################################################
1178 # Rules suggested by section 5:
1179 #
1180 #   If a subset of to-be-renamed files have a file or directory in the way,
1181 #   "turn off" the directory rename for those specific sub-paths, falling
1182 #   back to old handling.  But, sadly, see testcases 8a and 8b.
1183 ###########################################################################
1184
1185
1186 ###########################################################################
1187 # SECTION 6: Same side of the merge was the one that did the rename
1188 #
1189 # It may sound obvious that you only want to apply implicit directory
1190 # renames to directories if the _other_ side of history did the renaming.
1191 # If you did make an implementation that didn't explicitly enforce this
1192 # rule, the majority of cases that would fall under this section would
1193 # also be solved by following the rules from the above sections.  But
1194 # there are still a few that stick out, so this section covers them just
1195 # to make sure we also get them right.
1196 ###########################################################################
1197
1198 # Testcase 6a, Tricky rename/delete
1199 #   Commit O: z/{b,c,d}
1200 #   Commit A: z/b
1201 #   Commit B: y/{b,c}, z/d
1202 #   Expected: y/b, CONFLICT(rename/delete, z/c -> y/c vs. NULL)
1203 #   Note: We're just checking here that the rename of z/b and z/c to put
1204 #         them under y/ doesn't accidentally catch z/d and make it look like
1205 #         it is also involved in a rename/delete conflict.
1206
1207 test_expect_success '6a-setup: Tricky rename/delete' '
1208         test_create_repo 6a &&
1209         (
1210                 cd 6a &&
1211
1212                 mkdir z &&
1213                 echo b >z/b &&
1214                 echo c >z/c &&
1215                 echo d >z/d &&
1216                 git add z &&
1217                 test_tick &&
1218                 git commit -m "O" &&
1219
1220                 git branch O &&
1221                 git branch A &&
1222                 git branch B &&
1223
1224                 git checkout A &&
1225                 git rm z/c &&
1226                 git rm z/d &&
1227                 test_tick &&
1228                 git commit -m "A" &&
1229
1230                 git checkout B &&
1231                 mkdir y &&
1232                 git mv z/b y/ &&
1233                 git mv z/c y/ &&
1234                 test_tick &&
1235                 git commit -m "B"
1236         )
1237 '
1238
1239 test_expect_success '6a-check: Tricky rename/delete' '
1240         (
1241                 cd 6a &&
1242
1243                 git checkout A^0 &&
1244
1245                 test_must_fail git merge -s recursive B^0 >out &&
1246                 test_i18ngrep "CONFLICT (rename/delete).*z/c.*y/c" out &&
1247
1248                 git ls-files -s >out &&
1249                 test_line_count = 2 out &&
1250                 git ls-files -u >out &&
1251                 test_line_count = 1 out &&
1252                 git ls-files -o >out &&
1253                 test_line_count = 1 out &&
1254
1255                 git rev-parse >actual \
1256                         :0:y/b :3:y/c &&
1257                 git rev-parse >expect \
1258                          O:z/b  O:z/c &&
1259                 test_cmp expect actual
1260         )
1261 '
1262
1263 # Testcase 6b, Same rename done on both sides
1264 #   (Related to testcases 6c and 8e)
1265 #   Commit O: z/{b,c}
1266 #   Commit A: y/{b,c}
1267 #   Commit B: y/{b,c}, z/d
1268 #   Expected: y/{b,c}, z/d
1269 #   Note: If we did directory rename detection here, we'd move z/d into y/,
1270 #         but B did that rename and still decided to put the file into z/,
1271 #         so we probably shouldn't apply directory rename detection for it.
1272
1273 test_expect_success '6b-setup: Same rename done on both sides' '
1274         test_create_repo 6b &&
1275         (
1276                 cd 6b &&
1277
1278                 mkdir z &&
1279                 echo b >z/b &&
1280                 echo c >z/c &&
1281                 git add z &&
1282                 test_tick &&
1283                 git commit -m "O" &&
1284
1285                 git branch O &&
1286                 git branch A &&
1287                 git branch B &&
1288
1289                 git checkout A &&
1290                 git mv z y &&
1291                 test_tick &&
1292                 git commit -m "A" &&
1293
1294                 git checkout B &&
1295                 git mv z y &&
1296                 mkdir z &&
1297                 echo d >z/d &&
1298                 git add z/d &&
1299                 test_tick &&
1300                 git commit -m "B"
1301         )
1302 '
1303
1304 test_expect_success '6b-check: Same rename done on both sides' '
1305         (
1306                 cd 6b &&
1307
1308                 git checkout A^0 &&
1309
1310                 git merge -s recursive B^0 &&
1311
1312                 git ls-files -s >out &&
1313                 test_line_count = 3 out &&
1314                 git ls-files -u >out &&
1315                 test_line_count = 0 out &&
1316                 git ls-files -o >out &&
1317                 test_line_count = 1 out &&
1318
1319                 git rev-parse >actual \
1320                         HEAD:y/b HEAD:y/c HEAD:z/d &&
1321                 git rev-parse >expect \
1322                         O:z/b    O:z/c    B:z/d &&
1323                 test_cmp expect actual
1324         )
1325 '
1326
1327 # Testcase 6c, Rename only done on same side
1328 #   (Related to testcases 6b and 8e)
1329 #   Commit O: z/{b,c}
1330 #   Commit A: z/{b,c} (no change)
1331 #   Commit B: y/{b,c}, z/d
1332 #   Expected: y/{b,c}, z/d
1333 #   NOTE: Seems obvious, but just checking that the implementation doesn't
1334 #         "accidentally detect a rename" and give us y/{b,c,d}.
1335
1336 test_expect_success '6c-setup: Rename only done on same side' '
1337         test_create_repo 6c &&
1338         (
1339                 cd 6c &&
1340
1341                 mkdir z &&
1342                 echo b >z/b &&
1343                 echo c >z/c &&
1344                 git add z &&
1345                 test_tick &&
1346                 git commit -m "O" &&
1347
1348                 git branch O &&
1349                 git branch A &&
1350                 git branch B &&
1351
1352                 git checkout A &&
1353                 test_tick &&
1354                 git commit --allow-empty -m "A" &&
1355
1356                 git checkout B &&
1357                 git mv z y &&
1358                 mkdir z &&
1359                 echo d >z/d &&
1360                 git add z/d &&
1361                 test_tick &&
1362                 git commit -m "B"
1363         )
1364 '
1365
1366 test_expect_success '6c-check: Rename only done on same side' '
1367         (
1368                 cd 6c &&
1369
1370                 git checkout A^0 &&
1371
1372                 git merge -s recursive B^0 &&
1373
1374                 git ls-files -s >out &&
1375                 test_line_count = 3 out &&
1376                 git ls-files -u >out &&
1377                 test_line_count = 0 out &&
1378                 git ls-files -o >out &&
1379                 test_line_count = 1 out &&
1380
1381                 git rev-parse >actual \
1382                         HEAD:y/b HEAD:y/c HEAD:z/d &&
1383                 git rev-parse >expect \
1384                         O:z/b    O:z/c    B:z/d &&
1385                 test_cmp expect actual
1386         )
1387 '
1388
1389 # Testcase 6d, We don't always want transitive renaming
1390 #   (Related to testcase 1c)
1391 #   Commit O: z/{b,c}, x/d
1392 #   Commit A: z/{b,c}, x/d (no change)
1393 #   Commit B: y/{b,c}, z/d
1394 #   Expected: y/{b,c}, z/d
1395 #   NOTE: Again, this seems obvious but just checking that the implementation
1396 #         doesn't "accidentally detect a rename" and give us y/{b,c,d}.
1397
1398 test_expect_success '6d-setup: We do not always want transitive renaming' '
1399         test_create_repo 6d &&
1400         (
1401                 cd 6d &&
1402
1403                 mkdir z &&
1404                 echo b >z/b &&
1405                 echo c >z/c &&
1406                 mkdir x &&
1407                 echo d >x/d &&
1408                 git add z x &&
1409                 test_tick &&
1410                 git commit -m "O" &&
1411
1412                 git branch O &&
1413                 git branch A &&
1414                 git branch B &&
1415
1416                 git checkout A &&
1417                 test_tick &&
1418                 git commit --allow-empty -m "A" &&
1419
1420                 git checkout B &&
1421                 git mv z y &&
1422                 git mv x z &&
1423                 test_tick &&
1424                 git commit -m "B"
1425         )
1426 '
1427
1428 test_expect_success '6d-check: We do not always want transitive renaming' '
1429         (
1430                 cd 6d &&
1431
1432                 git checkout A^0 &&
1433
1434                 git merge -s recursive B^0 &&
1435
1436                 git ls-files -s >out &&
1437                 test_line_count = 3 out &&
1438                 git ls-files -u >out &&
1439                 test_line_count = 0 out &&
1440                 git ls-files -o >out &&
1441                 test_line_count = 1 out &&
1442
1443                 git rev-parse >actual \
1444                         HEAD:y/b HEAD:y/c HEAD:z/d &&
1445                 git rev-parse >expect \
1446                         O:z/b    O:z/c    O:x/d &&
1447                 test_cmp expect actual
1448         )
1449 '
1450
1451 # Testcase 6e, Add/add from one-side
1452 #   Commit O: z/{b,c}
1453 #   Commit A: z/{b,c} (no change)
1454 #   Commit B: y/{b,c,d_1}, z/d_2
1455 #   Expected: y/{b,c,d_1}, z/d_2
1456 #   NOTE: Again, this seems obvious but just checking that the implementation
1457 #         doesn't "accidentally detect a rename" and give us y/{b,c} +
1458 #         add/add conflict on y/d_1 vs y/d_2.
1459
1460 test_expect_success '6e-setup: Add/add from one side' '
1461         test_create_repo 6e &&
1462         (
1463                 cd 6e &&
1464
1465                 mkdir z &&
1466                 echo b >z/b &&
1467                 echo c >z/c &&
1468                 git add z &&
1469                 test_tick &&
1470                 git commit -m "O" &&
1471
1472                 git branch O &&
1473                 git branch A &&
1474                 git branch B &&
1475
1476                 git checkout A &&
1477                 test_tick &&
1478                 git commit --allow-empty -m "A" &&
1479
1480                 git checkout B &&
1481                 git mv z y &&
1482                 echo d1 > y/d &&
1483                 mkdir z &&
1484                 echo d2 > z/d &&
1485                 git add y/d z/d &&
1486                 test_tick &&
1487                 git commit -m "B"
1488         )
1489 '
1490
1491 test_expect_success '6e-check: Add/add from one side' '
1492         (
1493                 cd 6e &&
1494
1495                 git checkout A^0 &&
1496
1497                 git merge -s recursive B^0 &&
1498
1499                 git ls-files -s >out &&
1500                 test_line_count = 4 out &&
1501                 git ls-files -u >out &&
1502                 test_line_count = 0 out &&
1503                 git ls-files -o >out &&
1504                 test_line_count = 1 out &&
1505
1506                 git rev-parse >actual \
1507                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:z/d &&
1508                 git rev-parse >expect \
1509                         O:z/b    O:z/c    B:y/d    B:z/d &&
1510                 test_cmp expect actual
1511         )
1512 '
1513
1514 ###########################################################################
1515 # Rules suggested by section 6:
1516 #
1517 #   Only apply implicit directory renames to directories if the other
1518 #   side of history is the one doing the renaming.
1519 ###########################################################################
1520
1521
1522 ###########################################################################
1523 # SECTION 7: More involved Edge/Corner cases
1524 #
1525 # The ruleset we have generated in the above sections seems to provide
1526 # well-defined merges.  But can we find edge/corner cases that either (a)
1527 # are harder for users to understand, or (b) have a resolution that is
1528 # non-intuitive or suboptimal?
1529 #
1530 # The testcases in this section dive into cases that I've tried to craft in
1531 # a way to find some that might be surprising to users or difficult for
1532 # them to understand (the next section will look at non-intuitive or
1533 # suboptimal merge results).  Some of the testcases are similar to ones
1534 # from past sections, but have been simplified to try to highlight error
1535 # messages using a "modified" path (due to the directory rename).  Are
1536 # users okay with these?
1537 #
1538 # In my opinion, testcases that are difficult to understand from this
1539 # section is due to difficulty in the testcase rather than the directory
1540 # renaming (similar to how t6042 and t6036 have difficult resolutions due
1541 # to the problem setup itself being complex).  And I don't think the
1542 # error messages are a problem.
1543 #
1544 # On the other hand, the testcases in section 8 worry me slightly more...
1545 ###########################################################################
1546
1547 # Testcase 7a, rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file
1548 #   Commit O: z/{b,c}
1549 #   Commit A: y/{b,c}
1550 #   Commit B: w/b, x/c, z/d
1551 #   Expected: y/d, CONFLICT(rename/rename for both z/b and z/c)
1552 #   NOTE: There's a rename of z/ here, y/ has more renames, so z/d -> y/d.
1553
1554 test_expect_success '7a-setup: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file' '
1555         test_create_repo 7a &&
1556         (
1557                 cd 7a &&
1558
1559                 mkdir z &&
1560                 echo b >z/b &&
1561                 echo c >z/c &&
1562                 git add z &&
1563                 test_tick &&
1564                 git commit -m "O" &&
1565
1566                 git branch O &&
1567                 git branch A &&
1568                 git branch B &&
1569
1570                 git checkout A &&
1571                 git mv z y &&
1572                 test_tick &&
1573                 git commit -m "A" &&
1574
1575                 git checkout B &&
1576                 mkdir w &&
1577                 mkdir x &&
1578                 git mv z/b w/ &&
1579                 git mv z/c x/ &&
1580                 echo d > z/d &&
1581                 git add z/d &&
1582                 test_tick &&
1583                 git commit -m "B"
1584         )
1585 '
1586
1587 test_expect_success '7a-check: rename-dir vs. rename-dir (NOT split evenly) PLUS add-other-file' '
1588         (
1589                 cd 7a &&
1590
1591                 git checkout A^0 &&
1592
1593                 test_must_fail git merge -s recursive B^0 >out &&
1594                 test_i18ngrep "CONFLICT (rename/rename).*z/b.*y/b.*w/b" out &&
1595                 test_i18ngrep "CONFLICT (rename/rename).*z/c.*y/c.*x/c" out &&
1596
1597                 git ls-files -s >out &&
1598                 test_line_count = 7 out &&
1599                 git ls-files -u >out &&
1600                 test_line_count = 6 out &&
1601                 git ls-files -o >out &&
1602                 test_line_count = 1 out &&
1603
1604                 git rev-parse >actual \
1605                         :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:x/c :0:y/d &&
1606                 git rev-parse >expect \
1607                          O:z/b  O:z/b  O:z/b  O:z/c  O:z/c  O:z/c  B:z/d &&
1608                 test_cmp expect actual &&
1609
1610                 git hash-object >actual \
1611                         y/b   w/b   y/c   x/c &&
1612                 git rev-parse >expect \
1613                         O:z/b O:z/b O:z/c O:z/c &&
1614                 test_cmp expect actual
1615         )
1616 '
1617
1618 # Testcase 7b, rename/rename(2to1), but only due to transitive rename
1619 #   (Related to testcase 1d)
1620 #   Commit O: z/{b,c},     x/d_1, w/d_2
1621 #   Commit A: y/{b,c,d_2}, x/d_1
1622 #   Commit B: z/{b,c,d_1},        w/d_2
1623 #   Expected: y/{b,c}, CONFLICT(rename/rename(2to1): x/d_1, w/d_2 -> y_d)
1624
1625 test_expect_success '7b-setup: rename/rename(2to1), but only due to transitive rename' '
1626         test_create_repo 7b &&
1627         (
1628                 cd 7b &&
1629
1630                 mkdir z &&
1631                 mkdir x &&
1632                 mkdir w &&
1633                 echo b >z/b &&
1634                 echo c >z/c &&
1635                 echo d1 > x/d &&
1636                 echo d2 > w/d &&
1637                 git add z x w &&
1638                 test_tick &&
1639                 git commit -m "O" &&
1640
1641                 git branch O &&
1642                 git branch A &&
1643                 git branch B &&
1644
1645                 git checkout A &&
1646                 git mv z y &&
1647                 git mv w/d y/ &&
1648                 test_tick &&
1649                 git commit -m "A" &&
1650
1651                 git checkout B &&
1652                 git mv x/d z/ &&
1653                 rmdir x &&
1654                 test_tick &&
1655                 git commit -m "B"
1656         )
1657 '
1658
1659 test_expect_success '7b-check: rename/rename(2to1), but only due to transitive rename' '
1660         (
1661                 cd 7b &&
1662
1663                 git checkout A^0 &&
1664
1665                 test_must_fail git merge -s recursive B^0 >out &&
1666                 test_i18ngrep "CONFLICT (rename/rename)" out &&
1667
1668                 git ls-files -s >out &&
1669                 test_line_count = 4 out &&
1670                 git ls-files -u >out &&
1671                 test_line_count = 2 out &&
1672                 git ls-files -o >out &&
1673                 test_line_count = 3 out &&
1674
1675                 git rev-parse >actual \
1676                         :0:y/b :0:y/c :2:y/d :3:y/d &&
1677                 git rev-parse >expect \
1678                          O:z/b  O:z/c  O:w/d  O:x/d &&
1679                 test_cmp expect actual &&
1680
1681                 test_path_is_missing y/d &&
1682                 test_path_is_file y/d~HEAD &&
1683                 test_path_is_file y/d~B^0 &&
1684
1685                 git hash-object >actual \
1686                         y/d~HEAD y/d~B^0 &&
1687                 git rev-parse >expect \
1688                         O:w/d    O:x/d &&
1689                 test_cmp expect actual
1690         )
1691 '
1692
1693 # Testcase 7c, rename/rename(1to...2or3); transitive rename may add complexity
1694 #   (Related to testcases 3b and 5c)
1695 #   Commit O: z/{b,c}, x/d
1696 #   Commit A: y/{b,c}, w/d
1697 #   Commit B: z/{b,c,d}
1698 #   Expected: y/{b,c}, CONFLICT(x/d -> w/d vs. y/d)
1699 #   NOTE: z/ was renamed to y/ so we do want to report
1700 #         neither CONFLICT(x/d -> w/d vs. z/d)
1701 #         nor CONFLiCT x/d -> w/d vs. y/d vs. z/d)
1702
1703 test_expect_success '7c-setup: rename/rename(1to...2or3); transitive rename may add complexity' '
1704         test_create_repo 7c &&
1705         (
1706                 cd 7c &&
1707
1708                 mkdir z &&
1709                 echo b >z/b &&
1710                 echo c >z/c &&
1711                 mkdir x &&
1712                 echo d >x/d &&
1713                 git add z x &&
1714                 test_tick &&
1715                 git commit -m "O" &&
1716
1717                 git branch O &&
1718                 git branch A &&
1719                 git branch B &&
1720
1721                 git checkout A &&
1722                 git mv z y &&
1723                 git mv x w &&
1724                 test_tick &&
1725                 git commit -m "A" &&
1726
1727                 git checkout B &&
1728                 git mv x/d z/ &&
1729                 rmdir x &&
1730                 test_tick &&
1731                 git commit -m "B"
1732         )
1733 '
1734
1735 test_expect_success '7c-check: rename/rename(1to...2or3); transitive rename may add complexity' '
1736         (
1737                 cd 7c &&
1738
1739                 git checkout A^0 &&
1740
1741                 test_must_fail git merge -s recursive B^0 >out &&
1742                 test_i18ngrep "CONFLICT (rename/rename).*x/d.*w/d.*y/d" out &&
1743
1744                 git ls-files -s >out &&
1745                 test_line_count = 5 out &&
1746                 git ls-files -u >out &&
1747                 test_line_count = 3 out &&
1748                 git ls-files -o >out &&
1749                 test_line_count = 1 out &&
1750
1751                 git rev-parse >actual \
1752                         :0:y/b :0:y/c :1:x/d :2:w/d :3:y/d &&
1753                 git rev-parse >expect \
1754                          O:z/b  O:z/c  O:x/d  O:x/d  O:x/d &&
1755                 test_cmp expect actual
1756         )
1757 '
1758
1759 # Testcase 7d, transitive rename involved in rename/delete; how is it reported?
1760 #   (Related somewhat to testcases 5b and 8d)
1761 #   Commit O: z/{b,c}, x/d
1762 #   Commit A: y/{b,c}
1763 #   Commit B: z/{b,c,d}
1764 #   Expected: y/{b,c}, CONFLICT(delete x/d vs rename to y/d)
1765 #   NOTE: z->y so NOT CONFLICT(delete x/d vs rename to z/d)
1766
1767 test_expect_success '7d-setup: transitive rename involved in rename/delete; how is it reported?' '
1768         test_create_repo 7d &&
1769         (
1770                 cd 7d &&
1771
1772                 mkdir z &&
1773                 echo b >z/b &&
1774                 echo c >z/c &&
1775                 mkdir x &&
1776                 echo d >x/d &&
1777                 git add z x &&
1778                 test_tick &&
1779                 git commit -m "O" &&
1780
1781                 git branch O &&
1782                 git branch A &&
1783                 git branch B &&
1784
1785                 git checkout A &&
1786                 git mv z y &&
1787                 git rm -rf x &&
1788                 test_tick &&
1789                 git commit -m "A" &&
1790
1791                 git checkout B &&
1792                 git mv x/d z/ &&
1793                 rmdir x &&
1794                 test_tick &&
1795                 git commit -m "B"
1796         )
1797 '
1798
1799 test_expect_success '7d-check: transitive rename involved in rename/delete; how is it reported?' '
1800         (
1801                 cd 7d &&
1802
1803                 git checkout A^0 &&
1804
1805                 test_must_fail git merge -s recursive B^0 >out &&
1806                 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1807
1808                 git ls-files -s >out &&
1809                 test_line_count = 3 out &&
1810                 git ls-files -u >out &&
1811                 test_line_count = 1 out &&
1812                 git ls-files -o >out &&
1813                 test_line_count = 1 out &&
1814
1815                 git rev-parse >actual \
1816                         :0:y/b :0:y/c :3:y/d &&
1817                 git rev-parse >expect \
1818                          O:z/b  O:z/c  O:x/d &&
1819                 test_cmp expect actual
1820         )
1821 '
1822
1823 # Testcase 7e, transitive rename in rename/delete AND dirs in the way
1824 #   (Very similar to 'both rename source and destination involved in D/F conflict' from t6022-merge-rename.sh)
1825 #   (Also related to testcases 9c and 9d)
1826 #   Commit O: z/{b,c},     x/d_1
1827 #   Commit A: y/{b,c,d/g}, x/d/f
1828 #   Commit B: z/{b,c,d_1}
1829 #   Expected: rename/delete(x/d_1->y/d_1 vs. None) + D/F conflict on y/d
1830 #             y/{b,c,d/g}, y/d_1~B^0, x/d/f
1831
1832 #   NOTE: The main path of interest here is d_1 and where it ends up, but
1833 #         this is actually a case that has two potential directory renames
1834 #         involved and D/F conflict(s), so it makes sense to walk through
1835 #         each step.
1836 #
1837 #         Commit A renames z/ -> y/.  Thus everything that B adds to z/
1838 #         should be instead moved to y/.  This gives us the D/F conflict on
1839 #         y/d because x/d_1 -> z/d_1 -> y/d_1 conflicts with y/d/g.
1840 #
1841 #         Further, commit B renames x/ -> z/, thus everything A adds to x/
1842 #         should instead be moved to z/...BUT we removed z/ and renamed it
1843 #         to y/, so maybe everything should move not from x/ to z/, but
1844 #         from x/ to z/ to y/.  Doing so might make sense from the logic so
1845 #         far, but note that commit A had both an x/ and a y/; it did the
1846 #         renaming of z/ to y/ and created x/d/f and it clearly made these
1847 #         things separate, so it doesn't make much sense to push these
1848 #         together.  Doing so is what I'd call a doubly transitive rename;
1849 #         see testcases 9c and 9d for further discussion of this issue and
1850 #         how it's resolved.
1851
1852 test_expect_success '7e-setup: transitive rename in rename/delete AND dirs in the way' '
1853         test_create_repo 7e &&
1854         (
1855                 cd 7e &&
1856
1857                 mkdir z &&
1858                 echo b >z/b &&
1859                 echo c >z/c &&
1860                 mkdir x &&
1861                 echo d1 >x/d &&
1862                 git add z x &&
1863                 test_tick &&
1864                 git commit -m "O" &&
1865
1866                 git branch O &&
1867                 git branch A &&
1868                 git branch B &&
1869
1870                 git checkout A &&
1871                 git mv z y &&
1872                 git rm x/d &&
1873                 mkdir -p x/d &&
1874                 mkdir -p y/d &&
1875                 echo f >x/d/f &&
1876                 echo g >y/d/g &&
1877                 git add x/d/f y/d/g &&
1878                 test_tick &&
1879                 git commit -m "A" &&
1880
1881                 git checkout B &&
1882                 git mv x/d z/ &&
1883                 rmdir x &&
1884                 test_tick &&
1885                 git commit -m "B"
1886         )
1887 '
1888
1889 test_expect_success '7e-check: transitive rename in rename/delete AND dirs in the way' '
1890         (
1891                 cd 7e &&
1892
1893                 git checkout A^0 &&
1894
1895                 test_must_fail git merge -s recursive B^0 >out &&
1896                 test_i18ngrep "CONFLICT (rename/delete).*x/d.*y/d" out &&
1897
1898                 git ls-files -s >out &&
1899                 test_line_count = 5 out &&
1900                 git ls-files -u >out &&
1901                 test_line_count = 1 out &&
1902                 git ls-files -o >out &&
1903                 test_line_count = 2 out &&
1904
1905                 git rev-parse >actual \
1906                         :0:x/d/f :0:y/d/g :0:y/b :0:y/c :3:y/d &&
1907                 git rev-parse >expect \
1908                          A:x/d/f  A:y/d/g  O:z/b  O:z/c  O:x/d &&
1909                 test_cmp expect actual &&
1910
1911                 git hash-object y/d~B^0 >actual &&
1912                 git rev-parse O:x/d >expect &&
1913                 test_cmp expect actual
1914         )
1915 '
1916
1917 ###########################################################################
1918 # SECTION 8: Suboptimal merges
1919 #
1920 # As alluded to in the last section, the ruleset we have built up for
1921 # detecting directory renames unfortunately has some special cases where it
1922 # results in slightly suboptimal or non-intuitive behavior.  This section
1923 # explores these cases.
1924 #
1925 # To be fair, we already had non-intuitive or suboptimal behavior for most
1926 # of these cases in git before introducing implicit directory rename
1927 # detection, but it'd be nice if there was a modified ruleset out there
1928 # that handled these cases a bit better.
1929 ###########################################################################
1930
1931 # Testcase 8a, Dual-directory rename, one into the others' way
1932 #   Commit O. x/{a,b},   y/{c,d}
1933 #   Commit A. x/{a,b,e}, y/{c,d,f}
1934 #   Commit B. y/{a,b},   z/{c,d}
1935 #
1936 # Possible Resolutions:
1937 #   w/o dir-rename detection: y/{a,b,f},   z/{c,d},   x/e
1938 #   Currently expected:       y/{a,b,e,f}, z/{c,d}
1939 #   Optimal:                  y/{a,b,e},   z/{c,d,f}
1940 #
1941 # Note: Both x and y got renamed and it'd be nice to detect both, and we do
1942 # better with directory rename detection than git did without, but the
1943 # simple rule from section 5 prevents me from handling this as optimally as
1944 # we potentially could.
1945
1946 test_expect_success '8a-setup: Dual-directory rename, one into the others way' '
1947         test_create_repo 8a &&
1948         (
1949                 cd 8a &&
1950
1951                 mkdir x &&
1952                 mkdir y &&
1953                 echo a >x/a &&
1954                 echo b >x/b &&
1955                 echo c >y/c &&
1956                 echo d >y/d &&
1957                 git add x y &&
1958                 test_tick &&
1959                 git commit -m "O" &&
1960
1961                 git branch O &&
1962                 git branch A &&
1963                 git branch B &&
1964
1965                 git checkout A &&
1966                 echo e >x/e &&
1967                 echo f >y/f &&
1968                 git add x/e y/f &&
1969                 test_tick &&
1970                 git commit -m "A" &&
1971
1972                 git checkout B &&
1973                 git mv y z &&
1974                 git mv x y &&
1975                 test_tick &&
1976                 git commit -m "B"
1977         )
1978 '
1979
1980 test_expect_success '8a-check: Dual-directory rename, one into the others way' '
1981         (
1982                 cd 8a &&
1983
1984                 git checkout A^0 &&
1985
1986                 git merge -s recursive B^0 &&
1987
1988                 git ls-files -s >out &&
1989                 test_line_count = 6 out &&
1990                 git ls-files -u >out &&
1991                 test_line_count = 0 out &&
1992                 git ls-files -o >out &&
1993                 test_line_count = 1 out &&
1994
1995                 git rev-parse >actual \
1996                         HEAD:y/a HEAD:y/b HEAD:y/e HEAD:y/f HEAD:z/c HEAD:z/d &&
1997                 git rev-parse >expect \
1998                         O:x/a    O:x/b    A:x/e    A:y/f    O:y/c    O:y/d &&
1999                 test_cmp expect actual
2000         )
2001 '
2002
2003 # Testcase 8b, Dual-directory rename, one into the others' way, with conflicting filenames
2004 #   Commit O. x/{a_1,b_1},     y/{a_2,b_2}
2005 #   Commit A. x/{a_1,b_1,e_1}, y/{a_2,b_2,e_2}
2006 #   Commit B. y/{a_1,b_1},     z/{a_2,b_2}
2007 #
2008 #   w/o dir-rename detection: y/{a_1,b_1,e_2}, z/{a_2,b_2}, x/e_1
2009 #   Currently expected:       <same>
2010 #   Scary:                    y/{a_1,b_1},     z/{a_2,b_2}, CONFLICT(add/add, e_1 vs. e_2)
2011 #   Optimal:                  y/{a_1,b_1,e_1}, z/{a_2,b_2,e_2}
2012 #
2013 # Note: Very similar to 8a, except instead of 'e' and 'f' in directories x and
2014 # y, both are named 'e'.  Without directory rename detection, neither file
2015 # moves directories.  Implement directory rename detection suboptimally, and
2016 # you get an add/add conflict, but both files were added in commit A, so this
2017 # is an add/add conflict where one side of history added both files --
2018 # something we can't represent in the index.  Obviously, we'd prefer the last
2019 # resolution, but our previous rules are too coarse to allow it.  Using both
2020 # the rules from section 4 and section 5 save us from the Scary resolution,
2021 # making us fall back to pre-directory-rename-detection behavior for both
2022 # e_1 and e_2.
2023
2024 test_expect_success '8b-setup: Dual-directory rename, one into the others way, with conflicting filenames' '
2025         test_create_repo 8b &&
2026         (
2027                 cd 8b &&
2028
2029                 mkdir x &&
2030                 mkdir y &&
2031                 echo a1 >x/a &&
2032                 echo b1 >x/b &&
2033                 echo a2 >y/a &&
2034                 echo b2 >y/b &&
2035                 git add x y &&
2036                 test_tick &&
2037                 git commit -m "O" &&
2038
2039                 git branch O &&
2040                 git branch A &&
2041                 git branch B &&
2042
2043                 git checkout A &&
2044                 echo e1 >x/e &&
2045                 echo e2 >y/e &&
2046                 git add x/e y/e &&
2047                 test_tick &&
2048                 git commit -m "A" &&
2049
2050                 git checkout B &&
2051                 git mv y z &&
2052                 git mv x y &&
2053                 test_tick &&
2054                 git commit -m "B"
2055         )
2056 '
2057
2058 test_expect_success '8b-check: Dual-directory rename, one into the others way, with conflicting filenames' '
2059         (
2060                 cd 8b &&
2061
2062                 git checkout A^0 &&
2063
2064                 git merge -s recursive B^0 &&
2065
2066                 git ls-files -s >out &&
2067                 test_line_count = 6 out &&
2068                 git ls-files -u >out &&
2069                 test_line_count = 0 out &&
2070                 git ls-files -o >out &&
2071                 test_line_count = 1 out &&
2072
2073                 git rev-parse >actual \
2074                         HEAD:y/a HEAD:y/b HEAD:z/a HEAD:z/b HEAD:x/e HEAD:y/e &&
2075                 git rev-parse >expect \
2076                         O:x/a    O:x/b    O:y/a    O:y/b    A:x/e    A:y/e &&
2077                 test_cmp expect actual
2078         )
2079 '
2080
2081 # Testcase 8c, modify/delete or rename+modify/delete?
2082 #   (Related to testcases 5b, 8d, and 9h)
2083 #   Commit O: z/{b,c,d}
2084 #   Commit A: y/{b,c}
2085 #   Commit B: z/{b,c,d_modified,e}
2086 #   Expected: y/{b,c,e}, CONFLICT(modify/delete: on z/d)
2087 #
2088 #   Note: It could easily be argued that the correct resolution here is
2089 #         y/{b,c,e}, CONFLICT(rename/delete: z/d -> y/d vs deleted)
2090 #         and that the modifed version of d should be present in y/ after
2091 #         the merge, just marked as conflicted.  Indeed, I previously did
2092 #         argue that.  But applying directory renames to the side of
2093 #         history where a file is merely modified results in spurious
2094 #         rename/rename(1to2) conflicts -- see testcase 9h.  See also
2095 #         notes in 8d.
2096
2097 test_expect_success '8c-setup: modify/delete or rename+modify/delete?' '
2098         test_create_repo 8c &&
2099         (
2100                 cd 8c &&
2101
2102                 mkdir z &&
2103                 echo b >z/b &&
2104                 echo c >z/c &&
2105                 test_seq 1 10 >z/d &&
2106                 git add z &&
2107                 test_tick &&
2108                 git commit -m "O" &&
2109
2110                 git branch O &&
2111                 git branch A &&
2112                 git branch B &&
2113
2114                 git checkout A &&
2115                 git rm z/d &&
2116                 git mv z y &&
2117                 test_tick &&
2118                 git commit -m "A" &&
2119
2120                 git checkout B &&
2121                 echo 11 >z/d &&
2122                 test_chmod +x z/d &&
2123                 echo e >z/e &&
2124                 git add z/d z/e &&
2125                 test_tick &&
2126                 git commit -m "B"
2127         )
2128 '
2129
2130 test_expect_success '8c-check: modify/delete or rename+modify/delete' '
2131         (
2132                 cd 8c &&
2133
2134                 git checkout A^0 &&
2135
2136                 test_must_fail git merge -s recursive B^0 >out &&
2137                 test_i18ngrep "CONFLICT (modify/delete).* z/d" out &&
2138
2139                 git ls-files -s >out &&
2140                 test_line_count = 5 out &&
2141                 git ls-files -u >out &&
2142                 test_line_count = 2 out &&
2143                 git ls-files -o >out &&
2144                 test_line_count = 1 out &&
2145
2146                 git rev-parse >actual \
2147                         :0:y/b :0:y/c :0:y/e :1:z/d :3:z/d &&
2148                 git rev-parse >expect \
2149                          O:z/b  O:z/c  B:z/e  O:z/d  B:z/d &&
2150                 test_cmp expect actual &&
2151
2152                 test_must_fail git rev-parse :2:z/d &&
2153                 git ls-files -s z/d | grep ^100755 &&
2154                 test_path_is_file z/d &&
2155                 test_path_is_missing y/d
2156         )
2157 '
2158
2159 # Testcase 8d, rename/delete...or not?
2160 #   (Related to testcase 5b; these may appear slightly inconsistent to users;
2161 #    Also related to testcases 7d and 7e)
2162 #   Commit O: z/{b,c,d}
2163 #   Commit A: y/{b,c}
2164 #   Commit B: z/{b,c,d,e}
2165 #   Expected: y/{b,c,e}
2166 #
2167 #   Note: It would also be somewhat reasonable to resolve this as
2168 #             y/{b,c,e}, CONFLICT(rename/delete: x/d -> y/d or deleted)
2169 #
2170 #   In this case, I'm leaning towards: commit A was the one that deleted z/d
2171 #   and it did the rename of z to y, so the two "conflicts" (rename vs.
2172 #   delete) are both coming from commit A, which is illogical.  Conflicts
2173 #   during merging are supposed to be about opposite sides doing things
2174 #   differently.
2175
2176 test_expect_success '8d-setup: rename/delete...or not?' '
2177         test_create_repo 8d &&
2178         (
2179                 cd 8d &&
2180
2181                 mkdir z &&
2182                 echo b >z/b &&
2183                 echo c >z/c &&
2184                 test_seq 1 10 >z/d &&
2185                 git add z &&
2186                 test_tick &&
2187                 git commit -m "O" &&
2188
2189                 git branch O &&
2190                 git branch A &&
2191                 git branch B &&
2192
2193                 git checkout A &&
2194                 git rm z/d &&
2195                 git mv z y &&
2196                 test_tick &&
2197                 git commit -m "A" &&
2198
2199                 git checkout B &&
2200                 echo e >z/e &&
2201                 git add z/e &&
2202                 test_tick &&
2203                 git commit -m "B"
2204         )
2205 '
2206
2207 test_expect_success '8d-check: rename/delete...or not?' '
2208         (
2209                 cd 8d &&
2210
2211                 git checkout A^0 &&
2212
2213                 git merge -s recursive B^0 &&
2214
2215                 git ls-files -s >out &&
2216                 test_line_count = 3 out &&
2217
2218                 git rev-parse >actual \
2219                         HEAD:y/b HEAD:y/c HEAD:y/e &&
2220                 git rev-parse >expect \
2221                         O:z/b    O:z/c    B:z/e &&
2222                 test_cmp expect actual
2223         )
2224 '
2225
2226 # Testcase 8e, Both sides rename, one side adds to original directory
2227 #   Commit O: z/{b,c}
2228 #   Commit A: y/{b,c}
2229 #   Commit B: w/{b,c}, z/d
2230 #
2231 # Possible Resolutions:
2232 #   w/o dir-rename detection: z/d, CONFLICT(z/b -> y/b vs. w/b),
2233 #                                  CONFLICT(z/c -> y/c vs. w/c)
2234 #   Currently expected:       y/d, CONFLICT(z/b -> y/b vs. w/b),
2235 #                                  CONFLICT(z/c -> y/c vs. w/c)
2236 #   Optimal:                  ??
2237 #
2238 # Notes: In commit A, directory z got renamed to y.  In commit B, directory z
2239 #        did NOT get renamed; the directory is still present; instead it is
2240 #        considered to have just renamed a subset of paths in directory z
2241 #        elsewhere.  Therefore, the directory rename done in commit A to z/
2242 #        applies to z/d and maps it to y/d.
2243 #
2244 #        It's possible that users would get confused about this, but what
2245 #        should we do instead?  Silently leaving at z/d seems just as bad or
2246 #        maybe even worse.  Perhaps we could print a big warning about z/d
2247 #        and how we're moving to y/d in this case, but when I started thinking
2248 #        about the ramifications of doing that, I didn't know how to rule out
2249 #        that opening other weird edge and corner cases so I just punted.
2250
2251 test_expect_success '8e-setup: Both sides rename, one side adds to original directory' '
2252         test_create_repo 8e &&
2253         (
2254                 cd 8e &&
2255
2256                 mkdir z &&
2257                 echo b >z/b &&
2258                 echo c >z/c &&
2259                 git add z &&
2260                 test_tick &&
2261                 git commit -m "O" &&
2262
2263                 git branch O &&
2264                 git branch A &&
2265                 git branch B &&
2266
2267                 git checkout A &&
2268                 git mv z y &&
2269                 test_tick &&
2270                 git commit -m "A" &&
2271
2272                 git checkout B &&
2273                 git mv z w &&
2274                 mkdir z &&
2275                 echo d >z/d &&
2276                 git add z/d &&
2277                 test_tick &&
2278                 git commit -m "B"
2279         )
2280 '
2281
2282 test_expect_success '8e-check: Both sides rename, one side adds to original directory' '
2283         (
2284                 cd 8e &&
2285
2286                 git checkout A^0 &&
2287
2288                 test_must_fail git merge -s recursive B^0 >out 2>err &&
2289                 test_i18ngrep CONFLICT.*rename/rename.*z/c.*y/c.*w/c out &&
2290                 test_i18ngrep CONFLICT.*rename/rename.*z/b.*y/b.*w/b out &&
2291
2292                 git ls-files -s >out &&
2293                 test_line_count = 7 out &&
2294                 git ls-files -u >out &&
2295                 test_line_count = 6 out &&
2296                 git ls-files -o >out &&
2297                 test_line_count = 2 out &&
2298
2299                 git rev-parse >actual \
2300                         :1:z/b :2:y/b :3:w/b :1:z/c :2:y/c :3:w/c :0:y/d &&
2301                 git rev-parse >expect \
2302                          O:z/b  O:z/b  O:z/b  O:z/c  O:z/c  O:z/c  B:z/d &&
2303                 test_cmp expect actual &&
2304
2305                 git hash-object >actual \
2306                         y/b   w/b   y/c   w/c &&
2307                 git rev-parse >expect \
2308                         O:z/b O:z/b O:z/c O:z/c &&
2309                 test_cmp expect actual &&
2310
2311                 test_path_is_missing z/b &&
2312                 test_path_is_missing z/c
2313         )
2314 '
2315
2316 ###########################################################################
2317 # SECTION 9: Other testcases
2318 #
2319 # This section consists of miscellaneous testcases I thought of during
2320 # the implementation which round out the testing.
2321 ###########################################################################
2322
2323 # Testcase 9a, Inner renamed directory within outer renamed directory
2324 #   (Related to testcase 1f)
2325 #   Commit O: z/{b,c,d/{e,f,g}}
2326 #   Commit A: y/{b,c}, x/w/{e,f,g}
2327 #   Commit B: z/{b,c,d/{e,f,g,h},i}
2328 #   Expected: y/{b,c,i}, x/w/{e,f,g,h}
2329 #   NOTE: The only reason this one is interesting is because when a directory
2330 #         is split into multiple other directories, we determine by the weight
2331 #         of which one had the most paths going to it.  A naive implementation
2332 #         of that could take the new file in commit B at z/i to x/w/i or x/i.
2333
2334 test_expect_success '9a-setup: Inner renamed directory within outer renamed directory' '
2335         test_create_repo 9a &&
2336         (
2337                 cd 9a &&
2338
2339                 mkdir -p z/d &&
2340                 echo b >z/b &&
2341                 echo c >z/c &&
2342                 echo e >z/d/e &&
2343                 echo f >z/d/f &&
2344                 echo g >z/d/g &&
2345                 git add z &&
2346                 test_tick &&
2347                 git commit -m "O" &&
2348
2349                 git branch O &&
2350                 git branch A &&
2351                 git branch B &&
2352
2353                 git checkout A &&
2354                 mkdir x &&
2355                 git mv z/d x/w &&
2356                 git mv z y &&
2357                 test_tick &&
2358                 git commit -m "A" &&
2359
2360                 git checkout B &&
2361                 echo h >z/d/h &&
2362                 echo i >z/i &&
2363                 git add z &&
2364                 test_tick &&
2365                 git commit -m "B"
2366         )
2367 '
2368
2369 test_expect_success '9a-check: Inner renamed directory within outer renamed directory' '
2370         (
2371                 cd 9a &&
2372
2373                 git checkout A^0 &&
2374
2375                 git merge -s recursive B^0 &&
2376
2377                 git ls-files -s >out &&
2378                 test_line_count = 7 out &&
2379                 git ls-files -u >out &&
2380                 test_line_count = 0 out &&
2381                 git ls-files -o >out &&
2382                 test_line_count = 1 out &&
2383
2384                 git rev-parse >actual \
2385                         HEAD:y/b HEAD:y/c HEAD:y/i &&
2386                 git rev-parse >expect \
2387                         O:z/b    O:z/c    B:z/i &&
2388                 test_cmp expect actual &&
2389
2390                 git rev-parse >actual \
2391                         HEAD:x/w/e HEAD:x/w/f HEAD:x/w/g HEAD:x/w/h &&
2392                 git rev-parse >expect \
2393                         O:z/d/e    O:z/d/f    O:z/d/g    B:z/d/h &&
2394                 test_cmp expect actual
2395         )
2396 '
2397
2398 # Testcase 9b, Transitive rename with content merge
2399 #   (Related to testcase 1c)
2400 #   Commit O: z/{b,c},   x/d_1
2401 #   Commit A: y/{b,c},   x/d_2
2402 #   Commit B: z/{b,c,d_3}
2403 #   Expected: y/{b,c,d_merged}
2404
2405 test_expect_success '9b-setup: Transitive rename with content merge' '
2406         test_create_repo 9b &&
2407         (
2408                 cd 9b &&
2409
2410                 mkdir z &&
2411                 echo b >z/b &&
2412                 echo c >z/c &&
2413                 mkdir x &&
2414                 test_seq 1 10 >x/d &&
2415                 git add z x &&
2416                 test_tick &&
2417                 git commit -m "O" &&
2418
2419                 git branch O &&
2420                 git branch A &&
2421                 git branch B &&
2422
2423                 git checkout A &&
2424                 git mv z y &&
2425                 test_seq 1 11 >x/d &&
2426                 git add x/d &&
2427                 test_tick &&
2428                 git commit -m "A" &&
2429
2430                 git checkout B &&
2431                 test_seq 0 10 >x/d &&
2432                 git mv x/d z/d &&
2433                 git add z/d &&
2434                 test_tick &&
2435                 git commit -m "B"
2436         )
2437 '
2438
2439 test_expect_success '9b-check: Transitive rename with content merge' '
2440         (
2441                 cd 9b &&
2442
2443                 git checkout A^0 &&
2444
2445                 git merge -s recursive B^0 &&
2446
2447                 git ls-files -s >out &&
2448                 test_line_count = 3 out &&
2449
2450                 test_seq 0 11 >expected &&
2451                 test_cmp expected y/d &&
2452                 git add expected &&
2453                 git rev-parse >actual \
2454                         HEAD:y/b HEAD:y/c HEAD:y/d &&
2455                 git rev-parse >expect \
2456                         O:z/b    O:z/c    :0:expected &&
2457                 test_cmp expect actual &&
2458                 test_must_fail git rev-parse HEAD:x/d &&
2459                 test_must_fail git rev-parse HEAD:z/d &&
2460                 test_path_is_missing z/d &&
2461
2462                 test $(git rev-parse HEAD:y/d) != $(git rev-parse O:x/d) &&
2463                 test $(git rev-parse HEAD:y/d) != $(git rev-parse A:x/d) &&
2464                 test $(git rev-parse HEAD:y/d) != $(git rev-parse B:z/d)
2465         )
2466 '
2467
2468 # Testcase 9c, Doubly transitive rename?
2469 #   (Related to testcase 1c, 7e, and 9d)
2470 #   Commit O: z/{b,c},     x/{d,e},    w/f
2471 #   Commit A: y/{b,c},     x/{d,e,f,g}
2472 #   Commit B: z/{b,c,d,e},             w/f
2473 #   Expected: y/{b,c,d,e}, x/{f,g}
2474 #
2475 #   NOTE: x/f and x/g may be slightly confusing here.  The rename from w/f to
2476 #         x/f is clear.  Let's look beyond that.  Here's the logic:
2477 #            Commit B renamed x/ -> z/
2478 #            Commit A renamed z/ -> y/
2479 #         So, we could possibly further rename x/f to z/f to y/f, a doubly
2480 #         transient rename.  However, where does it end?  We can chain these
2481 #         indefinitely (see testcase 9d).  What if there is a D/F conflict
2482 #         at z/f/ or y/f/?  Or just another file conflict at one of those
2483 #         paths?  In the case of an N-long chain of transient renamings,
2484 #         where do we "abort" the rename at?  Can the user make sense of
2485 #         the resulting conflict and resolve it?
2486 #
2487 #         To avoid this confusion I use the simple rule that if the other side
2488 #         of history did a directory rename to a path that your side renamed
2489 #         away, then ignore that particular rename from the other side of
2490 #         history for any implicit directory renames.
2491
2492 test_expect_success '9c-setup: Doubly transitive rename?' '
2493         test_create_repo 9c &&
2494         (
2495                 cd 9c &&
2496
2497                 mkdir z &&
2498                 echo b >z/b &&
2499                 echo c >z/c &&
2500                 mkdir x &&
2501                 echo d >x/d &&
2502                 echo e >x/e &&
2503                 mkdir w &&
2504                 echo f >w/f &&
2505                 git add z x w &&
2506                 test_tick &&
2507                 git commit -m "O" &&
2508
2509                 git branch O &&
2510                 git branch A &&
2511                 git branch B &&
2512
2513                 git checkout A &&
2514                 git mv z y &&
2515                 git mv w/f x/ &&
2516                 echo g >x/g &&
2517                 git add x/g &&
2518                 test_tick &&
2519                 git commit -m "A" &&
2520
2521                 git checkout B &&
2522                 git mv x/d z/d &&
2523                 git mv x/e z/e &&
2524                 test_tick &&
2525                 git commit -m "B"
2526         )
2527 '
2528
2529 test_expect_success '9c-check: Doubly transitive rename?' '
2530         (
2531                 cd 9c &&
2532
2533                 git checkout A^0 &&
2534
2535                 git merge -s recursive B^0 >out &&
2536                 test_i18ngrep "WARNING: Avoiding applying x -> z rename to x/f" out &&
2537
2538                 git ls-files -s >out &&
2539                 test_line_count = 6 out &&
2540                 git ls-files -o >out &&
2541                 test_line_count = 1 out &&
2542
2543                 git rev-parse >actual \
2544                         HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e HEAD:x/f HEAD:x/g &&
2545                 git rev-parse >expect \
2546                         O:z/b    O:z/c    O:x/d    O:x/e    O:w/f    A:x/g &&
2547                 test_cmp expect actual
2548         )
2549 '
2550
2551 # Testcase 9d, N-fold transitive rename?
2552 #   (Related to testcase 9c...and 1c and 7e)
2553 #   Commit O: z/a, y/b, x/c, w/d, v/e, u/f
2554 #   Commit A:  y/{a,b},  w/{c,d},  u/{e,f}
2555 #   Commit B: z/{a,t}, x/{b,c}, v/{d,e}, u/f
2556 #   Expected: <see NOTE first>
2557 #
2558 #   NOTE: z/ -> y/ (in commit A)
2559 #         y/ -> x/ (in commit B)
2560 #         x/ -> w/ (in commit A)
2561 #         w/ -> v/ (in commit B)
2562 #         v/ -> u/ (in commit A)
2563 #         So, if we add a file to z, say z/t, where should it end up?  In u?
2564 #         What if there's another file or directory named 't' in one of the
2565 #         intervening directories and/or in u itself?  Also, shouldn't the
2566 #         same logic that places 't' in u/ also move ALL other files to u/?
2567 #         What if there are file or directory conflicts in any of them?  If
2568 #         we attempted to do N-way (N-fold? N-ary? N-uple?) transitive renames
2569 #         like this, would the user have any hope of understanding any
2570 #         conflicts or how their working tree ended up?  I think not, so I'm
2571 #         ruling out N-ary transitive renames for N>1.
2572 #
2573 #   Therefore our expected result is:
2574 #     z/t, y/a, x/b, w/c, u/d, u/e, u/f
2575 #   The reason that v/d DOES get transitively renamed to u/d is that u/ isn't
2576 #   renamed somewhere.  A slightly sub-optimal result, but it uses fairly
2577 #   simple rules that are consistent with what we need for all the other
2578 #   testcases and simplifies things for the user.
2579
2580 test_expect_success '9d-setup: N-way transitive rename?' '
2581         test_create_repo 9d &&
2582         (
2583                 cd 9d &&
2584
2585                 mkdir z y x w v u &&
2586                 echo a >z/a &&
2587                 echo b >y/b &&
2588                 echo c >x/c &&
2589                 echo d >w/d &&
2590                 echo e >v/e &&
2591                 echo f >u/f &&
2592                 git add z y x w v u &&
2593                 test_tick &&
2594                 git commit -m "O" &&
2595
2596                 git branch O &&
2597                 git branch A &&
2598                 git branch B &&
2599
2600                 git checkout A &&
2601                 git mv z/a y/ &&
2602                 git mv x/c w/ &&
2603                 git mv v/e u/ &&
2604                 test_tick &&
2605                 git commit -m "A" &&
2606
2607                 git checkout B &&
2608                 echo t >z/t &&
2609                 git mv y/b x/ &&
2610                 git mv w/d v/ &&
2611                 git add z/t &&
2612                 test_tick &&
2613                 git commit -m "B"
2614         )
2615 '
2616
2617 test_expect_success '9d-check: N-way transitive rename?' '
2618         (
2619                 cd 9d &&
2620
2621                 git checkout A^0 &&
2622
2623                 git merge -s recursive B^0 >out &&
2624                 test_i18ngrep "WARNING: Avoiding applying z -> y rename to z/t" out &&
2625                 test_i18ngrep "WARNING: Avoiding applying y -> x rename to y/a" out &&
2626                 test_i18ngrep "WARNING: Avoiding applying x -> w rename to x/b" out &&
2627                 test_i18ngrep "WARNING: Avoiding applying w -> v rename to w/c" out &&
2628
2629                 git ls-files -s >out &&
2630                 test_line_count = 7 out &&
2631                 git ls-files -o >out &&
2632                 test_line_count = 1 out &&
2633
2634                 git rev-parse >actual \
2635                         HEAD:z/t \
2636                         HEAD:y/a HEAD:x/b HEAD:w/c \
2637                         HEAD:u/d HEAD:u/e HEAD:u/f &&
2638                 git rev-parse >expect \
2639                         B:z/t    \
2640                         O:z/a    O:y/b    O:x/c    \
2641                         O:w/d    O:v/e    A:u/f &&
2642                 test_cmp expect actual
2643         )
2644 '
2645
2646 # Testcase 9e, N-to-1 whammo
2647 #   (Related to testcase 9c...and 1c and 7e)
2648 #   Commit O: dir1/{a,b}, dir2/{d,e}, dir3/{g,h}, dirN/{j,k}
2649 #   Commit A: dir1/{a,b,c,yo}, dir2/{d,e,f,yo}, dir3/{g,h,i,yo}, dirN/{j,k,l,yo}
2650 #   Commit B: combined/{a,b,d,e,g,h,j,k}
2651 #   Expected: combined/{a,b,c,d,e,f,g,h,i,j,k,l}, CONFLICT(Nto1) warnings,
2652 #             dir1/yo, dir2/yo, dir3/yo, dirN/yo
2653
2654 test_expect_success '9e-setup: N-to-1 whammo' '
2655         test_create_repo 9e &&
2656         (
2657                 cd 9e &&
2658
2659                 mkdir dir1 dir2 dir3 dirN &&
2660                 echo a >dir1/a &&
2661                 echo b >dir1/b &&
2662                 echo d >dir2/d &&
2663                 echo e >dir2/e &&
2664                 echo g >dir3/g &&
2665                 echo h >dir3/h &&
2666                 echo j >dirN/j &&
2667                 echo k >dirN/k &&
2668                 git add dir* &&
2669                 test_tick &&
2670                 git commit -m "O" &&
2671
2672                 git branch O &&
2673                 git branch A &&
2674                 git branch B &&
2675
2676                 git checkout A &&
2677                 echo c  >dir1/c &&
2678                 echo yo >dir1/yo &&
2679                 echo f  >dir2/f &&
2680                 echo yo >dir2/yo &&
2681                 echo i  >dir3/i &&
2682                 echo yo >dir3/yo &&
2683                 echo l  >dirN/l &&
2684                 echo yo >dirN/yo &&
2685                 git add dir* &&
2686                 test_tick &&
2687                 git commit -m "A" &&
2688
2689                 git checkout B &&
2690                 git mv dir1 combined &&
2691                 git mv dir2/* combined/ &&
2692                 git mv dir3/* combined/ &&
2693                 git mv dirN/* combined/ &&
2694                 test_tick &&
2695                 git commit -m "B"
2696         )
2697 '
2698
2699 test_expect_success C_LOCALE_OUTPUT '9e-check: N-to-1 whammo' '
2700         (
2701                 cd 9e &&
2702
2703                 git checkout A^0 &&
2704
2705                 test_must_fail git merge -s recursive B^0 >out &&
2706                 grep "CONFLICT (implicit dir rename): Cannot map more than one path to combined/yo" out >error_line &&
2707                 grep -q dir1/yo error_line &&
2708                 grep -q dir2/yo error_line &&
2709                 grep -q dir3/yo error_line &&
2710                 grep -q dirN/yo error_line &&
2711
2712                 git ls-files -s >out &&
2713                 test_line_count = 16 out &&
2714                 git ls-files -u >out &&
2715                 test_line_count = 0 out &&
2716                 git ls-files -o >out &&
2717                 test_line_count = 2 out &&
2718
2719                 git rev-parse >actual \
2720                         :0:combined/a :0:combined/b :0:combined/c \
2721                         :0:combined/d :0:combined/e :0:combined/f \
2722                         :0:combined/g :0:combined/h :0:combined/i \
2723                         :0:combined/j :0:combined/k :0:combined/l &&
2724                 git rev-parse >expect \
2725                          O:dir1/a      O:dir1/b      A:dir1/c \
2726                          O:dir2/d      O:dir2/e      A:dir2/f \
2727                          O:dir3/g      O:dir3/h      A:dir3/i \
2728                          O:dirN/j      O:dirN/k      A:dirN/l &&
2729                 test_cmp expect actual &&
2730
2731                 git rev-parse >actual \
2732                         :0:dir1/yo :0:dir2/yo :0:dir3/yo :0:dirN/yo &&
2733                 git rev-parse >expect \
2734                          A:dir1/yo  A:dir2/yo  A:dir3/yo  A:dirN/yo &&
2735                 test_cmp expect actual
2736         )
2737 '
2738
2739 # Testcase 9f, Renamed directory that only contained immediate subdirs
2740 #   (Related to testcases 1e & 9g)
2741 #   Commit O: goal/{a,b}/$more_files
2742 #   Commit A: priority/{a,b}/$more_files
2743 #   Commit B: goal/{a,b}/$more_files, goal/c
2744 #   Expected: priority/{a,b}/$more_files, priority/c
2745
2746 test_expect_success '9f-setup: Renamed directory that only contained immediate subdirs' '
2747         test_create_repo 9f &&
2748         (
2749                 cd 9f &&
2750
2751                 mkdir -p goal/a &&
2752                 mkdir -p goal/b &&
2753                 echo foo >goal/a/foo &&
2754                 echo bar >goal/b/bar &&
2755                 echo baz >goal/b/baz &&
2756                 git add goal &&
2757                 test_tick &&
2758                 git commit -m "O" &&
2759
2760                 git branch O &&
2761                 git branch A &&
2762                 git branch B &&
2763
2764                 git checkout A &&
2765                 git mv goal/ priority &&
2766                 test_tick &&
2767                 git commit -m "A" &&
2768
2769                 git checkout B &&
2770                 echo c >goal/c &&
2771                 git add goal/c &&
2772                 test_tick &&
2773                 git commit -m "B"
2774         )
2775 '
2776
2777 test_expect_success '9f-check: Renamed directory that only contained immediate subdirs' '
2778         (
2779                 cd 9f &&
2780
2781                 git checkout A^0 &&
2782
2783                 git merge -s recursive B^0 &&
2784
2785                 git ls-files -s >out &&
2786                 test_line_count = 4 out &&
2787
2788                 git rev-parse >actual \
2789                         HEAD:priority/a/foo \
2790                         HEAD:priority/b/bar \
2791                         HEAD:priority/b/baz \
2792                         HEAD:priority/c &&
2793                 git rev-parse >expect \
2794                         O:goal/a/foo \
2795                         O:goal/b/bar \
2796                         O:goal/b/baz \
2797                         B:goal/c &&
2798                 test_cmp expect actual &&
2799                 test_must_fail git rev-parse HEAD:goal/c
2800         )
2801 '
2802
2803 # Testcase 9g, Renamed directory that only contained immediate subdirs, immediate subdirs renamed
2804 #   (Related to testcases 1e & 9f)
2805 #   Commit O: goal/{a,b}/$more_files
2806 #   Commit A: priority/{alpha,bravo}/$more_files
2807 #   Commit B: goal/{a,b}/$more_files, goal/c
2808 #   Expected: priority/{alpha,bravo}/$more_files, priority/c
2809
2810 test_expect_success '9g-setup: Renamed directory that only contained immediate subdirs, immediate subdirs renamed' '
2811         test_create_repo 9g &&
2812         (
2813                 cd 9g &&
2814
2815                 mkdir -p goal/a &&
2816                 mkdir -p goal/b &&
2817                 echo foo >goal/a/foo &&
2818                 echo bar >goal/b/bar &&
2819                 echo baz >goal/b/baz &&
2820                 git add goal &&
2821                 test_tick &&
2822                 git commit -m "O" &&
2823
2824                 git branch O &&
2825                 git branch A &&
2826                 git branch B &&
2827
2828                 git checkout A &&
2829                 mkdir priority &&
2830                 git mv goal/a/ priority/alpha &&
2831                 git mv goal/b/ priority/beta &&
2832                 rmdir goal/ &&
2833                 test_tick &&
2834                 git commit -m "A" &&
2835
2836                 git checkout B &&
2837                 echo c >goal/c &&
2838                 git add goal/c &&
2839                 test_tick &&
2840                 git commit -m "B"
2841         )
2842 '
2843
2844 test_expect_failure '9g-check: Renamed directory that only contained immediate subdirs, immediate subdirs renamed' '
2845         (
2846                 cd 9g &&
2847
2848                 git checkout A^0 &&
2849
2850                 git merge -s recursive B^0 &&
2851
2852                 git ls-files -s >out &&
2853                 test_line_count = 4 out &&
2854
2855                 git rev-parse >actual \
2856                         HEAD:priority/alpha/foo \
2857                         HEAD:priority/beta/bar  \
2858                         HEAD:priority/beta/baz  \
2859                         HEAD:priority/c &&
2860                 git rev-parse >expect \
2861                         O:goal/a/foo \
2862                         O:goal/b/bar \
2863                         O:goal/b/baz \
2864                         B:goal/c &&
2865                 test_cmp expect actual &&
2866                 test_must_fail git rev-parse HEAD:goal/c
2867         )
2868 '
2869
2870 # Testcase 9h, Avoid implicit rename if involved as source on other side
2871 #   (Extremely closely related to testcase 3a)
2872 #   Commit O: z/{b,c,d_1}
2873 #   Commit A: z/{b,c,d_2}
2874 #   Commit B: y/{b,c}, x/d_1
2875 #   Expected: y/{b,c}, x/d_2
2876 #   NOTE: If we applied the z/ -> y/ rename to z/d, then we'd end up with
2877 #         a rename/rename(1to2) conflict (z/d -> y/d vs. x/d)
2878 test_expect_success '9h-setup: Avoid dir rename on merely modified path' '
2879         test_create_repo 9h &&
2880         (
2881                 cd 9h &&
2882
2883                 mkdir z &&
2884                 echo b >z/b &&
2885                 echo c >z/c &&
2886                 printf "1\n2\n3\n4\n5\n6\n7\n8\nd\n" >z/d &&
2887                 git add z &&
2888                 test_tick &&
2889                 git commit -m "O" &&
2890
2891                 git branch O &&
2892                 git branch A &&
2893                 git branch B &&
2894
2895                 git checkout A &&
2896                 test_tick &&
2897                 echo more >>z/d &&
2898                 git add z/d &&
2899                 git commit -m "A" &&
2900
2901                 git checkout B &&
2902                 mkdir y &&
2903                 mkdir x &&
2904                 git mv z/b y/ &&
2905                 git mv z/c y/ &&
2906                 git mv z/d x/ &&
2907                 rmdir z &&
2908                 test_tick &&
2909                 git commit -m "B"
2910         )
2911 '
2912
2913 test_expect_success '9h-check: Avoid dir rename on merely modified path' '
2914         (
2915                 cd 9h &&
2916
2917                 git checkout A^0 &&
2918
2919                 git merge -s recursive B^0 &&
2920
2921                 git ls-files -s >out &&
2922                 test_line_count = 3 out &&
2923
2924                 git rev-parse >actual \
2925                         HEAD:y/b HEAD:y/c HEAD:x/d &&
2926                 git rev-parse >expect \
2927                         O:z/b    O:z/c    A:z/d &&
2928                 test_cmp expect actual
2929         )
2930 '
2931
2932 ###########################################################################
2933 # Rules suggested by section 9:
2934 #
2935 #   If the other side of history did a directory rename to a path that your
2936 #   side renamed away, then ignore that particular rename from the other
2937 #   side of history for any implicit directory renames.
2938 ###########################################################################
2939
2940 ###########################################################################
2941 # SECTION 10: Handling untracked files
2942 #
2943 # unpack_trees(), upon which the recursive merge algorithm is based, aborts
2944 # the operation if untracked or dirty files would be deleted or overwritten
2945 # by the merge.  Unfortunately, unpack_trees() does not understand renames,
2946 # and if it doesn't abort, then it muddies up the working directory before
2947 # we even get to the point of detecting renames, so we need some special
2948 # handling, at least in the case of directory renames.
2949 ###########################################################################
2950
2951 # Testcase 10a, Overwrite untracked: normal rename/delete
2952 #   Commit O: z/{b,c_1}
2953 #   Commit A: z/b + untracked z/c + untracked z/d
2954 #   Commit B: z/{b,d_1}
2955 #   Expected: Aborted Merge +
2956 #       ERROR_MSG(untracked working tree files would be overwritten by merge)
2957
2958 test_expect_success '10a-setup: Overwrite untracked with normal rename/delete' '
2959         test_create_repo 10a &&
2960         (
2961                 cd 10a &&
2962
2963                 mkdir z &&
2964                 echo b >z/b &&
2965                 echo c >z/c &&
2966                 git add z &&
2967                 test_tick &&
2968                 git commit -m "O" &&
2969
2970                 git branch O &&
2971                 git branch A &&
2972                 git branch B &&
2973
2974                 git checkout A &&
2975                 git rm z/c &&
2976                 test_tick &&
2977                 git commit -m "A" &&
2978
2979                 git checkout B &&
2980                 git mv z/c z/d &&
2981                 test_tick &&
2982                 git commit -m "B"
2983         )
2984 '
2985
2986 test_expect_success '10a-check: Overwrite untracked with normal rename/delete' '
2987         (
2988                 cd 10a &&
2989
2990                 git checkout A^0 &&
2991                 echo very >z/c &&
2992                 echo important >z/d &&
2993
2994                 test_must_fail git merge -s recursive B^0 >out 2>err &&
2995                 test_i18ngrep "The following untracked working tree files would be overwritten by merge" err &&
2996
2997                 git ls-files -s >out &&
2998                 test_line_count = 1 out &&
2999                 git ls-files -o >out &&
3000                 test_line_count = 4 out &&
3001
3002                 echo very >expect &&
3003                 test_cmp expect z/c &&
3004
3005                 echo important >expect &&
3006                 test_cmp expect z/d &&
3007
3008                 git rev-parse HEAD:z/b >actual &&
3009                 git rev-parse O:z/b >expect &&
3010                 test_cmp expect actual
3011         )
3012 '
3013
3014 # Testcase 10b, Overwrite untracked: dir rename + delete
3015 #   Commit O: z/{b,c_1}
3016 #   Commit A: y/b + untracked y/{c,d,e}
3017 #   Commit B: z/{b,d_1,e}
3018 #   Expected: Failed Merge; y/b + untracked y/c + untracked y/d on disk +
3019 #             z/c_1 -> z/d_1 rename recorded at stage 3 for y/d +
3020 #       ERROR_MSG(refusing to lose untracked file at 'y/d')
3021
3022 test_expect_success '10b-setup: Overwrite untracked with dir rename + delete' '
3023         test_create_repo 10b &&
3024         (
3025                 cd 10b &&
3026
3027                 mkdir z &&
3028                 echo b >z/b &&
3029                 echo c >z/c &&
3030                 git add z &&
3031                 test_tick &&
3032                 git commit -m "O" &&
3033
3034                 git branch O &&
3035                 git branch A &&
3036                 git branch B &&
3037
3038                 git checkout A &&
3039                 git rm z/c &&
3040                 git mv z/ y/ &&
3041                 test_tick &&
3042                 git commit -m "A" &&
3043
3044                 git checkout B &&
3045                 git mv z/c z/d &&
3046                 echo e >z/e &&
3047                 git add z/e &&
3048                 test_tick &&
3049                 git commit -m "B"
3050         )
3051 '
3052
3053 test_expect_success '10b-check: Overwrite untracked with dir rename + delete' '
3054         (
3055                 cd 10b &&
3056
3057                 git checkout A^0 &&
3058                 echo very >y/c &&
3059                 echo important >y/d &&
3060                 echo contents >y/e &&
3061
3062                 test_must_fail git merge -s recursive B^0 >out 2>err &&
3063                 test_i18ngrep "CONFLICT (rename/delete).*Version B\^0 of y/d left in tree at y/d~B\^0" out &&
3064                 test_i18ngrep "Error: Refusing to lose untracked file at y/e; writing to y/e~B\^0 instead" out &&
3065
3066                 git ls-files -s >out &&
3067                 test_line_count = 3 out &&
3068                 git ls-files -u >out &&
3069                 test_line_count = 2 out &&
3070                 git ls-files -o >out &&
3071                 test_line_count = 5 out &&
3072
3073                 git rev-parse >actual \
3074                         :0:y/b :3:y/d :3:y/e &&
3075                 git rev-parse >expect \
3076                         O:z/b  O:z/c  B:z/e &&
3077                 test_cmp expect actual &&
3078
3079                 echo very >expect &&
3080                 test_cmp expect y/c &&
3081
3082                 echo important >expect &&
3083                 test_cmp expect y/d &&
3084
3085                 echo contents >expect &&
3086                 test_cmp expect y/e
3087         )
3088 '
3089
3090 # Testcase 10c, Overwrite untracked: dir rename/rename(1to2)
3091 #   Commit O: z/{a,b}, x/{c,d}
3092 #   Commit A: y/{a,b}, w/c, x/d + different untracked y/c
3093 #   Commit B: z/{a,b,c}, x/d
3094 #   Expected: Failed Merge; y/{a,b} + x/d + untracked y/c +
3095 #             CONFLICT(rename/rename) x/c -> w/c vs y/c +
3096 #             y/c~B^0 +
3097 #             ERROR_MSG(Refusing to lose untracked file at y/c)
3098
3099 test_expect_success '10c-setup: Overwrite untracked with dir rename/rename(1to2)' '
3100         test_create_repo 10c &&
3101         (
3102                 cd 10c &&
3103
3104                 mkdir z x &&
3105                 echo a >z/a &&
3106                 echo b >z/b &&
3107                 echo c >x/c &&
3108                 echo d >x/d &&
3109                 git add z x &&
3110                 test_tick &&
3111                 git commit -m "O" &&
3112
3113                 git branch O &&
3114                 git branch A &&
3115                 git branch B &&
3116
3117                 git checkout A &&
3118                 mkdir w &&
3119                 git mv x/c w/c &&
3120                 git mv z/ y/ &&
3121                 test_tick &&
3122                 git commit -m "A" &&
3123
3124                 git checkout B &&
3125                 git mv x/c z/ &&
3126                 test_tick &&
3127                 git commit -m "B"
3128         )
3129 '
3130
3131 test_expect_success '10c-check: Overwrite untracked with dir rename/rename(1to2)' '
3132         (
3133                 cd 10c &&
3134
3135                 git checkout A^0 &&
3136                 echo important >y/c &&
3137
3138                 test_must_fail git merge -s recursive B^0 >out 2>err &&
3139                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3140                 test_i18ngrep "Refusing to lose untracked file at y/c; adding as y/c~B\^0 instead" out &&
3141
3142                 git ls-files -s >out &&
3143                 test_line_count = 6 out &&
3144                 git ls-files -u >out &&
3145                 test_line_count = 3 out &&
3146                 git ls-files -o >out &&
3147                 test_line_count = 3 out &&
3148
3149                 git rev-parse >actual \
3150                         :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :3:y/c &&
3151                 git rev-parse >expect \
3152                          O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  O:x/c &&
3153                 test_cmp expect actual &&
3154
3155                 git hash-object y/c~B^0 >actual &&
3156                 git rev-parse O:x/c >expect &&
3157                 test_cmp expect actual &&
3158
3159                 echo important >expect &&
3160                 test_cmp expect y/c
3161         )
3162 '
3163
3164 # Testcase 10d, Delete untracked w/ dir rename/rename(2to1)
3165 #   Commit O: z/{a,b,c_1},        x/{d,e,f_2}
3166 #   Commit A: y/{a,b},            x/{d,e,f_2,wham_1} + untracked y/wham
3167 #   Commit B: z/{a,b,c_1,wham_2}, y/{d,e}
3168 #   Expected: Failed Merge; y/{a,b,d,e} + untracked y/{wham,wham~B^0,wham~HEAD}+
3169 #             CONFLICT(rename/rename) z/c_1 vs x/f_2 -> y/wham
3170 #             ERROR_MSG(Refusing to lose untracked file at y/wham)
3171
3172 test_expect_success '10d-setup: Delete untracked with dir rename/rename(2to1)' '
3173         test_create_repo 10d &&
3174         (
3175                 cd 10d &&
3176
3177                 mkdir z x &&
3178                 echo a >z/a &&
3179                 echo b >z/b &&
3180                 echo c >z/c &&
3181                 echo d >x/d &&
3182                 echo e >x/e &&
3183                 echo f >x/f &&
3184                 git add z x &&
3185                 test_tick &&
3186                 git commit -m "O" &&
3187
3188                 git branch O &&
3189                 git branch A &&
3190                 git branch B &&
3191
3192                 git checkout A &&
3193                 git mv z/c x/wham &&
3194                 git mv z/ y/ &&
3195                 test_tick &&
3196                 git commit -m "A" &&
3197
3198                 git checkout B &&
3199                 git mv x/f z/wham &&
3200                 git mv x/ y/ &&
3201                 test_tick &&
3202                 git commit -m "B"
3203         )
3204 '
3205
3206 test_expect_success '10d-check: Delete untracked with dir rename/rename(2to1)' '
3207         (
3208                 cd 10d &&
3209
3210                 git checkout A^0 &&
3211                 echo important >y/wham &&
3212
3213                 test_must_fail git merge -s recursive B^0 >out 2>err &&
3214                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3215                 test_i18ngrep "Refusing to lose untracked file at y/wham" out &&
3216
3217                 git ls-files -s >out &&
3218                 test_line_count = 6 out &&
3219                 git ls-files -u >out &&
3220                 test_line_count = 2 out &&
3221                 git ls-files -o >out &&
3222                 test_line_count = 4 out &&
3223
3224                 git rev-parse >actual \
3225                         :0:y/a :0:y/b :0:y/d :0:y/e :2:y/wham :3:y/wham &&
3226                 git rev-parse >expect \
3227                          O:z/a  O:z/b  O:x/d  O:x/e  O:z/c     O:x/f &&
3228                 test_cmp expect actual &&
3229
3230                 test_must_fail git rev-parse :1:y/wham &&
3231
3232                 echo important >expect &&
3233                 test_cmp expect y/wham &&
3234
3235                 git hash-object >actual \
3236                         y/wham~B^0 y/wham~HEAD &&
3237                 git rev-parse >expect \
3238                         O:x/f      O:z/c &&
3239                 test_cmp expect actual
3240         )
3241 '
3242
3243 # Testcase 10e, Does git complain about untracked file that's not in the way?
3244 #   Commit O: z/{a,b}
3245 #   Commit A: y/{a,b} + untracked z/c
3246 #   Commit B: z/{a,b,c}
3247 #   Expected: y/{a,b,c} + untracked z/c
3248
3249 test_expect_success '10e-setup: Does git complain about untracked file that is not really in the way?' '
3250         test_create_repo 10e &&
3251         (
3252                 cd 10e &&
3253
3254                 mkdir z &&
3255                 echo a >z/a &&
3256                 echo b >z/b &&
3257                 git add z &&
3258                 test_tick &&
3259                 git commit -m "O" &&
3260
3261                 git branch O &&
3262                 git branch A &&
3263                 git branch B &&
3264
3265                 git checkout A &&
3266                 git mv z/ y/ &&
3267                 test_tick &&
3268                 git commit -m "A" &&
3269
3270                 git checkout B &&
3271                 echo c >z/c &&
3272                 git add z/c &&
3273                 test_tick &&
3274                 git commit -m "B"
3275         )
3276 '
3277
3278 test_expect_failure '10e-check: Does git complain about untracked file that is not really in the way?' '
3279         (
3280                 cd 10e &&
3281
3282                 git checkout A^0 &&
3283                 mkdir z &&
3284                 echo random >z/c &&
3285
3286                 git merge -s recursive B^0 >out 2>err &&
3287                 test_i18ngrep ! "following untracked working tree files would be overwritten by merge" err &&
3288
3289                 git ls-files -s >out &&
3290                 test_line_count = 3 out &&
3291                 git ls-files -u >out &&
3292                 test_line_count = 0 out &&
3293                 git ls-files -o >out &&
3294                 test_line_count = 3 out &&
3295
3296                 git rev-parse >actual \
3297                         :0:y/a :0:y/b :0:y/c &&
3298                 git rev-parse >expect \
3299                          O:z/a  O:z/b  B:z/c &&
3300                 test_cmp expect actual &&
3301
3302                 echo random >expect &&
3303                 test_cmp expect z/c
3304         )
3305 '
3306
3307 ###########################################################################
3308 # SECTION 11: Handling dirty (not up-to-date) files
3309 #
3310 # unpack_trees(), upon which the recursive merge algorithm is based, aborts
3311 # the operation if untracked or dirty files would be deleted or overwritten
3312 # by the merge.  Unfortunately, unpack_trees() does not understand renames,
3313 # and if it doesn't abort, then it muddies up the working directory before
3314 # we even get to the point of detecting renames, so we need some special
3315 # handling.  This was true even of normal renames, but there are additional
3316 # codepaths that need special handling with directory renames.  Add
3317 # testcases for both renamed-by-directory-rename-detection and standard
3318 # rename cases.
3319 ###########################################################################
3320
3321 # Testcase 11a, Avoid losing dirty contents with simple rename
3322 #   Commit O: z/{a,b_v1},
3323 #   Commit A: z/{a,c_v1}, and z/c_v1 has uncommitted mods
3324 #   Commit B: z/{a,b_v2}
3325 #   Expected: ERROR_MSG(Refusing to lose dirty file at z/c) +
3326 #             z/a, staged version of z/c has sha1sum matching B:z/b_v2,
3327 #             z/c~HEAD with contents of B:z/b_v2,
3328 #             z/c with uncommitted mods on top of A:z/c_v1
3329
3330 test_expect_success '11a-setup: Avoid losing dirty contents with simple rename' '
3331         test_create_repo 11a &&
3332         (
3333                 cd 11a &&
3334
3335                 mkdir z &&
3336                 echo a >z/a &&
3337                 test_seq 1 10 >z/b &&
3338                 git add z &&
3339                 test_tick &&
3340                 git commit -m "O" &&
3341
3342                 git branch O &&
3343                 git branch A &&
3344                 git branch B &&
3345
3346                 git checkout A &&
3347                 git mv z/b z/c &&
3348                 test_tick &&
3349                 git commit -m "A" &&
3350
3351                 git checkout B &&
3352                 echo 11 >>z/b &&
3353                 git add z/b &&
3354                 test_tick &&
3355                 git commit -m "B"
3356         )
3357 '
3358
3359 test_expect_success '11a-check: Avoid losing dirty contents with simple rename' '
3360         (
3361                 cd 11a &&
3362
3363                 git checkout A^0 &&
3364                 echo stuff >>z/c &&
3365
3366                 test_must_fail git merge -s recursive B^0 >out 2>err &&
3367                 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3368
3369                 test_seq 1 10 >expected &&
3370                 echo stuff >>expected &&
3371                 test_cmp expected z/c &&
3372
3373                 git ls-files -s >out &&
3374                 test_line_count = 2 out &&
3375                 git ls-files -u >out &&
3376                 test_line_count = 1 out &&
3377                 git ls-files -o >out &&
3378                 test_line_count = 4 out &&
3379
3380                 git rev-parse >actual \
3381                         :0:z/a :2:z/c &&
3382                 git rev-parse >expect \
3383                          O:z/a  B:z/b &&
3384                 test_cmp expect actual &&
3385
3386                 git hash-object z/c~HEAD >actual &&
3387                 git rev-parse B:z/b >expect &&
3388                 test_cmp expect actual
3389         )
3390 '
3391
3392 # Testcase 11b, Avoid losing dirty file involved in directory rename
3393 #   Commit O: z/a,         x/{b,c_v1}
3394 #   Commit A: z/{a,c_v1},  x/b,       and z/c_v1 has uncommitted mods
3395 #   Commit B: y/a,         x/{b,c_v2}
3396 #   Expected: y/{a,c_v2}, x/b, z/c_v1 with uncommitted mods untracked,
3397 #             ERROR_MSG(Refusing to lose dirty file at z/c)
3398
3399
3400 test_expect_success '11b-setup: Avoid losing dirty file involved in directory rename' '
3401         test_create_repo 11b &&
3402         (
3403                 cd 11b &&
3404
3405                 mkdir z x &&
3406                 echo a >z/a &&
3407                 echo b >x/b &&
3408                 test_seq 1 10 >x/c &&
3409                 git add z x &&
3410                 test_tick &&
3411                 git commit -m "O" &&
3412
3413                 git branch O &&
3414                 git branch A &&
3415                 git branch B &&
3416
3417                 git checkout A &&
3418                 git mv x/c z/c &&
3419                 test_tick &&
3420                 git commit -m "A" &&
3421
3422                 git checkout B &&
3423                 git mv z y &&
3424                 echo 11 >>x/c &&
3425                 git add x/c &&
3426                 test_tick &&
3427                 git commit -m "B"
3428         )
3429 '
3430
3431 test_expect_success '11b-check: Avoid losing dirty file involved in directory rename' '
3432         (
3433                 cd 11b &&
3434
3435                 git checkout A^0 &&
3436                 echo stuff >>z/c &&
3437
3438                 git merge -s recursive B^0 >out 2>err &&
3439                 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3440
3441                 grep -q stuff z/c &&
3442                 test_seq 1 10 >expected &&
3443                 echo stuff >>expected &&
3444                 test_cmp expected z/c &&
3445
3446                 git ls-files -s >out &&
3447                 test_line_count = 3 out &&
3448                 git ls-files -u >out &&
3449                 test_line_count = 0 out &&
3450                 git ls-files -m >out &&
3451                 test_line_count = 0 out &&
3452                 git ls-files -o >out &&
3453                 test_line_count = 4 out &&
3454
3455                 git rev-parse >actual \
3456                         :0:x/b :0:y/a :0:y/c &&
3457                 git rev-parse >expect \
3458                          O:x/b  O:z/a  B:x/c &&
3459                 test_cmp expect actual &&
3460
3461                 git hash-object y/c >actual &&
3462                 git rev-parse B:x/c >expect &&
3463                 test_cmp expect actual
3464         )
3465 '
3466
3467 # Testcase 11c, Avoid losing not-up-to-date with rename + D/F conflict
3468 #   Commit O: y/a,         x/{b,c_v1}
3469 #   Commit A: y/{a,c_v1},  x/b,       and y/c_v1 has uncommitted mods
3470 #   Commit B: y/{a,c/d},   x/{b,c_v2}
3471 #   Expected: Abort_msg("following files would be overwritten by merge") +
3472 #             y/c left untouched (still has uncommitted mods)
3473
3474 test_expect_success '11c-setup: Avoid losing not-uptodate with rename + D/F conflict' '
3475         test_create_repo 11c &&
3476         (
3477                 cd 11c &&
3478
3479                 mkdir y x &&
3480                 echo a >y/a &&
3481                 echo b >x/b &&
3482                 test_seq 1 10 >x/c &&
3483                 git add y x &&
3484                 test_tick &&
3485                 git commit -m "O" &&
3486
3487                 git branch O &&
3488                 git branch A &&
3489                 git branch B &&
3490
3491                 git checkout A &&
3492                 git mv x/c y/c &&
3493                 test_tick &&
3494                 git commit -m "A" &&
3495
3496                 git checkout B &&
3497                 mkdir y/c &&
3498                 echo d >y/c/d &&
3499                 echo 11 >>x/c &&
3500                 git add x/c y/c/d &&
3501                 test_tick &&
3502                 git commit -m "B"
3503         )
3504 '
3505
3506 test_expect_success '11c-check: Avoid losing not-uptodate with rename + D/F conflict' '
3507         (
3508                 cd 11c &&
3509
3510                 git checkout A^0 &&
3511                 echo stuff >>y/c &&
3512
3513                 test_must_fail git merge -s recursive B^0 >out 2>err &&
3514                 test_i18ngrep "following files would be overwritten by merge" err &&
3515
3516                 grep -q stuff y/c &&
3517                 test_seq 1 10 >expected &&
3518                 echo stuff >>expected &&
3519                 test_cmp expected y/c &&
3520
3521                 git ls-files -s >out &&
3522                 test_line_count = 3 out &&
3523                 git ls-files -u >out &&
3524                 test_line_count = 0 out &&
3525                 git ls-files -m >out &&
3526                 test_line_count = 1 out &&
3527                 git ls-files -o >out &&
3528                 test_line_count = 3 out
3529         )
3530 '
3531
3532 # Testcase 11d, Avoid losing not-up-to-date with rename + D/F conflict
3533 #   Commit O: z/a,         x/{b,c_v1}
3534 #   Commit A: z/{a,c_v1},  x/b,       and z/c_v1 has uncommitted mods
3535 #   Commit B: y/{a,c/d},   x/{b,c_v2}
3536 #   Expected: D/F: y/c_v2 vs y/c/d) +
3537 #             Warning_Msg("Refusing to lose dirty file at z/c) +
3538 #             y/{a,c~HEAD,c/d}, x/b, now-untracked z/c_v1 with uncommitted mods
3539
3540 test_expect_success '11d-setup: Avoid losing not-uptodate with rename + D/F conflict' '
3541         test_create_repo 11d &&
3542         (
3543                 cd 11d &&
3544
3545                 mkdir z x &&
3546                 echo a >z/a &&
3547                 echo b >x/b &&
3548                 test_seq 1 10 >x/c &&
3549                 git add z x &&
3550                 test_tick &&
3551                 git commit -m "O" &&
3552
3553                 git branch O &&
3554                 git branch A &&
3555                 git branch B &&
3556
3557                 git checkout A &&
3558                 git mv x/c z/c &&
3559                 test_tick &&
3560                 git commit -m "A" &&
3561
3562                 git checkout B &&
3563                 git mv z y &&
3564                 mkdir y/c &&
3565                 echo d >y/c/d &&
3566                 echo 11 >>x/c &&
3567                 git add x/c y/c/d &&
3568                 test_tick &&
3569                 git commit -m "B"
3570         )
3571 '
3572
3573 test_expect_success '11d-check: Avoid losing not-uptodate with rename + D/F conflict' '
3574         (
3575                 cd 11d &&
3576
3577                 git checkout A^0 &&
3578                 echo stuff >>z/c &&
3579
3580                 test_must_fail git merge -s recursive B^0 >out 2>err &&
3581                 test_i18ngrep "Refusing to lose dirty file at z/c" out &&
3582
3583                 grep -q stuff z/c &&
3584                 test_seq 1 10 >expected &&
3585                 echo stuff >>expected &&
3586                 test_cmp expected z/c
3587
3588                 git ls-files -s >out &&
3589                 test_line_count = 4 out &&
3590                 git ls-files -u >out &&
3591                 test_line_count = 1 out &&
3592                 git ls-files -o >out &&
3593                 test_line_count = 5 out &&
3594
3595                 git rev-parse >actual \
3596                         :0:x/b :0:y/a :0:y/c/d :3:y/c &&
3597                 git rev-parse >expect \
3598                          O:x/b  O:z/a  B:y/c/d  B:x/c &&
3599                 test_cmp expect actual &&
3600
3601                 git hash-object y/c~HEAD >actual &&
3602                 git rev-parse B:x/c >expect &&
3603                 test_cmp expect actual
3604         )
3605 '
3606
3607 # Testcase 11e, Avoid deleting not-up-to-date with dir rename/rename(1to2)/add
3608 #   Commit O: z/{a,b},      x/{c_1,d}
3609 #   Commit A: y/{a,b,c_2},  x/d, w/c_1, and y/c_2 has uncommitted mods
3610 #   Commit B: z/{a,b,c_1},  x/d
3611 #   Expected: Failed Merge; y/{a,b} + x/d +
3612 #             CONFLICT(rename/rename) x/c_1 -> w/c_1 vs y/c_1 +
3613 #             ERROR_MSG(Refusing to lose dirty file at y/c)
3614 #             y/c~B^0 has O:x/c_1 contents
3615 #             y/c~HEAD has A:y/c_2 contents
3616 #             y/c has dirty file from before merge
3617
3618 test_expect_success '11e-setup: Avoid deleting not-uptodate with dir rename/rename(1to2)/add' '
3619         test_create_repo 11e &&
3620         (
3621                 cd 11e &&
3622
3623                 mkdir z x &&
3624                 echo a >z/a &&
3625                 echo b >z/b &&
3626                 echo c >x/c &&
3627                 echo d >x/d &&
3628                 git add z x &&
3629                 test_tick &&
3630                 git commit -m "O" &&
3631
3632                 git branch O &&
3633                 git branch A &&
3634                 git branch B &&
3635
3636                 git checkout A &&
3637                 git mv z/ y/ &&
3638                 echo different >y/c &&
3639                 mkdir w &&
3640                 git mv x/c w/ &&
3641                 git add y/c &&
3642                 test_tick &&
3643                 git commit -m "A" &&
3644
3645                 git checkout B &&
3646                 git mv x/c z/ &&
3647                 test_tick &&
3648                 git commit -m "B"
3649         )
3650 '
3651
3652 test_expect_success '11e-check: Avoid deleting not-uptodate with dir rename/rename(1to2)/add' '
3653         (
3654                 cd 11e &&
3655
3656                 git checkout A^0 &&
3657                 echo mods >>y/c &&
3658
3659                 test_must_fail git merge -s recursive B^0 >out 2>err &&
3660                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3661                 test_i18ngrep "Refusing to lose dirty file at y/c" out &&
3662
3663                 git ls-files -s >out &&
3664                 test_line_count = 7 out &&
3665                 git ls-files -u >out &&
3666                 test_line_count = 4 out &&
3667                 git ls-files -o >out &&
3668                 test_line_count = 4 out &&
3669
3670                 echo different >expected &&
3671                 echo mods >>expected &&
3672                 test_cmp expected y/c &&
3673
3674                 git rev-parse >actual \
3675                         :0:y/a :0:y/b :0:x/d :1:x/c :2:w/c :2:y/c :3:y/c &&
3676                 git rev-parse >expect \
3677                          O:z/a  O:z/b  O:x/d  O:x/c  O:x/c  A:y/c  O:x/c &&
3678                 test_cmp expect actual &&
3679
3680                 git hash-object >actual \
3681                         y/c~B^0 y/c~HEAD &&
3682                 git rev-parse >expect \
3683                         O:x/c   A:y/c &&
3684                 test_cmp expect actual
3685         )
3686 '
3687
3688 # Testcase 11f, Avoid deleting not-up-to-date w/ dir rename/rename(2to1)
3689 #   Commit O: z/{a,b},        x/{c_1,d_2}
3690 #   Commit A: y/{a,b,wham_1}, x/d_2, except y/wham has uncommitted mods
3691 #   Commit B: z/{a,b,wham_2}, x/c_1
3692 #   Expected: Failed Merge; y/{a,b} + untracked y/{wham~B^0,wham~B^HEAD} +
3693 #             y/wham with dirty changes from before merge +
3694 #             CONFLICT(rename/rename) x/c vs x/d -> y/wham
3695 #             ERROR_MSG(Refusing to lose dirty file at y/wham)
3696
3697 test_expect_success '11f-setup: Avoid deleting not-uptodate with dir rename/rename(2to1)' '
3698         test_create_repo 11f &&
3699         (
3700                 cd 11f &&
3701
3702                 mkdir z x &&
3703                 echo a >z/a &&
3704                 echo b >z/b &&
3705                 test_seq 1 10 >x/c &&
3706                 echo d >x/d &&
3707                 git add z x &&
3708                 test_tick &&
3709                 git commit -m "O" &&
3710
3711                 git branch O &&
3712                 git branch A &&
3713                 git branch B &&
3714
3715                 git checkout A &&
3716                 git mv z/ y/ &&
3717                 git mv x/c y/wham &&
3718                 test_tick &&
3719                 git commit -m "A" &&
3720
3721                 git checkout B &&
3722                 git mv x/d z/wham &&
3723                 test_tick &&
3724                 git commit -m "B"
3725         )
3726 '
3727
3728 test_expect_success '11f-check: Avoid deleting not-uptodate with dir rename/rename(2to1)' '
3729         (
3730                 cd 11f &&
3731
3732                 git checkout A^0 &&
3733                 echo important >>y/wham &&
3734
3735                 test_must_fail git merge -s recursive B^0 >out 2>err &&
3736                 test_i18ngrep "CONFLICT (rename/rename)" out &&
3737                 test_i18ngrep "Refusing to lose dirty file at y/wham" out &&
3738
3739                 git ls-files -s >out &&
3740                 test_line_count = 4 out &&
3741                 git ls-files -u >out &&
3742                 test_line_count = 2 out &&
3743                 git ls-files -o >out &&
3744                 test_line_count = 4 out &&
3745
3746                 test_seq 1 10 >expected &&
3747                 echo important >>expected &&
3748                 test_cmp expected y/wham &&
3749
3750                 test_must_fail git rev-parse :1:y/wham &&
3751                 git hash-object >actual \
3752                         y/wham~B^0 y/wham~HEAD &&
3753                 git rev-parse >expect \
3754                         O:x/d      O:x/c &&
3755                 test_cmp expect actual &&
3756
3757                 git rev-parse >actual \
3758                         :0:y/a :0:y/b :2:y/wham :3:y/wham &&
3759                 git rev-parse >expect \
3760                          O:z/a  O:z/b  O:x/c     O:x/d &&
3761                 test_cmp expect actual
3762         )
3763 '
3764
3765 ###########################################################################
3766 # SECTION 12: Everything else
3767 #
3768 # Tests suggested by others.  Tests added after implementation completed
3769 # and submitted.  Grab bag.
3770 ###########################################################################
3771
3772 # Testcase 12a, Moving one directory hierarchy into another
3773 #   (Related to testcase 9a)
3774 #   Commit O: node1/{leaf1,leaf2}, node2/{leaf3,leaf4}
3775 #   Commit A: node1/{leaf1,leaf2,node2/{leaf3,leaf4}}
3776 #   Commit B: node1/{leaf1,leaf2,leaf5}, node2/{leaf3,leaf4,leaf6}
3777 #   Expected: node1/{leaf1,leaf2,leaf5,node2/{leaf3,leaf4,leaf6}}
3778
3779 test_expect_success '12a-setup: Moving one directory hierarchy into another' '
3780         test_create_repo 12a &&
3781         (
3782                 cd 12a &&
3783
3784                 mkdir -p node1 node2 &&
3785                 echo leaf1 >node1/leaf1 &&
3786                 echo leaf2 >node1/leaf2 &&
3787                 echo leaf3 >node2/leaf3 &&
3788                 echo leaf4 >node2/leaf4 &&
3789                 git add node1 node2 &&
3790                 test_tick &&
3791                 git commit -m "O" &&
3792
3793                 git branch O &&
3794                 git branch A &&
3795                 git branch B &&
3796
3797                 git checkout A &&
3798                 git mv node2/ node1/ &&
3799                 test_tick &&
3800                 git commit -m "A" &&
3801
3802                 git checkout B &&
3803                 echo leaf5 >node1/leaf5 &&
3804                 echo leaf6 >node2/leaf6 &&
3805                 git add node1 node2 &&
3806                 test_tick &&
3807                 git commit -m "B"
3808         )
3809 '
3810
3811 test_expect_success '12a-check: Moving one directory hierarchy into another' '
3812         (
3813                 cd 12a &&
3814
3815                 git checkout A^0 &&
3816
3817                 git merge -s recursive B^0 &&
3818
3819                 git ls-files -s >out &&
3820                 test_line_count = 6 out &&
3821
3822                 git rev-parse >actual \
3823                         HEAD:node1/leaf1 HEAD:node1/leaf2 HEAD:node1/leaf5 \
3824                         HEAD:node1/node2/leaf3 \
3825                         HEAD:node1/node2/leaf4 \
3826                         HEAD:node1/node2/leaf6 &&
3827                 git rev-parse >expect \
3828                         O:node1/leaf1    O:node1/leaf2    B:node1/leaf5 \
3829                         O:node2/leaf3 \
3830                         O:node2/leaf4 \
3831                         B:node2/leaf6 &&
3832                 test_cmp expect actual
3833         )
3834 '
3835
3836 # Testcase 12b, Moving two directory hierarchies into each other
3837 #   (Related to testcases 1c and 12c)
3838 #   Commit O: node1/{leaf1, leaf2}, node2/{leaf3, leaf4}
3839 #   Commit A: node1/{leaf1, leaf2, node2/{leaf3, leaf4}}
3840 #   Commit B: node2/{leaf3, leaf4, node1/{leaf1, leaf2}}
3841 #   Expected: node1/node2/node1/{leaf1, leaf2},
3842 #             node2/node1/node2/{leaf3, leaf4}
3843 #   NOTE: Without directory renames, we would expect
3844 #                   node2/node1/{leaf1, leaf2},
3845 #                   node1/node2/{leaf3, leaf4}
3846 #         with directory rename detection, we note that
3847 #             commit A renames node2/ -> node1/node2/
3848 #             commit B renames node1/ -> node2/node1/
3849 #         therefore, applying those directory renames to the initial result
3850 #         (making all four paths experience a transitive renaming), yields
3851 #         the expected result.
3852 #
3853 #         You may ask, is it weird to have two directories rename each other?
3854 #         To which, I can do no more than shrug my shoulders and say that
3855 #         even simple rules give weird results when given weird inputs.
3856
3857 test_expect_success '12b-setup: Moving one directory hierarchy into another' '
3858         test_create_repo 12b &&
3859         (
3860                 cd 12b &&
3861
3862                 mkdir -p node1 node2 &&
3863                 echo leaf1 >node1/leaf1 &&
3864                 echo leaf2 >node1/leaf2 &&
3865                 echo leaf3 >node2/leaf3 &&
3866                 echo leaf4 >node2/leaf4 &&
3867                 git add node1 node2 &&
3868                 test_tick &&
3869                 git commit -m "O" &&
3870
3871                 git branch O &&
3872                 git branch A &&
3873                 git branch B &&
3874
3875                 git checkout A &&
3876                 git mv node2/ node1/ &&
3877                 test_tick &&
3878                 git commit -m "A" &&
3879
3880                 git checkout B &&
3881                 git mv node1/ node2/ &&
3882                 test_tick &&
3883                 git commit -m "B"
3884         )
3885 '
3886
3887 test_expect_success '12b-check: Moving one directory hierarchy into another' '
3888         (
3889                 cd 12b &&
3890
3891                 git checkout A^0 &&
3892
3893                 git merge -s recursive B^0 &&
3894
3895                 git ls-files -s >out &&
3896                 test_line_count = 4 out &&
3897
3898                 git rev-parse >actual \
3899                         HEAD:node1/node2/node1/leaf1 \
3900                         HEAD:node1/node2/node1/leaf2 \
3901                         HEAD:node2/node1/node2/leaf3 \
3902                         HEAD:node2/node1/node2/leaf4 &&
3903                 git rev-parse >expect \
3904                         O:node1/leaf1 \
3905                         O:node1/leaf2 \
3906                         O:node2/leaf3 \
3907                         O:node2/leaf4 &&
3908                 test_cmp expect actual
3909         )
3910 '
3911
3912 # Testcase 12c, Moving two directory hierarchies into each other w/ content merge
3913 #   (Related to testcase 12b)
3914 #   Commit O: node1/{       leaf1_1, leaf2_1}, node2/{leaf3_1, leaf4_1}
3915 #   Commit A: node1/{       leaf1_2, leaf2_2,  node2/{leaf3_2, leaf4_2}}
3916 #   Commit B: node2/{node1/{leaf1_3, leaf2_3},        leaf3_3, leaf4_3}
3917 #   Expected: Content merge conflicts for each of:
3918 #               node1/node2/node1/{leaf1, leaf2},
3919 #               node2/node1/node2/{leaf3, leaf4}
3920 #   NOTE: This is *exactly* like 12c, except that every path is modified on
3921 #         each side of the merge.
3922
3923 test_expect_success '12c-setup: Moving one directory hierarchy into another w/ content merge' '
3924         test_create_repo 12c &&
3925         (
3926                 cd 12c &&
3927
3928                 mkdir -p node1 node2 &&
3929                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf1\n" >node1/leaf1 &&
3930                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf2\n" >node1/leaf2 &&
3931                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf3\n" >node2/leaf3 &&
3932                 printf "1\n2\n3\n4\n5\n6\n7\n8\nleaf4\n" >node2/leaf4 &&
3933                 git add node1 node2 &&
3934                 test_tick &&
3935                 git commit -m "O" &&
3936
3937                 git branch O &&
3938                 git branch A &&
3939                 git branch B &&
3940
3941                 git checkout A &&
3942                 git mv node2/ node1/ &&
3943                 for i in `git ls-files`; do echo side A >>$i; done &&
3944                 git add -u &&
3945                 test_tick &&
3946                 git commit -m "A" &&
3947
3948                 git checkout B &&
3949                 git mv node1/ node2/ &&
3950                 for i in `git ls-files`; do echo side B >>$i; done &&
3951                 git add -u &&
3952                 test_tick &&
3953                 git commit -m "B"
3954         )
3955 '
3956
3957 test_expect_success '12c-check: Moving one directory hierarchy into another w/ content merge' '
3958         (
3959                 cd 12c &&
3960
3961                 git checkout A^0 &&
3962
3963                 test_must_fail git merge -s recursive B^0 &&
3964
3965                 git ls-files -u >out &&
3966                 test_line_count = 12 out &&
3967
3968                 git rev-parse >actual \
3969                         :1:node1/node2/node1/leaf1 \
3970                         :1:node1/node2/node1/leaf2 \
3971                         :1:node2/node1/node2/leaf3 \
3972                         :1:node2/node1/node2/leaf4 \
3973                         :2:node1/node2/node1/leaf1 \
3974                         :2:node1/node2/node1/leaf2 \
3975                         :2:node2/node1/node2/leaf3 \
3976                         :2:node2/node1/node2/leaf4 \
3977                         :3:node1/node2/node1/leaf1 \
3978                         :3:node1/node2/node1/leaf2 \
3979                         :3:node2/node1/node2/leaf3 \
3980                         :3:node2/node1/node2/leaf4 &&
3981                 git rev-parse >expect \
3982                         O:node1/leaf1 \
3983                         O:node1/leaf2 \
3984                         O:node2/leaf3 \
3985                         O:node2/leaf4 \
3986                         A:node1/leaf1 \
3987                         A:node1/leaf2 \
3988                         A:node1/node2/leaf3 \
3989                         A:node1/node2/leaf4 \
3990                         B:node2/node1/leaf1 \
3991                         B:node2/node1/leaf2 \
3992                         B:node2/leaf3 \
3993                         B:node2/leaf4 &&
3994                 test_cmp expect actual
3995         )
3996 '
3997
3998 test_done