for_each_object_in_pack(): clarify pack vs index ordering
[git] / t / t6402-merge-rename.sh
1 #!/bin/sh
2
3 test_description='Merge-recursive merging renames'
4 . ./test-lib.sh
5
6 modify () {
7         sed -e "$1" <"$2" >"$2.x" &&
8         mv "$2.x" "$2"
9 }
10
11 test_expect_success 'setup' '
12         cat >A <<-\EOF &&
13         a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
14         b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
15         c cccccccccccccccccccccccccccccccccccccccccccccccc
16         d dddddddddddddddddddddddddddddddddddddddddddddddd
17         e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
18         f ffffffffffffffffffffffffffffffffffffffffffffffff
19         g gggggggggggggggggggggggggggggggggggggggggggggggg
20         h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
21         i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
22         j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
23         k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
24         l llllllllllllllllllllllllllllllllllllllllllllllll
25         m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
26         n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
27         o oooooooooooooooooooooooooooooooooooooooooooooooo
28         EOF
29
30         cat >M <<-\EOF &&
31         A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
32         B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
33         C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
34         D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
35         E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
36         F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
37         G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
38         H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
39         I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
40         J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
41         K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
42         L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
43         M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
44         N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
45         O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
46         EOF
47
48         git add A M &&
49         git commit -m "initial has A and M" &&
50         git branch white &&
51         git branch red &&
52         git branch blue &&
53         git branch yellow &&
54         git branch change &&
55         git branch change+rename &&
56
57         sed -e "/^g /s/.*/g : master changes a line/" <A >A+ &&
58         mv A+ A &&
59         git commit -a -m "master updates A" &&
60
61         git checkout yellow &&
62         rm -f M &&
63         git commit -a -m "yellow removes M" &&
64
65         git checkout white &&
66         sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
67         sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
68         rm -f A M &&
69         git update-index --add --remove A B M N &&
70         git commit -m "white renames A->B, M->N" &&
71
72         git checkout red &&
73         sed -e "/^g /s/.*/g : red changes a line/" <A >B &&
74         sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
75         rm -f A M &&
76         git update-index --add --remove A B M N &&
77         git commit -m "red renames A->B, M->N" &&
78
79         git checkout blue &&
80         sed -e "/^g /s/.*/g : blue changes a line/" <A >C &&
81         sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
82         rm -f A M &&
83         git update-index --add --remove A C M N &&
84         git commit -m "blue renames A->C, M->N" &&
85
86         git checkout change &&
87         sed -e "/^g /s/.*/g : changed line/" <A >A+ &&
88         mv A+ A &&
89         git commit -q -a -m "changed" &&
90
91         git checkout change+rename &&
92         sed -e "/^g /s/.*/g : changed line/" <A >B &&
93         rm A &&
94         git update-index --add B &&
95         git commit -q -a -m "changed and renamed" &&
96
97         git checkout master
98 '
99
100 test_expect_success 'pull renaming branch into unrenaming one' \
101 '
102         git show-branch &&
103         test_expect_code 1 git pull . white &&
104         git ls-files -s &&
105         git ls-files -u B >b.stages &&
106         test_line_count = 3 b.stages &&
107         git ls-files -s N >n.stages &&
108         test_line_count = 1 n.stages &&
109         sed -ne "/^g/{
110         p
111         q
112         }" B | grep master &&
113         git diff --exit-code white N
114 '
115
116 test_expect_success 'pull renaming branch into another renaming one' \
117 '
118         rm -f B &&
119         git reset --hard &&
120         git checkout red &&
121         test_expect_code 1 git pull . white &&
122         git ls-files -u B >b.stages &&
123         test_line_count = 3 b.stages &&
124         git ls-files -s N >n.stages &&
125         test_line_count = 1 n.stages &&
126         sed -ne "/^g/{
127         p
128         q
129         }" B | grep red &&
130         git diff --exit-code white N
131 '
132
133 test_expect_success 'pull unrenaming branch into renaming one' \
134 '
135         git reset --hard &&
136         git show-branch &&
137         test_expect_code 1 git pull . master &&
138         git ls-files -u B >b.stages &&
139         test_line_count = 3 b.stages &&
140         git ls-files -s N >n.stages &&
141         test_line_count = 1 n.stages &&
142         sed -ne "/^g/{
143         p
144         q
145         }" B | grep red &&
146         git diff --exit-code white N
147 '
148
149 test_expect_success 'pull conflicting renames' \
150 '
151         git reset --hard &&
152         git show-branch &&
153         test_expect_code 1 git pull . blue &&
154         git ls-files -u A >a.stages &&
155         test_line_count = 1 a.stages &&
156         git ls-files -u B >b.stages &&
157         test_line_count = 1 b.stages &&
158         git ls-files -u C >c.stages &&
159         test_line_count = 1 c.stages &&
160         git ls-files -s N >n.stages &&
161         test_line_count = 1 n.stages &&
162         sed -ne "/^g/{
163         p
164         q
165         }" B | grep red &&
166         git diff --exit-code white N
167 '
168
169 test_expect_success 'interference with untracked working tree file' '
170         git reset --hard &&
171         git show-branch &&
172         echo >A this file should not matter &&
173         test_expect_code 1 git pull . white &&
174         test_path_is_file A
175 '
176
177 test_expect_success 'interference with untracked working tree file' '
178         git reset --hard &&
179         git checkout white &&
180         git show-branch &&
181         rm -f A &&
182         echo >A this file should not matter &&
183         test_expect_code 1 git pull . red &&
184         test_path_is_file A
185 '
186
187 test_expect_success 'interference with untracked working tree file' '
188         git reset --hard &&
189         rm -f A M &&
190         git checkout -f master &&
191         git tag -f anchor &&
192         git show-branch &&
193         git pull . yellow &&
194         test_path_is_missing M &&
195         git reset --hard anchor
196 '
197
198 test_expect_success 'updated working tree file should prevent the merge' '
199         git reset --hard &&
200         rm -f A M &&
201         git checkout -f master &&
202         git tag -f anchor &&
203         git show-branch &&
204         echo >>M one line addition &&
205         cat M >M.saved &&
206         test_expect_code 128 git pull . yellow &&
207         test_cmp M M.saved &&
208         rm -f M.saved
209 '
210
211 test_expect_success 'updated working tree file should prevent the merge' '
212         git reset --hard &&
213         rm -f A M &&
214         git checkout -f master &&
215         git tag -f anchor &&
216         git show-branch &&
217         echo >>M one line addition &&
218         cat M >M.saved &&
219         git update-index M &&
220         test_expect_code 128 git pull . yellow &&
221         test_cmp M M.saved &&
222         rm -f M.saved
223 '
224
225 test_expect_success 'interference with untracked working tree file' '
226         git reset --hard &&
227         rm -f A M &&
228         git checkout -f yellow &&
229         git tag -f anchor &&
230         git show-branch &&
231         echo >M this file should not matter &&
232         git pull . master &&
233         test_path_is_file M &&
234         ! {
235                 git ls-files -s |
236                 grep M
237         } &&
238         git reset --hard anchor
239 '
240
241 test_expect_success 'merge of identical changes in a renamed file' '
242         rm -f A M N &&
243         git reset --hard &&
244         git checkout change+rename &&
245
246         test-tool chmtime --get -3600 B >old-mtime &&
247         GIT_MERGE_VERBOSITY=3 git merge change >out &&
248
249         test-tool chmtime --get B >new-mtime &&
250         test_cmp old-mtime new-mtime &&
251
252         git reset --hard HEAD^ &&
253         git checkout change &&
254
255         # A will be renamed to B; we check mtimes and file presence
256         test_path_is_missing B &&
257         test-tool chmtime --get -3600 A >old-mtime &&
258         GIT_MERGE_VERBOSITY=3 git merge change+rename >out &&
259
260         test_path_is_missing A &&
261         test-tool chmtime --get B >new-mtime &&
262         test $(cat old-mtime) -lt $(cat new-mtime)
263 '
264
265 test_expect_success 'setup for rename + d/f conflicts' '
266         git reset --hard &&
267         git checkout --orphan dir-in-way &&
268         git rm -rf . &&
269         git clean -fdqx &&
270
271         mkdir sub &&
272         mkdir dir &&
273         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
274         echo foo >dir/file-in-the-way &&
275         git add -A &&
276         git commit -m "Common commit" &&
277
278         echo 11 >>sub/file &&
279         echo more >>dir/file-in-the-way &&
280         git add -u &&
281         git commit -m "Commit to merge, with dir in the way" &&
282
283         git checkout -b dir-not-in-way &&
284         git reset --soft HEAD^ &&
285         git rm -rf dir &&
286         git commit -m "Commit to merge, with dir removed" -- dir sub/file &&
287
288         git checkout -b renamed-file-has-no-conflicts dir-in-way~1 &&
289         git rm -rf dir &&
290         git rm sub/file &&
291         printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n" >dir &&
292         git add dir &&
293         git commit -m "Independent change" &&
294
295         git checkout -b renamed-file-has-conflicts dir-in-way~1 &&
296         git rm -rf dir &&
297         git mv sub/file dir &&
298         echo 12 >>dir &&
299         git add dir &&
300         git commit -m "Conflicting change"
301 '
302
303 test_expect_success 'Rename+D/F conflict; renamed file merges + dir not in way' '
304         git reset --hard &&
305         git checkout -q renamed-file-has-no-conflicts^0 &&
306
307         git merge --strategy=recursive dir-not-in-way &&
308
309         git diff --quiet &&
310         test_path_is_file dir &&
311         test_write_lines 1 2 3 4 5555 6 7 8 9 10 11 >expected &&
312         test_cmp expected dir
313 '
314
315 test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
316         git reset --hard &&
317         rm -rf dir~* &&
318         git checkout -q renamed-file-has-no-conflicts^0 &&
319         test_must_fail git merge --strategy=recursive dir-in-way >output &&
320
321         test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
322         test_i18ngrep "Auto-merging dir" output &&
323         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
324         then
325                 test_i18ngrep "moving it to dir~HEAD instead" output
326         else
327                 test_i18ngrep "Adding as dir~HEAD instead" output
328         fi &&
329
330         test 3 -eq "$(git ls-files -u | wc -l)" &&
331         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
332
333         test_must_fail git diff --quiet &&
334         test_must_fail git diff --cached --quiet &&
335
336         test_path_is_file dir/file-in-the-way &&
337         test_path_is_file dir~HEAD &&
338         test_cmp expected dir~HEAD
339 '
340
341 test_expect_success 'Same as previous, but merged other way' '
342         git reset --hard &&
343         rm -rf dir~* &&
344         git checkout -q dir-in-way^0 &&
345         test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
346
347         ! grep "error: refusing to lose untracked file at" errors &&
348         test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
349         test_i18ngrep "Auto-merging dir" output &&
350         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
351         then
352                 test_i18ngrep "moving it to dir~renamed-file-has-no-conflicts instead" output
353         else
354                 test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output
355         fi &&
356
357         test 3 -eq "$(git ls-files -u | wc -l)" &&
358         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
359
360         test_must_fail git diff --quiet &&
361         test_must_fail git diff --cached --quiet &&
362
363         test_path_is_file dir/file-in-the-way &&
364         test_path_is_file dir~renamed-file-has-no-conflicts &&
365         test_cmp expected dir~renamed-file-has-no-conflicts
366 '
367
368 test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
369         git reset --hard &&
370         rm -rf dir~* &&
371         git checkout -q renamed-file-has-conflicts^0 &&
372         test_must_fail git merge --strategy=recursive dir-not-in-way &&
373
374         test 3 -eq "$(git ls-files -u | wc -l)" &&
375         test 3 -eq "$(git ls-files -u dir | wc -l)" &&
376
377         test_must_fail git diff --quiet &&
378         test_must_fail git diff --cached --quiet &&
379
380         test_path_is_file dir &&
381         cat >expected <<-\EOF &&
382         1
383         2
384         3
385         4
386         5
387         6
388         7
389         8
390         9
391         10
392         <<<<<<< HEAD:dir
393         12
394         =======
395         11
396         >>>>>>> dir-not-in-way:sub/file
397         EOF
398         test_cmp expected dir
399 '
400
401 test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in the way' '
402         modify s/dir-not-in-way/dir-in-way/ expected &&
403
404         git reset --hard &&
405         rm -rf dir~* &&
406         git checkout -q renamed-file-has-conflicts^0 &&
407         test_must_fail git merge --strategy=recursive dir-in-way &&
408
409         test 5 -eq "$(git ls-files -u | wc -l)" &&
410         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
411         then
412                 test 3 -eq "$(git ls-files -u dir~HEAD | wc -l)"
413         else
414                 test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)"
415         fi &&
416         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
417
418         test_must_fail git diff --quiet &&
419         test_must_fail git diff --cached --quiet &&
420
421         test_path_is_file dir/file-in-the-way &&
422         test_path_is_file dir~HEAD &&
423         test_cmp expected dir~HEAD
424 '
425
426 test_expect_success 'Same as previous, but merged other way' '
427         git reset --hard &&
428         rm -rf dir~* &&
429         git checkout -q dir-in-way^0 &&
430         test_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&
431
432         test 5 -eq "$(git ls-files -u | wc -l)" &&
433         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
434         then
435                 test 3 -eq "$(git ls-files -u dir~renamed-file-has-conflicts | wc -l)"
436         else
437                 test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)"
438         fi &&
439         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
440
441         test_must_fail git diff --quiet &&
442         test_must_fail git diff --cached --quiet &&
443
444         test_path_is_file dir/file-in-the-way &&
445         test_path_is_file dir~renamed-file-has-conflicts &&
446         cat >expected <<-\EOF &&
447         1
448         2
449         3
450         4
451         5
452         6
453         7
454         8
455         9
456         10
457         <<<<<<< HEAD:sub/file
458         11
459         =======
460         12
461         >>>>>>> renamed-file-has-conflicts:dir
462         EOF
463         test_cmp expected dir~renamed-file-has-conflicts
464 '
465
466 test_expect_success 'setup both rename source and destination involved in D/F conflict' '
467         git reset --hard &&
468         git checkout --orphan rename-dest &&
469         git rm -rf . &&
470         git clean -fdqx &&
471
472         mkdir one &&
473         echo stuff >one/file &&
474         git add -A &&
475         git commit -m "Common commit" &&
476
477         git mv one/file destdir &&
478         git commit -m "Renamed to destdir" &&
479
480         git checkout -b source-conflict HEAD~1 &&
481         git rm -rf one &&
482         mkdir destdir &&
483         touch one destdir/foo &&
484         git add -A &&
485         git commit -m "Conflicts in the way"
486 '
487
488 test_expect_success 'both rename source and destination involved in D/F conflict' '
489         git reset --hard &&
490         rm -rf dir~* &&
491         git checkout -q rename-dest^0 &&
492         test_must_fail git merge --strategy=recursive source-conflict &&
493
494         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
495         then
496                 test 2 -eq "$(git ls-files -u | wc -l)"
497         else
498                 test 1 -eq "$(git ls-files -u | wc -l)"
499         fi &&
500
501         test_must_fail git diff --quiet &&
502
503         test_path_is_file destdir/foo &&
504         test_path_is_file one &&
505         test_path_is_file destdir~HEAD &&
506         test "stuff" = "$(cat destdir~HEAD)"
507 '
508
509 test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '
510         git reset --hard &&
511         git checkout --orphan rename-two &&
512         git rm -rf . &&
513         git clean -fdqx &&
514
515         mkdir one &&
516         mkdir two &&
517         echo stuff >one/file &&
518         echo other >two/file &&
519         git add -A &&
520         git commit -m "Common commit" &&
521
522         git rm -rf one &&
523         git mv two/file one &&
524         git commit -m "Rename two/file -> one" &&
525
526         git checkout -b rename-one HEAD~1 &&
527         git rm -rf two &&
528         git mv one/file two &&
529         rm -r one &&
530         git commit -m "Rename one/file -> two"
531 '
532
533 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
534 then
535         test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '
536                 git checkout -q rename-one^0 &&
537                 mkdir one &&
538                 test_must_fail git merge --strategy=recursive rename-two &&
539
540                 test 4 -eq "$(git ls-files -u | wc -l)" &&
541                 test 2 -eq "$(git ls-files -u one | wc -l)" &&
542                 test 2 -eq "$(git ls-files -u two | wc -l)" &&
543
544                 test_must_fail git diff --quiet &&
545
546                 test 3 -eq $(find . | grep -v .git | wc -l) &&
547
548                 test_path_is_file one &&
549                 test_path_is_file two &&
550                 test "other" = $(cat one) &&
551                 test "stuff" = $(cat two)
552         '
553 else
554         test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '
555                 git checkout -q rename-one^0 &&
556                 mkdir one &&
557                 test_must_fail git merge --strategy=recursive rename-two &&
558
559                 test 2 -eq "$(git ls-files -u | wc -l)" &&
560                 test 1 -eq "$(git ls-files -u one | wc -l)" &&
561                 test 1 -eq "$(git ls-files -u two | wc -l)" &&
562
563                 test_must_fail git diff --quiet &&
564
565                 test 4 -eq $(find . | grep -v .git | wc -l) &&
566
567                 test_path_is_dir one &&
568                 test_path_is_file one~rename-two &&
569                 test_path_is_file two &&
570                 test "other" = $(cat one~rename-two) &&
571                 test "stuff" = $(cat two)
572         '
573 fi
574
575 test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean start' '
576         git reset --hard &&
577         git clean -fdqx &&
578         test_must_fail git merge --strategy=recursive rename-two &&
579
580         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
581         then
582                 test 4 -eq "$(git ls-files -u | wc -l)" &&
583                 test 2 -eq "$(git ls-files -u one | wc -l)" &&
584                 test 2 -eq "$(git ls-files -u two | wc -l)"
585         else
586                 test 2 -eq "$(git ls-files -u | wc -l)" &&
587                 test 1 -eq "$(git ls-files -u one | wc -l)" &&
588                 test 1 -eq "$(git ls-files -u two | wc -l)"
589         fi &&
590
591         test_must_fail git diff --quiet &&
592
593         test 3 -eq $(find . | grep -v .git | wc -l) &&
594
595         test_path_is_file one &&
596         test_path_is_file two &&
597         test "other" = $(cat one) &&
598         test "stuff" = $(cat two)
599 '
600
601 test_expect_success 'setup rename of one file to two, with directories in the way' '
602         git reset --hard &&
603         git checkout --orphan first-rename &&
604         git rm -rf . &&
605         git clean -fdqx &&
606
607         echo stuff >original &&
608         git add -A &&
609         git commit -m "Common commit" &&
610
611         mkdir two &&
612         >two/file &&
613         git add two/file &&
614         git mv original one &&
615         git commit -m "Put two/file in the way, rename to one" &&
616
617         git checkout -b second-rename HEAD~1 &&
618         mkdir one &&
619         >one/file &&
620         git add one/file &&
621         git mv original two &&
622         git commit -m "Put one/file in the way, rename to two"
623 '
624
625 test_expect_success 'check handling of differently renamed file with D/F conflicts' '
626         git checkout -q first-rename^0 &&
627         test_must_fail git merge --strategy=recursive second-rename &&
628
629         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
630         then
631                 test 5 -eq "$(git ls-files -s | wc -l)" &&
632                 test 3 -eq "$(git ls-files -u | wc -l)" &&
633                 test 1 -eq "$(git ls-files -u one~HEAD | wc -l)" &&
634                 test 1 -eq "$(git ls-files -u two~second-rename | wc -l)" &&
635                 test 1 -eq "$(git ls-files -u original | wc -l)" &&
636                 test 0 -eq "$(git ls-files -o | wc -l)"
637         else
638                 test 5 -eq "$(git ls-files -s | wc -l)" &&
639                 test 3 -eq "$(git ls-files -u | wc -l)" &&
640                 test 1 -eq "$(git ls-files -u one | wc -l)" &&
641                 test 1 -eq "$(git ls-files -u two | wc -l)" &&
642                 test 1 -eq "$(git ls-files -u original | wc -l)" &&
643                 test 2 -eq "$(git ls-files -o | wc -l)"
644         fi &&
645
646         test_path_is_file one/file &&
647         test_path_is_file two/file &&
648         test_path_is_file one~HEAD &&
649         test_path_is_file two~second-rename &&
650         test_path_is_missing original
651 '
652
653 test_expect_success 'setup rename one file to two; directories moving out of the way' '
654         git reset --hard &&
655         git checkout --orphan first-rename-redo &&
656         git rm -rf . &&
657         git clean -fdqx &&
658
659         echo stuff >original &&
660         mkdir one two &&
661         touch one/file two/file &&
662         git add -A &&
663         git commit -m "Common commit" &&
664
665         git rm -rf one &&
666         git mv original one &&
667         git commit -m "Rename to one" &&
668
669         git checkout -b second-rename-redo HEAD~1 &&
670         git rm -rf two &&
671         git mv original two &&
672         git commit -m "Rename to two"
673 '
674
675 test_expect_success 'check handling of differently renamed file with D/F conflicts' '
676         git checkout -q first-rename-redo^0 &&
677         test_must_fail git merge --strategy=recursive second-rename-redo &&
678
679         test 3 -eq "$(git ls-files -u | wc -l)" &&
680         test 1 -eq "$(git ls-files -u one | wc -l)" &&
681         test 1 -eq "$(git ls-files -u two | wc -l)" &&
682         test 1 -eq "$(git ls-files -u original | wc -l)" &&
683         test 0 -eq "$(git ls-files -o | wc -l)" &&
684
685         test_path_is_file one &&
686         test_path_is_file two &&
687         test_path_is_missing original
688 '
689
690 test_expect_success 'setup avoid unnecessary update, normal rename' '
691         git reset --hard &&
692         git checkout --orphan avoid-unnecessary-update-1 &&
693         git rm -rf . &&
694         git clean -fdqx &&
695
696         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original &&
697         git add -A &&
698         git commit -m "Common commit" &&
699
700         git mv original rename &&
701         echo 11 >>rename &&
702         git add -u &&
703         git commit -m "Renamed and modified" &&
704
705         git checkout -b merge-branch-1 HEAD~1 &&
706         echo "random content" >random-file &&
707         git add -A &&
708         git commit -m "Random, unrelated changes"
709 '
710
711 test_expect_success 'avoid unnecessary update, normal rename' '
712         git checkout -q avoid-unnecessary-update-1^0 &&
713         test-tool chmtime --get -3600 rename >expect &&
714         git merge merge-branch-1 &&
715         test-tool chmtime --get rename >actual &&
716         test_cmp expect actual # "rename" should have stayed intact
717 '
718
719 test_expect_success 'setup to test avoiding unnecessary update, with D/F conflict' '
720         git reset --hard &&
721         git checkout --orphan avoid-unnecessary-update-2 &&
722         git rm -rf . &&
723         git clean -fdqx &&
724
725         mkdir df &&
726         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file &&
727         git add -A &&
728         git commit -m "Common commit" &&
729
730         git mv df/file temp &&
731         rm -rf df &&
732         git mv temp df &&
733         echo 11 >>df &&
734         git add -u &&
735         git commit -m "Renamed and modified" &&
736
737         git checkout -b merge-branch-2 HEAD~1 &&
738         >unrelated-change &&
739         git add unrelated-change &&
740         git commit -m "Only unrelated changes"
741 '
742
743 test_expect_success 'avoid unnecessary update, with D/F conflict' '
744         git checkout -q avoid-unnecessary-update-2^0 &&
745         test-tool chmtime --get -3600 df >expect &&
746         git merge merge-branch-2 &&
747         test-tool chmtime --get df >actual &&
748         test_cmp expect actual # "df" should have stayed intact
749 '
750
751 test_expect_success 'setup avoid unnecessary update, dir->(file,nothing)' '
752         git rm -rf . &&
753         git clean -fdqx &&
754         rm -rf .git &&
755         git init &&
756
757         >irrelevant &&
758         mkdir df &&
759         >df/file &&
760         git add -A &&
761         git commit -mA &&
762
763         git checkout -b side &&
764         git rm -rf df &&
765         git commit -mB &&
766
767         git checkout master &&
768         git rm -rf df &&
769         echo bla >df &&
770         git add -A &&
771         git commit -m "Add a newfile"
772 '
773
774 test_expect_success 'avoid unnecessary update, dir->(file,nothing)' '
775         git checkout -q master^0 &&
776         test-tool chmtime --get -3600 df >expect &&
777         git merge side &&
778         test-tool chmtime --get df >actual &&
779         test_cmp expect actual # "df" should have stayed intact
780 '
781
782 test_expect_success 'setup avoid unnecessary update, modify/delete' '
783         git rm -rf . &&
784         git clean -fdqx &&
785         rm -rf .git &&
786         git init &&
787
788         >irrelevant &&
789         >file &&
790         git add -A &&
791         git commit -mA &&
792
793         git checkout -b side &&
794         git rm -f file &&
795         git commit -m "Delete file" &&
796
797         git checkout master &&
798         echo bla >file &&
799         git add -A &&
800         git commit -m "Modify file"
801 '
802
803 test_expect_success 'avoid unnecessary update, modify/delete' '
804         git checkout -q master^0 &&
805         test-tool chmtime --get -3600 file >expect &&
806         test_must_fail git merge side &&
807         test-tool chmtime --get file >actual &&
808         test_cmp expect actual # "file" should have stayed intact
809 '
810
811 test_expect_success 'setup avoid unnecessary update, rename/add-dest' '
812         git rm -rf . &&
813         git clean -fdqx &&
814         rm -rf .git &&
815         git init &&
816
817         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >file &&
818         git add -A &&
819         git commit -mA &&
820
821         git checkout -b side &&
822         cp file newfile &&
823         git add -A &&
824         git commit -m "Add file copy" &&
825
826         git checkout master &&
827         git mv file newfile &&
828         git commit -m "Rename file"
829 '
830
831 test_expect_success 'avoid unnecessary update, rename/add-dest' '
832         git checkout -q master^0 &&
833         test-tool chmtime --get -3600 newfile >expect &&
834         git merge side &&
835         test-tool chmtime --get newfile >actual &&
836         test_cmp expect actual # "file" should have stayed intact
837 '
838
839 test_expect_success 'setup merge of rename + small change' '
840         git reset --hard &&
841         git checkout --orphan rename-plus-small-change &&
842         git rm -rf . &&
843         git clean -fdqx &&
844
845         echo ORIGINAL >file &&
846         git add file &&
847
848         test_tick &&
849         git commit -m Initial &&
850         git checkout -b rename_branch &&
851         git mv file renamed_file &&
852         git commit -m Rename &&
853         git checkout rename-plus-small-change &&
854         echo NEW-VERSION >file &&
855         git commit -a -m Reformat
856 '
857
858 test_expect_success 'merge rename + small change' '
859         git merge rename_branch &&
860
861         test 1 -eq $(git ls-files -s | wc -l) &&
862         test 0 -eq $(git ls-files -o | wc -l) &&
863         test $(git rev-parse HEAD:renamed_file) = $(git rev-parse HEAD~1:file)
864 '
865
866 test_expect_success 'setup for use of extended merge markers' '
867         git rm -rf . &&
868         git clean -fdqx &&
869         rm -rf .git &&
870         git init &&
871
872         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
873         git add original_file &&
874         git commit -mA &&
875
876         git checkout -b rename &&
877         echo 9 >>original_file &&
878         git add original_file &&
879         git mv original_file renamed_file &&
880         git commit -mB &&
881
882         git checkout master &&
883         echo 8.5 >>original_file &&
884         git add original_file &&
885         git commit -mC
886 '
887
888 test_expect_success 'merge master into rename has correct extended markers' '
889         git checkout rename^0 &&
890         test_must_fail git merge -s recursive master^0 &&
891
892         cat >expected <<-\EOF &&
893         1
894         2
895         3
896         4
897         5
898         6
899         7
900         8
901         <<<<<<< HEAD:renamed_file
902         9
903         =======
904         8.5
905         >>>>>>> master^0:original_file
906         EOF
907         test_cmp expected renamed_file
908 '
909
910 test_expect_success 'merge rename into master has correct extended markers' '
911         git reset --hard &&
912         git checkout master^0 &&
913         test_must_fail git merge -s recursive rename^0 &&
914
915         cat >expected <<-\EOF &&
916         1
917         2
918         3
919         4
920         5
921         6
922         7
923         8
924         <<<<<<< HEAD:original_file
925         8.5
926         =======
927         9
928         >>>>>>> rename^0:renamed_file
929         EOF
930         test_cmp expected renamed_file
931 '
932
933 test_expect_success 'setup spurious "refusing to lose untracked" message' '
934         git rm -rf . &&
935         git clean -fdqx &&
936         rm -rf .git &&
937         git init &&
938
939         > irrelevant_file &&
940         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
941         git add irrelevant_file original_file &&
942         git commit -mA &&
943
944         git checkout -b rename &&
945         git mv original_file renamed_file &&
946         git commit -mB &&
947
948         git checkout master &&
949         git rm original_file &&
950         git commit -mC
951 '
952
953 test_expect_success 'no spurious "refusing to lose untracked" message' '
954         git checkout master^0 &&
955         test_must_fail git merge rename^0 2>errors.txt &&
956         ! grep "refusing to lose untracked file" errors.txt
957 '
958
959 test_expect_success 'do not follow renames for empty files' '
960         git checkout -f -b empty-base &&
961         >empty1 &&
962         git add empty1 &&
963         git commit -m base &&
964         echo content >empty1 &&
965         git add empty1 &&
966         git commit -m fill &&
967         git checkout -b empty-topic HEAD^ &&
968         git mv empty1 empty2 &&
969         git commit -m rename &&
970         test_must_fail git merge empty-base &&
971         test_must_be_empty empty2
972 '
973
974 test_done