convert: permit passing additional metadata to filter processes
[git] / t / t6022-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 =31337 B &&
247         test-tool chmtime --get B >old-mtime &&
248         GIT_MERGE_VERBOSITY=3 git merge change >out &&
249
250         test-tool chmtime --get B >new-mtime &&
251         test_cmp old-mtime new-mtime &&
252
253         git reset --hard HEAD^ &&
254         git checkout change &&
255
256         test-tool chmtime =-1 M &&
257         test-tool chmtime --get M >old-mtime &&
258         GIT_MERGE_VERBOSITY=3 git merge change+rename >out &&
259
260         test-tool chmtime --get B >new-mtime &&
261         test $(cat old-mtime) -lt $(cat new-mtime)
262 '
263
264 test_expect_success 'setup for rename + d/f conflicts' '
265         git reset --hard &&
266         git checkout --orphan dir-in-way &&
267         git rm -rf . &&
268         git clean -fdqx &&
269
270         mkdir sub &&
271         mkdir dir &&
272         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
273         echo foo >dir/file-in-the-way &&
274         git add -A &&
275         git commit -m "Common commit" &&
276
277         echo 11 >>sub/file &&
278         echo more >>dir/file-in-the-way &&
279         git add -u &&
280         git commit -m "Commit to merge, with dir in the way" &&
281
282         git checkout -b dir-not-in-way &&
283         git reset --soft HEAD^ &&
284         git rm -rf dir &&
285         git commit -m "Commit to merge, with dir removed" -- dir sub/file &&
286
287         git checkout -b renamed-file-has-no-conflicts dir-in-way~1 &&
288         git rm -rf dir &&
289         git rm sub/file &&
290         printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n" >dir &&
291         git add dir &&
292         git commit -m "Independent change" &&
293
294         git checkout -b renamed-file-has-conflicts dir-in-way~1 &&
295         git rm -rf dir &&
296         git mv sub/file dir &&
297         echo 12 >>dir &&
298         git add dir &&
299         git commit -m "Conflicting change"
300 '
301
302 test_expect_success 'Rename+D/F conflict; renamed file merges + dir not in way' '
303         git reset --hard &&
304         git checkout -q renamed-file-has-no-conflicts^0 &&
305
306         git merge --strategy=recursive dir-not-in-way &&
307
308         git diff --quiet &&
309         test_path_is_file dir &&
310         test_write_lines 1 2 3 4 5555 6 7 8 9 10 11 >expected &&
311         test_cmp expected dir
312 '
313
314 test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
315         git reset --hard &&
316         rm -rf dir~* &&
317         git checkout -q renamed-file-has-no-conflicts^0 &&
318         test_must_fail git merge --strategy=recursive dir-in-way >output &&
319
320         test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
321         test_i18ngrep "Auto-merging dir" output &&
322         test_i18ngrep "Adding as dir~HEAD instead" output &&
323
324         test 3 -eq "$(git ls-files -u | wc -l)" &&
325         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
326
327         test_must_fail git diff --quiet &&
328         test_must_fail git diff --cached --quiet &&
329
330         test_path_is_file dir/file-in-the-way &&
331         test_path_is_file dir~HEAD &&
332         test_cmp expected dir~HEAD
333 '
334
335 test_expect_success 'Same as previous, but merged other way' '
336         git reset --hard &&
337         rm -rf dir~* &&
338         git checkout -q dir-in-way^0 &&
339         test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
340
341         ! grep "error: refusing to lose untracked file at" errors &&
342         test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
343         test_i18ngrep "Auto-merging dir" output &&
344         test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
345
346         test 3 -eq "$(git ls-files -u | wc -l)" &&
347         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
348
349         test_must_fail git diff --quiet &&
350         test_must_fail git diff --cached --quiet &&
351
352         test_path_is_file dir/file-in-the-way &&
353         test_path_is_file dir~renamed-file-has-no-conflicts &&
354         test_cmp expected dir~renamed-file-has-no-conflicts
355 '
356
357 test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
358         git reset --hard &&
359         rm -rf dir~* &&
360         git checkout -q renamed-file-has-conflicts^0 &&
361         test_must_fail git merge --strategy=recursive dir-not-in-way &&
362
363         test 3 -eq "$(git ls-files -u | wc -l)" &&
364         test 3 -eq "$(git ls-files -u dir | wc -l)" &&
365
366         test_must_fail git diff --quiet &&
367         test_must_fail git diff --cached --quiet &&
368
369         test_path_is_file dir &&
370         cat >expected <<-\EOF &&
371         1
372         2
373         3
374         4
375         5
376         6
377         7
378         8
379         9
380         10
381         <<<<<<< HEAD:dir
382         12
383         =======
384         11
385         >>>>>>> dir-not-in-way:sub/file
386         EOF
387         test_cmp expected dir
388 '
389
390 test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in the way' '
391         modify s/dir-not-in-way/dir-in-way/ expected &&
392
393         git reset --hard &&
394         rm -rf dir~* &&
395         git checkout -q renamed-file-has-conflicts^0 &&
396         test_must_fail git merge --strategy=recursive dir-in-way &&
397
398         test 5 -eq "$(git ls-files -u | wc -l)" &&
399         test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
400         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
401
402         test_must_fail git diff --quiet &&
403         test_must_fail git diff --cached --quiet &&
404
405         test_path_is_file dir/file-in-the-way &&
406         test_path_is_file dir~HEAD &&
407         test_cmp expected dir~HEAD
408 '
409
410 test_expect_success 'Same as previous, but merged other way' '
411         git reset --hard &&
412         rm -rf dir~* &&
413         git checkout -q dir-in-way^0 &&
414         test_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&
415
416         test 5 -eq "$(git ls-files -u | wc -l)" &&
417         test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
418         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
419
420         test_must_fail git diff --quiet &&
421         test_must_fail git diff --cached --quiet &&
422
423         test_path_is_file dir/file-in-the-way &&
424         test_path_is_file dir~renamed-file-has-conflicts &&
425         cat >expected <<-\EOF &&
426         1
427         2
428         3
429         4
430         5
431         6
432         7
433         8
434         9
435         10
436         <<<<<<< HEAD:sub/file
437         11
438         =======
439         12
440         >>>>>>> renamed-file-has-conflicts:dir
441         EOF
442         test_cmp expected dir~renamed-file-has-conflicts
443 '
444
445 test_expect_success 'setup both rename source and destination involved in D/F conflict' '
446         git reset --hard &&
447         git checkout --orphan rename-dest &&
448         git rm -rf . &&
449         git clean -fdqx &&
450
451         mkdir one &&
452         echo stuff >one/file &&
453         git add -A &&
454         git commit -m "Common commit" &&
455
456         git mv one/file destdir &&
457         git commit -m "Renamed to destdir" &&
458
459         git checkout -b source-conflict HEAD~1 &&
460         git rm -rf one &&
461         mkdir destdir &&
462         touch one destdir/foo &&
463         git add -A &&
464         git commit -m "Conflicts in the way"
465 '
466
467 test_expect_success 'both rename source and destination involved in D/F conflict' '
468         git reset --hard &&
469         rm -rf dir~* &&
470         git checkout -q rename-dest^0 &&
471         test_must_fail git merge --strategy=recursive source-conflict &&
472
473         test 1 -eq "$(git ls-files -u | wc -l)" &&
474
475         test_must_fail git diff --quiet &&
476
477         test_path_is_file destdir/foo &&
478         test_path_is_file one &&
479         test_path_is_file destdir~HEAD &&
480         test "stuff" = "$(cat destdir~HEAD)"
481 '
482
483 test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '
484         git reset --hard &&
485         git checkout --orphan rename-two &&
486         git rm -rf . &&
487         git clean -fdqx &&
488
489         mkdir one &&
490         mkdir two &&
491         echo stuff >one/file &&
492         echo other >two/file &&
493         git add -A &&
494         git commit -m "Common commit" &&
495
496         git rm -rf one &&
497         git mv two/file one &&
498         git commit -m "Rename two/file -> one" &&
499
500         git checkout -b rename-one HEAD~1 &&
501         git rm -rf two &&
502         git mv one/file two &&
503         rm -r one &&
504         git commit -m "Rename one/file -> two"
505 '
506
507 test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '
508         git checkout -q rename-one^0 &&
509         mkdir one &&
510         test_must_fail git merge --strategy=recursive rename-two &&
511
512         test 2 -eq "$(git ls-files -u | wc -l)" &&
513         test 1 -eq "$(git ls-files -u one | wc -l)" &&
514         test 1 -eq "$(git ls-files -u two | wc -l)" &&
515
516         test_must_fail git diff --quiet &&
517
518         test 4 -eq $(find . | grep -v .git | wc -l) &&
519
520         test_path_is_dir one &&
521         test_path_is_file one~rename-two &&
522         test_path_is_file two &&
523         test "other" = $(cat one~rename-two) &&
524         test "stuff" = $(cat two)
525 '
526
527 test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean start' '
528         git reset --hard &&
529         git clean -fdqx &&
530         test_must_fail git merge --strategy=recursive rename-two &&
531
532         test 2 -eq "$(git ls-files -u | wc -l)" &&
533         test 1 -eq "$(git ls-files -u one | wc -l)" &&
534         test 1 -eq "$(git ls-files -u two | wc -l)" &&
535
536         test_must_fail git diff --quiet &&
537
538         test 3 -eq $(find . | grep -v .git | wc -l) &&
539
540         test_path_is_file one &&
541         test_path_is_file two &&
542         test "other" = $(cat one) &&
543         test "stuff" = $(cat two)
544 '
545
546 test_expect_success 'setup rename of one file to two, with directories in the way' '
547         git reset --hard &&
548         git checkout --orphan first-rename &&
549         git rm -rf . &&
550         git clean -fdqx &&
551
552         echo stuff >original &&
553         git add -A &&
554         git commit -m "Common commit" &&
555
556         mkdir two &&
557         >two/file &&
558         git add two/file &&
559         git mv original one &&
560         git commit -m "Put two/file in the way, rename to one" &&
561
562         git checkout -b second-rename HEAD~1 &&
563         mkdir one &&
564         >one/file &&
565         git add one/file &&
566         git mv original two &&
567         git commit -m "Put one/file in the way, rename to two"
568 '
569
570 test_expect_success 'check handling of differently renamed file with D/F conflicts' '
571         git checkout -q first-rename^0 &&
572         test_must_fail git merge --strategy=recursive second-rename &&
573
574         test 5 -eq "$(git ls-files -s | wc -l)" &&
575         test 3 -eq "$(git ls-files -u | wc -l)" &&
576         test 1 -eq "$(git ls-files -u one | wc -l)" &&
577         test 1 -eq "$(git ls-files -u two | wc -l)" &&
578         test 1 -eq "$(git ls-files -u original | wc -l)" &&
579         test 2 -eq "$(git ls-files -o | wc -l)" &&
580
581         test_path_is_file one/file &&
582         test_path_is_file two/file &&
583         test_path_is_file one~HEAD &&
584         test_path_is_file two~second-rename &&
585         test_path_is_missing original
586 '
587
588 test_expect_success 'setup rename one file to two; directories moving out of the way' '
589         git reset --hard &&
590         git checkout --orphan first-rename-redo &&
591         git rm -rf . &&
592         git clean -fdqx &&
593
594         echo stuff >original &&
595         mkdir one two &&
596         touch one/file two/file &&
597         git add -A &&
598         git commit -m "Common commit" &&
599
600         git rm -rf one &&
601         git mv original one &&
602         git commit -m "Rename to one" &&
603
604         git checkout -b second-rename-redo HEAD~1 &&
605         git rm -rf two &&
606         git mv original two &&
607         git commit -m "Rename to two"
608 '
609
610 test_expect_success 'check handling of differently renamed file with D/F conflicts' '
611         git checkout -q first-rename-redo^0 &&
612         test_must_fail git merge --strategy=recursive second-rename-redo &&
613
614         test 3 -eq "$(git ls-files -u | wc -l)" &&
615         test 1 -eq "$(git ls-files -u one | wc -l)" &&
616         test 1 -eq "$(git ls-files -u two | wc -l)" &&
617         test 1 -eq "$(git ls-files -u original | wc -l)" &&
618         test 0 -eq "$(git ls-files -o | wc -l)" &&
619
620         test_path_is_file one &&
621         test_path_is_file two &&
622         test_path_is_missing original
623 '
624
625 test_expect_success 'setup avoid unnecessary update, normal rename' '
626         git reset --hard &&
627         git checkout --orphan avoid-unnecessary-update-1 &&
628         git rm -rf . &&
629         git clean -fdqx &&
630
631         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original &&
632         git add -A &&
633         git commit -m "Common commit" &&
634
635         git mv original rename &&
636         echo 11 >>rename &&
637         git add -u &&
638         git commit -m "Renamed and modified" &&
639
640         git checkout -b merge-branch-1 HEAD~1 &&
641         echo "random content" >random-file &&
642         git add -A &&
643         git commit -m "Random, unrelated changes"
644 '
645
646 test_expect_success 'avoid unnecessary update, normal rename' '
647         git checkout -q avoid-unnecessary-update-1^0 &&
648         test-tool chmtime --get =1000000000 rename >expect &&
649         git merge merge-branch-1 &&
650         test-tool chmtime --get rename >actual &&
651         test_cmp expect actual # "rename" should have stayed intact
652 '
653
654 test_expect_success 'setup to test avoiding unnecessary update, with D/F conflict' '
655         git reset --hard &&
656         git checkout --orphan avoid-unnecessary-update-2 &&
657         git rm -rf . &&
658         git clean -fdqx &&
659
660         mkdir df &&
661         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file &&
662         git add -A &&
663         git commit -m "Common commit" &&
664
665         git mv df/file temp &&
666         rm -rf df &&
667         git mv temp df &&
668         echo 11 >>df &&
669         git add -u &&
670         git commit -m "Renamed and modified" &&
671
672         git checkout -b merge-branch-2 HEAD~1 &&
673         >unrelated-change &&
674         git add unrelated-change &&
675         git commit -m "Only unrelated changes"
676 '
677
678 test_expect_success 'avoid unnecessary update, with D/F conflict' '
679         git checkout -q avoid-unnecessary-update-2^0 &&
680         test-tool chmtime --get =1000000000 df >expect &&
681         git merge merge-branch-2 &&
682         test-tool chmtime --get df >actual &&
683         test_cmp expect actual # "df" should have stayed intact
684 '
685
686 test_expect_success 'setup avoid unnecessary update, dir->(file,nothing)' '
687         git rm -rf . &&
688         git clean -fdqx &&
689         rm -rf .git &&
690         git init &&
691
692         >irrelevant &&
693         mkdir df &&
694         >df/file &&
695         git add -A &&
696         git commit -mA &&
697
698         git checkout -b side &&
699         git rm -rf df &&
700         git commit -mB &&
701
702         git checkout master &&
703         git rm -rf df &&
704         echo bla >df &&
705         git add -A &&
706         git commit -m "Add a newfile"
707 '
708
709 test_expect_success 'avoid unnecessary update, dir->(file,nothing)' '
710         git checkout -q master^0 &&
711         test-tool chmtime --get =1000000000 df >expect &&
712         git merge side &&
713         test-tool chmtime --get df >actual &&
714         test_cmp expect actual # "df" should have stayed intact
715 '
716
717 test_expect_success 'setup avoid unnecessary update, modify/delete' '
718         git rm -rf . &&
719         git clean -fdqx &&
720         rm -rf .git &&
721         git init &&
722
723         >irrelevant &&
724         >file &&
725         git add -A &&
726         git commit -mA &&
727
728         git checkout -b side &&
729         git rm -f file &&
730         git commit -m "Delete file" &&
731
732         git checkout master &&
733         echo bla >file &&
734         git add -A &&
735         git commit -m "Modify file"
736 '
737
738 test_expect_success 'avoid unnecessary update, modify/delete' '
739         git checkout -q master^0 &&
740         test-tool chmtime --get =1000000000 file >expect &&
741         test_must_fail git merge side &&
742         test-tool chmtime --get file >actual &&
743         test_cmp expect actual # "file" should have stayed intact
744 '
745
746 test_expect_success 'setup avoid unnecessary update, rename/add-dest' '
747         git rm -rf . &&
748         git clean -fdqx &&
749         rm -rf .git &&
750         git init &&
751
752         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >file &&
753         git add -A &&
754         git commit -mA &&
755
756         git checkout -b side &&
757         cp file newfile &&
758         git add -A &&
759         git commit -m "Add file copy" &&
760
761         git checkout master &&
762         git mv file newfile &&
763         git commit -m "Rename file"
764 '
765
766 test_expect_success 'avoid unnecessary update, rename/add-dest' '
767         git checkout -q master^0 &&
768         test-tool chmtime --get =1000000000 newfile >expect &&
769         git merge side &&
770         test-tool chmtime --get newfile >actual &&
771         test_cmp expect actual # "file" should have stayed intact
772 '
773
774 test_expect_success 'setup merge of rename + small change' '
775         git reset --hard &&
776         git checkout --orphan rename-plus-small-change &&
777         git rm -rf . &&
778         git clean -fdqx &&
779
780         echo ORIGINAL >file &&
781         git add file &&
782
783         test_tick &&
784         git commit -m Initial &&
785         git checkout -b rename_branch &&
786         git mv file renamed_file &&
787         git commit -m Rename &&
788         git checkout rename-plus-small-change &&
789         echo NEW-VERSION >file &&
790         git commit -a -m Reformat
791 '
792
793 test_expect_success 'merge rename + small change' '
794         git merge rename_branch &&
795
796         test 1 -eq $(git ls-files -s | wc -l) &&
797         test 0 -eq $(git ls-files -o | wc -l) &&
798         test $(git rev-parse HEAD:renamed_file) = $(git rev-parse HEAD~1:file)
799 '
800
801 test_expect_success 'setup for use of extended merge markers' '
802         git rm -rf . &&
803         git clean -fdqx &&
804         rm -rf .git &&
805         git init &&
806
807         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
808         git add original_file &&
809         git commit -mA &&
810
811         git checkout -b rename &&
812         echo 9 >>original_file &&
813         git add original_file &&
814         git mv original_file renamed_file &&
815         git commit -mB &&
816
817         git checkout master &&
818         echo 8.5 >>original_file &&
819         git add original_file &&
820         git commit -mC
821 '
822
823 test_expect_success 'merge master into rename has correct extended markers' '
824         git checkout rename^0 &&
825         test_must_fail git merge -s recursive master^0 &&
826
827         cat >expected <<-\EOF &&
828         1
829         2
830         3
831         4
832         5
833         6
834         7
835         8
836         <<<<<<< HEAD:renamed_file
837         9
838         =======
839         8.5
840         >>>>>>> master^0:original_file
841         EOF
842         test_cmp expected renamed_file
843 '
844
845 test_expect_success 'merge rename into master has correct extended markers' '
846         git reset --hard &&
847         git checkout master^0 &&
848         test_must_fail git merge -s recursive rename^0 &&
849
850         cat >expected <<-\EOF &&
851         1
852         2
853         3
854         4
855         5
856         6
857         7
858         8
859         <<<<<<< HEAD:original_file
860         8.5
861         =======
862         9
863         >>>>>>> rename^0:renamed_file
864         EOF
865         test_cmp expected renamed_file
866 '
867
868 test_expect_success 'setup spurious "refusing to lose untracked" message' '
869         git rm -rf . &&
870         git clean -fdqx &&
871         rm -rf .git &&
872         git init &&
873
874         > irrelevant_file &&
875         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
876         git add irrelevant_file original_file &&
877         git commit -mA &&
878
879         git checkout -b rename &&
880         git mv original_file renamed_file &&
881         git commit -mB &&
882
883         git checkout master &&
884         git rm original_file &&
885         git commit -mC
886 '
887
888 test_expect_success 'no spurious "refusing to lose untracked" message' '
889         git checkout master^0 &&
890         test_must_fail git merge rename^0 2>errors.txt &&
891         ! grep "refusing to lose untracked file" errors.txt
892 '
893
894 test_expect_success 'do not follow renames for empty files' '
895         git checkout -f -b empty-base &&
896         >empty1 &&
897         git add empty1 &&
898         git commit -m base &&
899         echo content >empty1 &&
900         git add empty1 &&
901         git commit -m fill &&
902         git checkout -b empty-topic HEAD^ &&
903         git mv empty1 empty2 &&
904         git commit -m rename &&
905         test_must_fail git merge empty-base &&
906         test_must_be_empty empty2
907 '
908
909 test_done