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