]>
Commit | Line | Data |
---|---|---|
c94736a2 JH |
1 | #!/bin/sh |
2 | ||
695576fd | 3 | test_description='recursive merge corner cases involving criss-cross merges' |
c94736a2 JH |
4 | |
5 | . ./test-lib.sh | |
6 | ||
827f2b7d EN |
7 | get_clean_checkout () { |
8 | git reset --hard && | |
9 | git clean -fdqx && | |
10 | git checkout "$1" | |
11 | } | |
12 | ||
c94736a2 JH |
13 | # |
14 | # L1 L2 | |
15 | # o---o | |
16 | # / \ / \ | |
17 | # o X ? | |
18 | # \ / \ / | |
19 | # o---o | |
20 | # R1 R2 | |
21 | # | |
22 | ||
c976260d | 23 | test_expect_success 'setup basic criss-cross + rename with no modifications' ' |
a48fcd83 | 24 | ten="0 1 2 3 4 5 6 7 8 9" && |
c94736a2 JH |
25 | for i in $ten |
26 | do | |
27 | echo line $i in a sample file | |
28 | done >one && | |
29 | for i in $ten | |
30 | do | |
31 | echo line $i in another sample file | |
32 | done >two && | |
33 | git add one two && | |
34 | test_tick && git commit -m initial && | |
35 | ||
36 | git branch L1 && | |
37 | git checkout -b R1 && | |
38 | git mv one three && | |
39 | test_tick && git commit -m R1 && | |
40 | ||
41 | git checkout L1 && | |
42 | git mv two three && | |
43 | test_tick && git commit -m L1 && | |
44 | ||
45 | git checkout L1^0 && | |
46 | test_tick && git merge -s ours R1 && | |
47 | git tag L2 && | |
48 | ||
49 | git checkout R1^0 && | |
50 | test_tick && git merge -s ours L1 && | |
51 | git tag R2 | |
52 | ' | |
53 | ||
c976260d | 54 | test_expect_success 'merge simple rename+criss-cross with no modifications' ' |
c94736a2 JH |
55 | git reset --hard && |
56 | git checkout L2^0 && | |
57 | ||
c976260d EN |
58 | test_must_fail git merge -s recursive R2^0 && |
59 | ||
434b8525 EN |
60 | test 2 = $(git ls-files -s | wc -l) && |
61 | test 2 = $(git ls-files -u | wc -l) && | |
62 | test 2 = $(git ls-files -o | wc -l) && | |
c976260d | 63 | |
c976260d EN |
64 | test $(git rev-parse :2:three) = $(git rev-parse L2:three) && |
65 | test $(git rev-parse :3:three) = $(git rev-parse R2:three) && | |
66 | ||
434b8525 EN |
67 | test $(git rev-parse L2:three) = $(git hash-object three~HEAD) && |
68 | test $(git rev-parse R2:three) = $(git hash-object three~R2^0) | |
c94736a2 JH |
69 | ' |
70 | ||
583942df EN |
71 | # |
72 | # Same as before, but modify L1 slightly: | |
73 | # | |
74 | # L1m L2 | |
75 | # o---o | |
76 | # / \ / \ | |
77 | # o X ? | |
78 | # \ / \ / | |
79 | # o---o | |
80 | # R1 R2 | |
81 | # | |
82 | ||
83 | test_expect_success 'setup criss-cross + rename merges with basic modification' ' | |
84 | git rm -rf . && | |
85 | git clean -fdqx && | |
86 | rm -rf .git && | |
87 | git init && | |
88 | ||
99094a7a | 89 | ten="0 1 2 3 4 5 6 7 8 9" && |
583942df EN |
90 | for i in $ten |
91 | do | |
92 | echo line $i in a sample file | |
93 | done >one && | |
94 | for i in $ten | |
95 | do | |
96 | echo line $i in another sample file | |
97 | done >two && | |
98 | git add one two && | |
99 | test_tick && git commit -m initial && | |
100 | ||
101 | git branch L1 && | |
102 | git checkout -b R1 && | |
103 | git mv one three && | |
104 | echo more >>two && | |
105 | git add two && | |
106 | test_tick && git commit -m R1 && | |
107 | ||
108 | git checkout L1 && | |
109 | git mv two three && | |
110 | test_tick && git commit -m L1 && | |
111 | ||
112 | git checkout L1^0 && | |
113 | test_tick && git merge -s ours R1 && | |
114 | git tag L2 && | |
115 | ||
116 | git checkout R1^0 && | |
117 | test_tick && git merge -s ours L1 && | |
118 | git tag R2 | |
119 | ' | |
120 | ||
2a669c34 | 121 | test_expect_success 'merge criss-cross + rename merges with basic modification' ' |
583942df EN |
122 | git reset --hard && |
123 | git checkout L2^0 && | |
124 | ||
125 | test_must_fail git merge -s recursive R2^0 && | |
126 | ||
434b8525 EN |
127 | test 2 = $(git ls-files -s | wc -l) && |
128 | test 2 = $(git ls-files -u | wc -l) && | |
129 | test 2 = $(git ls-files -o | wc -l) && | |
583942df | 130 | |
583942df EN |
131 | test $(git rev-parse :2:three) = $(git rev-parse L2:three) && |
132 | test $(git rev-parse :3:three) = $(git rev-parse R2:three) && | |
133 | ||
434b8525 EN |
134 | test $(git rev-parse L2:three) = $(git hash-object three~HEAD) && |
135 | test $(git rev-parse R2:three) = $(git hash-object three~R2^0) | |
583942df EN |
136 | ' |
137 | ||
f63622c0 EN |
138 | # |
139 | # For the next test, we start with three commits in two lines of development | |
140 | # which setup a rename/add conflict: | |
141 | # Commit A: File 'a' exists | |
142 | # Commit B: Rename 'a' -> 'new_a' | |
143 | # Commit C: Modify 'a', create different 'new_a' | |
144 | # Later, two different people merge and resolve differently: | |
145 | # Commit D: Merge B & C, ignoring separately created 'new_a' | |
146 | # Commit E: Merge B & C making use of some piece of secondary 'new_a' | |
147 | # Finally, someone goes to merge D & E. Does git detect the conflict? | |
148 | # | |
149 | # B D | |
150 | # o---o | |
151 | # / \ / \ | |
152 | # A o X ? F | |
153 | # \ / \ / | |
154 | # o---o | |
155 | # C E | |
156 | # | |
157 | ||
158 | test_expect_success 'setup differently handled merges of rename/add conflict' ' | |
159 | git rm -rf . && | |
160 | git clean -fdqx && | |
161 | rm -rf .git && | |
162 | git init && | |
163 | ||
164 | printf "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n" >a && | |
165 | git add a && | |
166 | test_tick && git commit -m A && | |
167 | ||
168 | git branch B && | |
169 | git checkout -b C && | |
170 | echo 10 >>a && | |
171 | echo "other content" >>new_a && | |
172 | git add a new_a && | |
173 | test_tick && git commit -m C && | |
174 | ||
175 | git checkout B && | |
176 | git mv a new_a && | |
177 | test_tick && git commit -m B && | |
178 | ||
179 | git checkout B^0 && | |
180 | test_must_fail git merge C && | |
181 | git clean -f && | |
182 | test_tick && git commit -m D && | |
183 | git tag D && | |
184 | ||
185 | git checkout C^0 && | |
186 | test_must_fail git merge B && | |
187 | rm new_a~HEAD new_a && | |
188 | printf "Incorrectly merged content" >>new_a && | |
189 | git add -u && | |
190 | test_tick && git commit -m E && | |
191 | git tag E | |
192 | ' | |
193 | ||
2a669c34 | 194 | test_expect_success 'git detects differently handled merges conflict' ' |
f63622c0 EN |
195 | git reset --hard && |
196 | git checkout D^0 && | |
197 | ||
0a5e3c50 | 198 | test_must_fail git merge -s recursive E^0 && |
f63622c0 EN |
199 | |
200 | test 3 = $(git ls-files -s | wc -l) && | |
201 | test 3 = $(git ls-files -u | wc -l) && | |
202 | test 0 = $(git ls-files -o | wc -l) && | |
203 | ||
204 | test $(git rev-parse :2:new_a) = $(git rev-parse D:new_a) && | |
205 | test $(git rev-parse :3:new_a) = $(git rev-parse E:new_a) && | |
206 | ||
207 | git cat-file -p B:new_a >>merged && | |
208 | git cat-file -p C:new_a >>merge-me && | |
209 | >empty && | |
210 | test_must_fail git merge-file \ | |
211 | -L "Temporary merge branch 2" \ | |
212 | -L "" \ | |
213 | -L "Temporary merge branch 1" \ | |
214 | merged empty merge-me && | |
215 | test $(git rev-parse :1:new_a) = $(git hash-object merged) | |
c94736a2 JH |
216 | ' |
217 | ||
fe7e9c23 EN |
218 | # |
219 | # criss-cross + modify/delete: | |
220 | # | |
221 | # B D | |
222 | # o---o | |
223 | # / \ / \ | |
224 | # A o X ? F | |
225 | # \ / \ / | |
226 | # o---o | |
227 | # C E | |
228 | # | |
229 | # Commit A: file with contents 'A\n' | |
230 | # Commit B: file with contents 'B\n' | |
231 | # Commit C: file not present | |
232 | # Commit D: file with contents 'B\n' | |
233 | # Commit E: file not present | |
234 | # | |
235 | # Merging commits D & E should result in modify/delete conflict. | |
236 | ||
237 | test_expect_success 'setup criss-cross + modify/delete resolved differently' ' | |
238 | git rm -rf . && | |
239 | git clean -fdqx && | |
240 | rm -rf .git && | |
241 | git init && | |
242 | ||
243 | echo A >file && | |
244 | git add file && | |
245 | test_tick && | |
246 | git commit -m A && | |
247 | ||
248 | git branch B && | |
249 | git checkout -b C && | |
250 | git rm file && | |
251 | test_tick && | |
252 | git commit -m C && | |
253 | ||
254 | git checkout B && | |
255 | echo B >file && | |
256 | git add file && | |
257 | test_tick && | |
258 | git commit -m B && | |
259 | ||
260 | git checkout B^0 && | |
261 | test_must_fail git merge C && | |
262 | echo B >file && | |
263 | git add file && | |
264 | test_tick && | |
265 | git commit -m D && | |
266 | git tag D && | |
267 | ||
268 | git checkout C^0 && | |
269 | test_must_fail git merge B && | |
270 | git rm file && | |
271 | test_tick && | |
272 | git commit -m E && | |
273 | git tag E | |
274 | ' | |
275 | ||
ec61d149 | 276 | test_expect_success 'git detects conflict merging criss-cross+modify/delete' ' |
fe7e9c23 EN |
277 | git checkout D^0 && |
278 | ||
279 | test_must_fail git merge -s recursive E^0 && | |
280 | ||
281 | test 2 -eq $(git ls-files -s | wc -l) && | |
282 | test 2 -eq $(git ls-files -u | wc -l) && | |
283 | ||
284 | test $(git rev-parse :1:file) = $(git rev-parse master:file) && | |
285 | test $(git rev-parse :2:file) = $(git rev-parse B:file) | |
286 | ' | |
287 | ||
ec61d149 | 288 | test_expect_success 'git detects conflict merging criss-cross+modify/delete, reverse direction' ' |
fe7e9c23 EN |
289 | git reset --hard && |
290 | git checkout E^0 && | |
291 | ||
292 | test_must_fail git merge -s recursive D^0 && | |
293 | ||
294 | test 2 -eq $(git ls-files -s | wc -l) && | |
295 | test 2 -eq $(git ls-files -u | wc -l) && | |
296 | ||
297 | test $(git rev-parse :1:file) = $(git rev-parse master:file) && | |
298 | test $(git rev-parse :3:file) = $(git rev-parse B:file) | |
299 | ' | |
300 | ||
96b079e5 EN |
301 | # |
302 | # criss-cross + modify/modify with very contrived file contents: | |
303 | # | |
304 | # B D | |
305 | # o---o | |
306 | # / \ / \ | |
307 | # A o X ? F | |
308 | # \ / \ / | |
309 | # o---o | |
310 | # C E | |
311 | # | |
312 | # Commit A: file with contents 'A\n' | |
313 | # Commit B: file with contents 'B\n' | |
314 | # Commit C: file with contents 'C\n' | |
315 | # Commit D: file with contents 'D\n' | |
316 | # Commit E: file with contents: | |
317 | # <<<<<<< Temporary merge branch 1 | |
318 | # C | |
319 | # ======= | |
320 | # B | |
321 | # >>>>>>> Temporary merge branch 2 | |
322 | # | |
323 | # Now, when we merge commits D & E, does git detect the conflict? | |
324 | ||
325 | test_expect_success 'setup differently handled merges of content conflict' ' | |
326 | git clean -fdqx && | |
327 | rm -rf .git && | |
328 | git init && | |
329 | ||
330 | echo A >file && | |
331 | git add file && | |
332 | test_tick && | |
333 | git commit -m A && | |
334 | ||
335 | git branch B && | |
336 | git checkout -b C && | |
337 | echo C >file && | |
338 | git add file && | |
339 | test_tick && | |
340 | git commit -m C && | |
341 | ||
342 | git checkout B && | |
343 | echo B >file && | |
344 | git add file && | |
345 | test_tick && | |
346 | git commit -m B && | |
347 | ||
348 | git checkout B^0 && | |
349 | test_must_fail git merge C && | |
350 | echo D >file && | |
351 | git add file && | |
352 | test_tick && | |
353 | git commit -m D && | |
354 | git tag D && | |
355 | ||
356 | git checkout C^0 && | |
357 | test_must_fail git merge B && | |
358 | cat <<EOF >file && | |
359 | <<<<<<< Temporary merge branch 1 | |
360 | C | |
361 | ======= | |
362 | B | |
363 | >>>>>>> Temporary merge branch 2 | |
364 | EOF | |
365 | git add file && | |
366 | test_tick && | |
367 | git commit -m E && | |
368 | git tag E | |
369 | ' | |
370 | ||
371 | test_expect_failure 'git detects conflict w/ criss-cross+contrived resolution' ' | |
372 | git checkout D^0 && | |
373 | ||
374 | test_must_fail git merge -s recursive E^0 && | |
375 | ||
376 | test 3 -eq $(git ls-files -s | wc -l) && | |
377 | test 3 -eq $(git ls-files -u | wc -l) && | |
378 | test 0 -eq $(git ls-files -o | wc -l) && | |
379 | ||
380 | test $(git rev-parse :2:file) = $(git rev-parse D:file) && | |
381 | test $(git rev-parse :3:file) = $(git rev-parse E:file) | |
382 | ' | |
383 | ||
827f2b7d EN |
384 | # |
385 | # criss-cross + d/f conflict via add/add: | |
235e8d59 | 386 | # Commit A: Neither file 'a' nor directory 'a/' exists. |
827f2b7d EN |
387 | # Commit B: Introduce 'a' |
388 | # Commit C: Introduce 'a/file' | |
389 | # Commit D: Merge B & C, keeping 'a' and deleting 'a/' | |
390 | # | |
391 | # Two different later cases: | |
392 | # Commit E1: Merge B & C, deleting 'a' but keeping 'a/file' | |
393 | # Commit E2: Merge B & C, deleting 'a' but keeping a slightly modified 'a/file' | |
394 | # | |
395 | # B D | |
396 | # o---o | |
397 | # / \ / \ | |
398 | # A o X ? F | |
399 | # \ / \ / | |
400 | # o---o | |
401 | # C E1 or E2 | |
402 | # | |
403 | # Merging D & E1 requires we first create a virtual merge base X from | |
404 | # merging A & B in memory. Now, if X could keep both 'a' and 'a/file' in | |
405 | # the index, then the merge of D & E1 could be resolved cleanly with both | |
406 | # 'a' and 'a/file' removed. Since git does not currently allow creating | |
407 | # such a tree, the best we can do is have X contain both 'a~<unique>' and | |
408 | # 'a/file' resulting in the merge of D and E1 having a rename/delete | |
409 | # conflict for 'a'. (Although this merge appears to be unsolvable with git | |
410 | # currently, git could do a lot better than it currently does with these | |
411 | # d/f conflicts, which is the purpose of this test.) | |
412 | # | |
413 | # Merge of D & E2 has similar issues for path 'a', but should always result | |
414 | # in a modify/delete conflict for path 'a/file'. | |
415 | # | |
416 | # We run each merge in both directions, to check for directional issues | |
417 | # with D/F conflict handling. | |
418 | # | |
419 | ||
420 | test_expect_success 'setup differently handled merges of directory/file conflict' ' | |
421 | git rm -rf . && | |
422 | git clean -fdqx && | |
423 | rm -rf .git && | |
424 | git init && | |
425 | ||
426 | >ignore-me && | |
427 | git add ignore-me && | |
428 | test_tick && | |
429 | git commit -m A && | |
430 | git tag A && | |
431 | ||
432 | git branch B && | |
433 | git checkout -b C && | |
434 | mkdir a && | |
435 | echo 10 >a/file && | |
436 | git add a/file && | |
437 | test_tick && | |
438 | git commit -m C && | |
439 | ||
440 | git checkout B && | |
441 | echo 5 >a && | |
442 | git add a && | |
443 | test_tick && | |
444 | git commit -m B && | |
445 | ||
446 | git checkout B^0 && | |
447 | test_must_fail git merge C && | |
448 | git clean -f && | |
449 | rm -rf a/ && | |
450 | echo 5 >a && | |
451 | git add a && | |
452 | test_tick && | |
453 | git commit -m D && | |
454 | git tag D && | |
455 | ||
456 | git checkout C^0 && | |
457 | test_must_fail git merge B && | |
458 | git clean -f && | |
459 | git rm --cached a && | |
460 | echo 10 >a/file && | |
461 | git add a/file && | |
462 | test_tick && | |
463 | git commit -m E1 && | |
464 | git tag E1 && | |
465 | ||
466 | git checkout C^0 && | |
467 | test_must_fail git merge B && | |
468 | git clean -f && | |
469 | git rm --cached a && | |
470 | printf "10\n11\n" >a/file && | |
471 | git add a/file && | |
472 | test_tick && | |
473 | git commit -m E2 && | |
474 | git tag E2 | |
475 | ' | |
476 | ||
ed0148a5 | 477 | test_expect_success 'merge of D & E1 fails but has appropriate contents' ' |
827f2b7d EN |
478 | get_clean_checkout D^0 && |
479 | ||
480 | test_must_fail git merge -s recursive E1^0 && | |
481 | ||
482 | test 2 -eq $(git ls-files -s | wc -l) && | |
483 | test 1 -eq $(git ls-files -u | wc -l) && | |
484 | test 0 -eq $(git ls-files -o | wc -l) && | |
485 | ||
486 | test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) && | |
487 | test $(git rev-parse :2:a) = $(git rev-parse B:a) | |
488 | ' | |
489 | ||
7b1c610f | 490 | test_expect_success 'merge of E1 & D fails but has appropriate contents' ' |
827f2b7d EN |
491 | get_clean_checkout E1^0 && |
492 | ||
493 | test_must_fail git merge -s recursive D^0 && | |
494 | ||
495 | test 2 -eq $(git ls-files -s | wc -l) && | |
496 | test 1 -eq $(git ls-files -u | wc -l) && | |
497 | test 0 -eq $(git ls-files -o | wc -l) && | |
498 | ||
499 | test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) && | |
500 | test $(git rev-parse :3:a) = $(git rev-parse B:a) | |
501 | ' | |
502 | ||
503 | test_expect_success 'merge of D & E2 fails but has appropriate contents' ' | |
504 | get_clean_checkout D^0 && | |
505 | ||
506 | test_must_fail git merge -s recursive E2^0 && | |
507 | ||
508 | test 4 -eq $(git ls-files -s | wc -l) && | |
509 | test 3 -eq $(git ls-files -u | wc -l) && | |
510 | test 1 -eq $(git ls-files -o | wc -l) && | |
511 | ||
512 | test $(git rev-parse :2:a) = $(git rev-parse B:a) && | |
513 | test $(git rev-parse :3:a/file) = $(git rev-parse E2:a/file) && | |
514 | test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) && | |
515 | test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) && | |
516 | ||
517 | test -f a~HEAD | |
518 | ' | |
519 | ||
7b1c610f | 520 | test_expect_success 'merge of E2 & D fails but has appropriate contents' ' |
827f2b7d EN |
521 | get_clean_checkout E2^0 && |
522 | ||
523 | test_must_fail git merge -s recursive D^0 && | |
524 | ||
525 | test 4 -eq $(git ls-files -s | wc -l) && | |
526 | test 3 -eq $(git ls-files -u | wc -l) && | |
527 | test 1 -eq $(git ls-files -o | wc -l) && | |
528 | ||
529 | test $(git rev-parse :3:a) = $(git rev-parse B:a) && | |
530 | test $(git rev-parse :2:a/file) = $(git rev-parse E2:a/file) && | |
8fb26872 | 531 | test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) && |
827f2b7d EN |
532 | test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) && |
533 | ||
534 | test -f a~D^0 | |
535 | ' | |
536 | ||
a0d33116 EN |
537 | # |
538 | # criss-cross with rename/rename(1to2)/modify followed by | |
539 | # rename/rename(2to1)/modify: | |
540 | # | |
541 | # B D | |
542 | # o---o | |
543 | # / \ / \ | |
544 | # A o X ? F | |
545 | # \ / \ / | |
546 | # o---o | |
547 | # C E | |
548 | # | |
549 | # Commit A: new file: a | |
550 | # Commit B: rename a->b, modifying by adding a line | |
551 | # Commit C: rename a->c | |
552 | # Commit D: merge B&C, resolving conflict by keeping contents in newname | |
553 | # Commit E: merge B&C, resolving conflict similar to D but adding another line | |
554 | # | |
555 | # There is a conflict merging B & C, but one of filename not of file | |
556 | # content. Whoever created D and E chose specific resolutions for that | |
557 | # conflict resolution. Now, since: (1) there is no content conflict | |
558 | # merging B & C, (2) D does not modify that merged content further, and (3) | |
559 | # both D & E resolve the name conflict in the same way, the modification to | |
560 | # newname in E should not cause any conflicts when it is merged with D. | |
561 | # (Note that this can be accomplished by having the virtual merge base have | |
562 | # the merged contents of b and c stored in a file named a, which seems like | |
563 | # the most logical choice anyway.) | |
564 | # | |
565 | # Comment from Junio: I do not necessarily agree with the choice "a", but | |
566 | # it feels sound to say "B and C do not agree what the final pathname | |
567 | # should be, but we know this content was derived from the common A:a so we | |
568 | # use one path whose name is arbitrary in the virtual merge base X between | |
569 | # D and E" and then further let the rename detection to notice that that | |
570 | # arbitrary path gets renamed between X-D to "newname" and X-E also to | |
571 | # "newname" to resolve it as both sides renaming it to the same new | |
572 | # name. It is akin to what we do at the content level, i.e. "B and C do not | |
573 | # agree what the final contents should be, so we leave the conflict marker | |
574 | # but that may cancel out at the final merge stage". | |
575 | ||
576 | test_expect_success 'setup rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' ' | |
577 | git reset --hard && | |
578 | git rm -rf . && | |
579 | git clean -fdqx && | |
580 | rm -rf .git && | |
581 | git init && | |
582 | ||
583 | printf "1\n2\n3\n4\n5\n6\n" >a && | |
584 | git add a && | |
585 | git commit -m A && | |
586 | git tag A && | |
587 | ||
588 | git checkout -b B A && | |
589 | git mv a b && | |
590 | echo 7 >>b && | |
591 | git add -u && | |
592 | git commit -m B && | |
593 | ||
594 | git checkout -b C A && | |
595 | git mv a c && | |
596 | git commit -m C && | |
597 | ||
598 | git checkout -q B^0 && | |
599 | git merge --no-commit -s ours C^0 && | |
600 | git mv b newname && | |
601 | git commit -m "Merge commit C^0 into HEAD" && | |
602 | git tag D && | |
603 | ||
604 | git checkout -q C^0 && | |
605 | git merge --no-commit -s ours B^0 && | |
606 | git mv c newname && | |
607 | printf "7\n8\n" >>newname && | |
608 | git add -u && | |
609 | git commit -m "Merge commit B^0 into HEAD" && | |
610 | git tag E | |
611 | ' | |
612 | ||
c52ff85d | 613 | test_expect_success 'handle rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' ' |
a0d33116 EN |
614 | git checkout D^0 && |
615 | ||
616 | git merge -s recursive E^0 && | |
617 | ||
618 | test 1 -eq $(git ls-files -s | wc -l) && | |
619 | test 0 -eq $(git ls-files -u | wc -l) && | |
620 | test 0 -eq $(git ls-files -o | wc -l) && | |
621 | ||
622 | test $(git rev-parse HEAD:newname) = $(git rev-parse E:newname) | |
623 | ' | |
624 | ||
0b35deb3 EN |
625 | # |
626 | # criss-cross with rename/rename(1to2)/add-source + resolvable modify/modify: | |
627 | # | |
628 | # B D | |
629 | # o---o | |
630 | # / \ / \ | |
631 | # A o X ? F | |
632 | # \ / \ / | |
633 | # o---o | |
634 | # C E | |
635 | # | |
636 | # Commit A: new file: a | |
637 | # Commit B: rename a->b | |
638 | # Commit C: rename a->c, add different a | |
639 | # Commit D: merge B&C, keeping b&c and (new) a modified at beginning | |
640 | # Commit E: merge B&C, keeping b&c and (new) a modified at end | |
641 | # | |
642 | # Merging commits D & E should result in no conflict; doing so correctly | |
643 | # requires getting the virtual merge base (from merging B&C) right, handling | |
644 | # renaming carefully (both in the virtual merge base and later), and getting | |
645 | # content merge handled. | |
646 | ||
647 | test_expect_success 'setup criss-cross + rename/rename/add + modify/modify' ' | |
648 | git rm -rf . && | |
649 | git clean -fdqx && | |
650 | rm -rf .git && | |
651 | git init && | |
652 | ||
653 | printf "lots\nof\nwords\nand\ncontent\n" >a && | |
654 | git add a && | |
655 | git commit -m A && | |
656 | git tag A && | |
657 | ||
658 | git checkout -b B A && | |
659 | git mv a b && | |
660 | git commit -m B && | |
661 | ||
662 | git checkout -b C A && | |
663 | git mv a c && | |
664 | printf "2\n3\n4\n5\n6\n7\n" >a && | |
665 | git add a && | |
666 | git commit -m C && | |
667 | ||
668 | git checkout B^0 && | |
669 | git merge --no-commit -s ours C^0 && | |
670 | git checkout C -- a c && | |
671 | mv a old_a && | |
672 | echo 1 >a && | |
673 | cat old_a >>a && | |
674 | rm old_a && | |
675 | git add -u && | |
676 | git commit -m "Merge commit C^0 into HEAD" && | |
677 | git tag D && | |
678 | ||
679 | git checkout C^0 && | |
680 | git merge --no-commit -s ours B^0 && | |
681 | git checkout B -- b && | |
682 | echo 8 >>a && | |
683 | git add -u && | |
684 | git commit -m "Merge commit B^0 into HEAD" && | |
685 | git tag E | |
686 | ' | |
687 | ||
688 | test_expect_failure 'detect rename/rename/add-source for virtual merge-base' ' | |
689 | git checkout D^0 && | |
690 | ||
691 | git merge -s recursive E^0 && | |
692 | ||
693 | test 3 -eq $(git ls-files -s | wc -l) && | |
694 | test 0 -eq $(git ls-files -u | wc -l) && | |
695 | test 0 -eq $(git ls-files -o | wc -l) && | |
696 | ||
697 | test $(git rev-parse HEAD:b) = $(git rev-parse A:a) && | |
698 | test $(git rev-parse HEAD:c) = $(git rev-parse A:a) && | |
699 | test "$(cat a)" = "$(printf "1\n2\n3\n4\n5\n6\n7\n8\n")" | |
700 | ' | |
701 | ||
b630b814 EN |
702 | # |
703 | # criss-cross with rename/rename(1to2)/add-dest + simple modify: | |
704 | # | |
705 | # B D | |
706 | # o---o | |
707 | # / \ / \ | |
708 | # A o X ? F | |
709 | # \ / \ / | |
710 | # o---o | |
711 | # C E | |
712 | # | |
713 | # Commit A: new file: a | |
714 | # Commit B: rename a->b, add c | |
715 | # Commit C: rename a->c | |
716 | # Commit D: merge B&C, keeping A:a and B:c | |
717 | # Commit E: merge B&C, keeping A:a and slightly modified c from B | |
718 | # | |
719 | # Merging commits D & E should result in no conflict. The virtual merge | |
720 | # base of B & C needs to not delete B:c for that to work, though... | |
721 | ||
722 | test_expect_success 'setup criss-cross+rename/rename/add-dest + simple modify' ' | |
723 | git rm -rf . && | |
724 | git clean -fdqx && | |
725 | rm -rf .git && | |
726 | git init && | |
727 | ||
728 | >a && | |
729 | git add a && | |
730 | git commit -m A && | |
731 | git tag A && | |
732 | ||
733 | git checkout -b B A && | |
734 | git mv a b && | |
735 | printf "1\n2\n3\n4\n5\n6\n7\n" >c && | |
736 | git add c && | |
737 | git commit -m B && | |
738 | ||
739 | git checkout -b C A && | |
740 | git mv a c && | |
741 | git commit -m C && | |
742 | ||
743 | git checkout B^0 && | |
744 | git merge --no-commit -s ours C^0 && | |
745 | git mv b a && | |
746 | git commit -m "D is like B but renames b back to a" && | |
747 | git tag D && | |
748 | ||
749 | git checkout B^0 && | |
750 | git merge --no-commit -s ours C^0 && | |
751 | git mv b a && | |
752 | echo 8 >>c && | |
753 | git add c && | |
754 | git commit -m "E like D but has mod in c" && | |
755 | git tag E | |
756 | ' | |
757 | ||
6d63070c | 758 | test_expect_success 'virtual merge base handles rename/rename(1to2)/add-dest' ' |
b630b814 EN |
759 | git checkout D^0 && |
760 | ||
761 | git merge -s recursive E^0 && | |
762 | ||
763 | test 2 -eq $(git ls-files -s | wc -l) && | |
764 | test 0 -eq $(git ls-files -u | wc -l) && | |
765 | test 0 -eq $(git ls-files -o | wc -l) && | |
766 | ||
767 | test $(git rev-parse HEAD:a) = $(git rev-parse A:a) && | |
768 | test $(git rev-parse HEAD:c) = $(git rev-parse E:c) | |
769 | ' | |
770 | ||
c94736a2 | 771 | test_done |