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