Merge branch 'ma/roll-back-lockfiles'
[git] / t / t6042-merge-rename-corner-cases.sh
1 #!/bin/sh
2
3 test_description="recursive merge corner cases w/ renames but not criss-crosses"
4 # t6036 has corner cases that involve both criss-cross merges and renames
5
6 . ./test-lib.sh
7
8 test_expect_success 'setup rename/delete + untracked file' '
9         echo "A pretty inscription" >ring &&
10         git add ring &&
11         test_tick &&
12         git commit -m beginning &&
13
14         git branch people &&
15         git checkout -b rename-the-ring &&
16         git mv ring one-ring-to-rule-them-all &&
17         test_tick &&
18         git commit -m fullname &&
19
20         git checkout people &&
21         git rm ring &&
22         echo gollum >owner &&
23         git add owner &&
24         test_tick &&
25         git commit -m track-people-instead-of-objects &&
26         echo "Myyy PRECIOUSSS" >ring
27 '
28
29 test_expect_success "Does git preserve Gollum's precious artifact?" '
30         test_must_fail git merge -s recursive rename-the-ring &&
31
32         # Make sure git did not delete an untracked file
33         test -f ring
34 '
35
36 # Testcase setup for rename/modify/add-source:
37 #   Commit A: new file: a
38 #   Commit B: modify a slightly
39 #   Commit C: rename a->b, add completely different a
40 #
41 # We should be able to merge B & C cleanly
42
43 test_expect_success 'setup rename/modify/add-source conflict' '
44         git rm -rf . &&
45         git clean -fdqx &&
46         rm -rf .git &&
47         git init &&
48
49         printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
50         git add a &&
51         git commit -m A &&
52         git tag A &&
53
54         git checkout -b B A &&
55         echo 8 >>a &&
56         git add a &&
57         git commit -m B &&
58
59         git checkout -b C A &&
60         git mv a b &&
61         echo something completely different >a &&
62         git add a &&
63         git commit -m C
64 '
65
66 test_expect_failure 'rename/modify/add-source conflict resolvable' '
67         git checkout B^0 &&
68
69         git merge -s recursive C^0 &&
70
71         test $(git rev-parse B:a) = $(git rev-parse b) &&
72         test $(git rev-parse C:a) = $(git rev-parse a)
73 '
74
75 test_expect_success 'setup resolvable conflict missed if rename missed' '
76         git rm -rf . &&
77         git clean -fdqx &&
78         rm -rf .git &&
79         git init &&
80
81         printf "1\n2\n3\n4\n5\n" >a &&
82         echo foo >b &&
83         git add a b &&
84         git commit -m A &&
85         git tag A &&
86
87         git checkout -b B A &&
88         git mv a c &&
89         echo "Completely different content" >a &&
90         git add a &&
91         git commit -m B &&
92
93         git checkout -b C A &&
94         echo 6 >>a &&
95         git add a &&
96         git commit -m C
97 '
98
99 test_expect_failure 'conflict caused if rename not detected' '
100         git checkout -q C^0 &&
101         git merge -s recursive B^0 &&
102
103         test 3 -eq $(git ls-files -s | wc -l) &&
104         test 0 -eq $(git ls-files -u | wc -l) &&
105         test 0 -eq $(git ls-files -o | wc -l) &&
106
107         test_line_count = 6 c &&
108         test $(git rev-parse HEAD:a) = $(git rev-parse B:a) &&
109         test $(git rev-parse HEAD:b) = $(git rev-parse A:b)
110 '
111
112 test_expect_success 'setup conflict resolved wrong if rename missed' '
113         git reset --hard &&
114         git clean -f &&
115
116         git checkout -b D A &&
117         echo 7 >>a &&
118         git add a &&
119         git mv a c &&
120         echo "Completely different content" >a &&
121         git add a &&
122         git commit -m D &&
123
124         git checkout -b E A &&
125         git rm a &&
126         echo "Completely different content" >>a &&
127         git add a &&
128         git commit -m E
129 '
130
131 test_expect_failure 'missed conflict if rename not detected' '
132         git checkout -q E^0 &&
133         test_must_fail git merge -s recursive D^0
134 '
135
136 # Tests for undetected rename/add-source causing a file to erroneously be
137 # deleted (and for mishandled rename/rename(1to1) causing the same issue).
138 #
139 # This test uses a rename/rename(1to1)+add-source conflict (1to1 means the
140 # same file is renamed on both sides to the same thing; it should trigger
141 # the 1to2 logic, which it would do if the add-source didn't cause issues
142 # for git's rename detection):
143 #   Commit A: new file: a
144 #   Commit B: rename a->b
145 #   Commit C: rename a->b, add unrelated a
146
147 test_expect_success 'setup undetected rename/add-source causes data loss' '
148         git rm -rf . &&
149         git clean -fdqx &&
150         rm -rf .git &&
151         git init &&
152
153         printf "1\n2\n3\n4\n5\n" >a &&
154         git add a &&
155         git commit -m A &&
156         git tag A &&
157
158         git checkout -b B A &&
159         git mv a b &&
160         git commit -m B &&
161
162         git checkout -b C A &&
163         git mv a b &&
164         echo foobar >a &&
165         git add a &&
166         git commit -m C
167 '
168
169 test_expect_failure 'detect rename/add-source and preserve all data' '
170         git checkout B^0 &&
171
172         git merge -s recursive C^0 &&
173
174         test 2 -eq $(git ls-files -s | wc -l) &&
175         test 2 -eq $(git ls-files -u | wc -l) &&
176         test 0 -eq $(git ls-files -o | wc -l) &&
177
178         test -f a &&
179         test -f b &&
180
181         test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
182         test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
183 '
184
185 test_expect_failure 'detect rename/add-source and preserve all data, merge other way' '
186         git checkout C^0 &&
187
188         git merge -s recursive B^0 &&
189
190         test 2 -eq $(git ls-files -s | wc -l) &&
191         test 2 -eq $(git ls-files -u | wc -l) &&
192         test 0 -eq $(git ls-files -o | wc -l) &&
193
194         test -f a &&
195         test -f b &&
196
197         test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
198         test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
199 '
200
201 test_expect_success 'setup content merge + rename/directory conflict' '
202         git rm -rf . &&
203         git clean -fdqx &&
204         rm -rf .git &&
205         git init &&
206
207         printf "1\n2\n3\n4\n5\n6\n" >file &&
208         git add file &&
209         test_tick &&
210         git commit -m base &&
211         git tag base &&
212
213         git checkout -b right &&
214         echo 7 >>file &&
215         mkdir newfile &&
216         echo junk >newfile/realfile &&
217         git add file newfile/realfile &&
218         test_tick &&
219         git commit -m right &&
220
221         git checkout -b left-conflict base &&
222         echo 8 >>file &&
223         git add file &&
224         git mv file newfile &&
225         test_tick &&
226         git commit -m left &&
227
228         git checkout -b left-clean base &&
229         echo 0 >newfile &&
230         cat file >>newfile &&
231         git add newfile &&
232         git rm file &&
233         test_tick &&
234         git commit -m left
235 '
236
237 test_expect_success 'rename/directory conflict + clean content merge' '
238         git reset --hard &&
239         git reset --hard &&
240         git clean -fdqx &&
241
242         git checkout left-clean^0 &&
243
244         test_must_fail git merge -s recursive right^0 &&
245
246         test 2 -eq $(git ls-files -s | wc -l) &&
247         test 1 -eq $(git ls-files -u | wc -l) &&
248         test 1 -eq $(git ls-files -o | wc -l) &&
249
250         echo 0 >expect &&
251         git cat-file -p base:file >>expect &&
252         echo 7 >>expect &&
253         test_cmp expect newfile~HEAD &&
254
255         test $(git rev-parse :2:newfile) = $(git hash-object expect) &&
256
257         test -f newfile/realfile &&
258         test -f newfile~HEAD
259 '
260
261 test_expect_success 'rename/directory conflict + content merge conflict' '
262         git reset --hard &&
263         git reset --hard &&
264         git clean -fdqx &&
265
266         git checkout left-conflict^0 &&
267
268         test_must_fail git merge -s recursive right^0 &&
269
270         test 4 -eq $(git ls-files -s | wc -l) &&
271         test 3 -eq $(git ls-files -u | wc -l) &&
272         test 1 -eq $(git ls-files -o | wc -l) &&
273
274         git cat-file -p left-conflict:newfile >left &&
275         git cat-file -p base:file    >base &&
276         git cat-file -p right:file   >right &&
277         test_must_fail git merge-file \
278                 -L "HEAD:newfile" \
279                 -L "" \
280                 -L "right^0:file" \
281                 left base right &&
282         test_cmp left newfile~HEAD &&
283
284         test $(git rev-parse :1:newfile) = $(git rev-parse base:file) &&
285         test $(git rev-parse :2:newfile) = $(git rev-parse left-conflict:newfile) &&
286         test $(git rev-parse :3:newfile) = $(git rev-parse right:file) &&
287
288         test -f newfile/realfile &&
289         test -f newfile~HEAD
290 '
291
292 test_expect_success 'setup content merge + rename/directory conflict w/ disappearing dir' '
293         git reset --hard &&
294         git rm -rf . &&
295         git clean -fdqx &&
296         rm -rf .git &&
297         git init &&
298
299         mkdir sub &&
300         printf "1\n2\n3\n4\n5\n6\n" >sub/file &&
301         git add sub/file &&
302         test_tick &&
303         git commit -m base &&
304         git tag base &&
305
306         git checkout -b right &&
307         echo 7 >>sub/file &&
308         git add sub/file &&
309         test_tick &&
310         git commit -m right &&
311
312         git checkout -b left base &&
313         echo 0 >newfile &&
314         cat sub/file >>newfile &&
315         git rm sub/file &&
316         mv newfile sub &&
317         git add sub &&
318         test_tick &&
319         git commit -m left
320 '
321
322 test_expect_success 'disappearing dir in rename/directory conflict handled' '
323         git reset --hard &&
324         git clean -fdqx &&
325
326         git checkout left^0 &&
327
328         git merge -s recursive right^0 &&
329
330         test 1 -eq $(git ls-files -s | wc -l) &&
331         test 0 -eq $(git ls-files -u | wc -l) &&
332         test 0 -eq $(git ls-files -o | wc -l) &&
333
334         echo 0 >expect &&
335         git cat-file -p base:sub/file >>expect &&
336         echo 7 >>expect &&
337         test_cmp expect sub &&
338
339         test -f sub
340 '
341
342 # Test for all kinds of things that can go wrong with rename/rename (2to1):
343 #   Commit A: new files: a & b
344 #   Commit B: rename a->c, modify b
345 #   Commit C: rename b->c, modify a
346 #
347 # Merging of B & C should NOT be clean.  Questions:
348 #   * Both a & b should be removed by the merge; are they?
349 #   * The two c's should contain modifications to a & b; do they?
350 #   * The index should contain two files, both for c; does it?
351 #   * The working copy should have two files, both of form c~<unique>; does it?
352 #   * Nothing else should be present.  Is anything?
353
354 test_expect_success 'setup rename/rename (2to1) + modify/modify' '
355         git rm -rf . &&
356         git clean -fdqx &&
357         rm -rf .git &&
358         git init &&
359
360         printf "1\n2\n3\n4\n5\n" >a &&
361         printf "5\n4\n3\n2\n1\n" >b &&
362         git add a b &&
363         git commit -m A &&
364         git tag A &&
365
366         git checkout -b B A &&
367         git mv a c &&
368         echo 0 >>b &&
369         git add b &&
370         git commit -m B &&
371
372         git checkout -b C A &&
373         git mv b c &&
374         echo 6 >>a &&
375         git add a &&
376         git commit -m C
377 '
378
379 test_expect_success 'handle rename/rename (2to1) conflict correctly' '
380         git checkout B^0 &&
381
382         test_must_fail git merge -s recursive C^0 >out &&
383         test_i18ngrep "CONFLICT (rename/rename)" out &&
384
385         test 2 -eq $(git ls-files -s | wc -l) &&
386         test 2 -eq $(git ls-files -u | wc -l) &&
387         test 2 -eq $(git ls-files -u c | wc -l) &&
388         test 3 -eq $(git ls-files -o | wc -l) &&
389
390         test ! -f a &&
391         test ! -f b &&
392         test -f c~HEAD &&
393         test -f c~C^0 &&
394
395         test $(git hash-object c~HEAD) = $(git rev-parse C:a) &&
396         test $(git hash-object c~C^0) = $(git rev-parse B:b)
397 '
398
399 # Testcase setup for simple rename/rename (1to2) conflict:
400 #   Commit A: new file: a
401 #   Commit B: rename a->b
402 #   Commit C: rename a->c
403 test_expect_success 'setup simple rename/rename (1to2) conflict' '
404         git rm -rf . &&
405         git clean -fdqx &&
406         rm -rf .git &&
407         git init &&
408
409         echo stuff >a &&
410         git add a &&
411         test_tick &&
412         git commit -m A &&
413         git tag A &&
414
415         git checkout -b B A &&
416         git mv a b &&
417         test_tick &&
418         git commit -m B &&
419
420         git checkout -b C A &&
421         git mv a c &&
422         test_tick &&
423         git commit -m C
424 '
425
426 test_expect_success 'merge has correct working tree contents' '
427         git checkout C^0 &&
428
429         test_must_fail git merge -s recursive B^0 &&
430
431         test 3 -eq $(git ls-files -s | wc -l) &&
432         test 3 -eq $(git ls-files -u | wc -l) &&
433         test 0 -eq $(git ls-files -o | wc -l) &&
434
435         test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
436         test $(git rev-parse :3:b) = $(git rev-parse A:a) &&
437         test $(git rev-parse :2:c) = $(git rev-parse A:a) &&
438
439         test ! -f a &&
440         test $(git hash-object b) = $(git rev-parse A:a) &&
441         test $(git hash-object c) = $(git rev-parse A:a)
442 '
443
444 # Testcase setup for rename/rename(1to2)/add-source conflict:
445 #   Commit A: new file: a
446 #   Commit B: rename a->b
447 #   Commit C: rename a->c, add completely different a
448 #
449 # Merging of B & C should NOT be clean; there's a rename/rename conflict
450
451 test_expect_success 'setup rename/rename(1to2)/add-source conflict' '
452         git rm -rf . &&
453         git clean -fdqx &&
454         rm -rf .git &&
455         git init &&
456
457         printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
458         git add a &&
459         git commit -m A &&
460         git tag A &&
461
462         git checkout -b B A &&
463         git mv a b &&
464         git commit -m B &&
465
466         git checkout -b C A &&
467         git mv a c &&
468         echo something completely different >a &&
469         git add a &&
470         git commit -m C
471 '
472
473 test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge' '
474         git checkout B^0 &&
475
476         test_must_fail git merge -s recursive C^0 &&
477
478         test 4 -eq $(git ls-files -s | wc -l) &&
479         test 0 -eq $(git ls-files -o | wc -l) &&
480
481         test $(git rev-parse 3:a) = $(git rev-parse C:a) &&
482         test $(git rev-parse 1:a) = $(git rev-parse A:a) &&
483         test $(git rev-parse 2:b) = $(git rev-parse B:b) &&
484         test $(git rev-parse 3:c) = $(git rev-parse C:c) &&
485
486         test -f a &&
487         test -f b &&
488         test -f c
489 '
490
491 test_expect_success 'setup rename/rename(1to2)/add-source resolvable conflict' '
492         git rm -rf . &&
493         git clean -fdqx &&
494         rm -rf .git &&
495         git init &&
496
497         >a &&
498         git add a &&
499         test_tick &&
500         git commit -m base &&
501         git tag A &&
502
503         git checkout -b B A &&
504         git mv a b &&
505         test_tick &&
506         git commit -m one &&
507
508         git checkout -b C A &&
509         git mv a b &&
510         echo important-info >a &&
511         git add a &&
512         test_tick &&
513         git commit -m two
514 '
515
516 test_expect_failure 'rename/rename/add-source still tracks new a file' '
517         git checkout C^0 &&
518         git merge -s recursive B^0 &&
519
520         test 2 -eq $(git ls-files -s | wc -l) &&
521         test 0 -eq $(git ls-files -o | wc -l) &&
522
523         test $(git rev-parse HEAD:a) = $(git rev-parse C:a) &&
524         test $(git rev-parse HEAD:b) = $(git rev-parse A:a)
525 '
526
527 test_expect_success 'setup rename/rename(1to2)/add-dest conflict' '
528         git rm -rf . &&
529         git clean -fdqx &&
530         rm -rf .git &&
531         git init &&
532
533         echo stuff >a &&
534         git add a &&
535         test_tick &&
536         git commit -m base &&
537         git tag A &&
538
539         git checkout -b B A &&
540         git mv a b &&
541         echo precious-data >c &&
542         git add c &&
543         test_tick &&
544         git commit -m one &&
545
546         git checkout -b C A &&
547         git mv a c &&
548         echo important-info >b &&
549         git add b &&
550         test_tick &&
551         git commit -m two
552 '
553
554 test_expect_success 'rename/rename/add-dest merge still knows about conflicting file versions' '
555         git checkout C^0 &&
556         test_must_fail git merge -s recursive B^0 &&
557
558         test 5 -eq $(git ls-files -s | wc -l) &&
559         test 2 -eq $(git ls-files -u b | wc -l) &&
560         test 2 -eq $(git ls-files -u c | wc -l) &&
561         test 4 -eq $(git ls-files -o | wc -l) &&
562
563         test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
564         test $(git rev-parse :2:b) = $(git rev-parse C:b) &&
565         test $(git rev-parse :3:b) = $(git rev-parse B:b) &&
566         test $(git rev-parse :2:c) = $(git rev-parse C:c) &&
567         test $(git rev-parse :3:c) = $(git rev-parse B:c) &&
568
569         test $(git hash-object c~HEAD) = $(git rev-parse C:c) &&
570         test $(git hash-object c~B\^0) = $(git rev-parse B:c) &&
571         test $(git hash-object b~HEAD) = $(git rev-parse C:b) &&
572         test $(git hash-object b~B\^0) = $(git rev-parse B:b) &&
573
574         test ! -f b &&
575         test ! -f c
576 '
577
578 test_done