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 && | |
d694a179 JH |
215 | sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal && |
216 | test $(git rev-parse :1:new_a) = $(git hash-object merged-internal) | |
c94736a2 JH |
217 | ' |
218 | ||
fe7e9c23 EN |
219 | # |
220 | # criss-cross + modify/delete: | |
221 | # | |
222 | # B D | |
223 | # o---o | |
224 | # / \ / \ | |
225 | # A o X ? F | |
226 | # \ / \ / | |
227 | # o---o | |
228 | # C E | |
229 | # | |
230 | # Commit A: file with contents 'A\n' | |
231 | # Commit B: file with contents 'B\n' | |
232 | # Commit C: file not present | |
233 | # Commit D: file with contents 'B\n' | |
234 | # Commit E: file not present | |
235 | # | |
236 | # Merging commits D & E should result in modify/delete conflict. | |
237 | ||
238 | test_expect_success 'setup criss-cross + modify/delete resolved differently' ' | |
239 | git rm -rf . && | |
240 | git clean -fdqx && | |
241 | rm -rf .git && | |
242 | git init && | |
243 | ||
244 | echo A >file && | |
245 | git add file && | |
246 | test_tick && | |
247 | git commit -m A && | |
248 | ||
249 | git branch B && | |
250 | git checkout -b C && | |
251 | git rm file && | |
252 | test_tick && | |
253 | git commit -m C && | |
254 | ||
255 | git checkout B && | |
256 | echo B >file && | |
257 | git add file && | |
258 | test_tick && | |
259 | git commit -m B && | |
260 | ||
261 | git checkout B^0 && | |
262 | test_must_fail git merge C && | |
263 | echo B >file && | |
264 | git add file && | |
265 | test_tick && | |
266 | git commit -m D && | |
267 | git tag D && | |
268 | ||
269 | git checkout C^0 && | |
270 | test_must_fail git merge B && | |
271 | git rm file && | |
272 | test_tick && | |
273 | git commit -m E && | |
274 | git tag E | |
275 | ' | |
276 | ||
ec61d149 | 277 | test_expect_success 'git detects conflict merging criss-cross+modify/delete' ' |
fe7e9c23 EN |
278 | git checkout D^0 && |
279 | ||
280 | test_must_fail git merge -s recursive E^0 && | |
281 | ||
282 | test 2 -eq $(git ls-files -s | wc -l) && | |
283 | test 2 -eq $(git ls-files -u | wc -l) && | |
284 | ||
285 | test $(git rev-parse :1:file) = $(git rev-parse master:file) && | |
286 | test $(git rev-parse :2:file) = $(git rev-parse B:file) | |
287 | ' | |
288 | ||
ec61d149 | 289 | test_expect_success 'git detects conflict merging criss-cross+modify/delete, reverse direction' ' |
fe7e9c23 EN |
290 | git reset --hard && |
291 | git checkout E^0 && | |
292 | ||
293 | test_must_fail git merge -s recursive D^0 && | |
294 | ||
295 | test 2 -eq $(git ls-files -s | wc -l) && | |
296 | test 2 -eq $(git ls-files -u | wc -l) && | |
297 | ||
298 | test $(git rev-parse :1:file) = $(git rev-parse master:file) && | |
299 | test $(git rev-parse :3:file) = $(git rev-parse B:file) | |
300 | ' | |
301 | ||
827f2b7d EN |
302 | # |
303 | # criss-cross + d/f conflict via add/add: | |
235e8d59 | 304 | # Commit A: Neither file 'a' nor directory 'a/' exists. |
827f2b7d EN |
305 | # Commit B: Introduce 'a' |
306 | # Commit C: Introduce 'a/file' | |
307 | # Commit D: Merge B & C, keeping 'a' and deleting 'a/' | |
308 | # | |
309 | # Two different later cases: | |
310 | # Commit E1: Merge B & C, deleting 'a' but keeping 'a/file' | |
311 | # Commit E2: Merge B & C, deleting 'a' but keeping a slightly modified 'a/file' | |
312 | # | |
313 | # B D | |
314 | # o---o | |
315 | # / \ / \ | |
316 | # A o X ? F | |
317 | # \ / \ / | |
318 | # o---o | |
319 | # C E1 or E2 | |
320 | # | |
321 | # Merging D & E1 requires we first create a virtual merge base X from | |
322 | # merging A & B in memory. Now, if X could keep both 'a' and 'a/file' in | |
323 | # the index, then the merge of D & E1 could be resolved cleanly with both | |
324 | # 'a' and 'a/file' removed. Since git does not currently allow creating | |
325 | # such a tree, the best we can do is have X contain both 'a~<unique>' and | |
326 | # 'a/file' resulting in the merge of D and E1 having a rename/delete | |
327 | # conflict for 'a'. (Although this merge appears to be unsolvable with git | |
328 | # currently, git could do a lot better than it currently does with these | |
329 | # d/f conflicts, which is the purpose of this test.) | |
330 | # | |
331 | # Merge of D & E2 has similar issues for path 'a', but should always result | |
332 | # in a modify/delete conflict for path 'a/file'. | |
333 | # | |
334 | # We run each merge in both directions, to check for directional issues | |
335 | # with D/F conflict handling. | |
336 | # | |
337 | ||
338 | test_expect_success 'setup differently handled merges of directory/file conflict' ' | |
339 | git rm -rf . && | |
340 | git clean -fdqx && | |
341 | rm -rf .git && | |
342 | git init && | |
343 | ||
344 | >ignore-me && | |
345 | git add ignore-me && | |
346 | test_tick && | |
347 | git commit -m A && | |
348 | git tag A && | |
349 | ||
350 | git branch B && | |
351 | git checkout -b C && | |
352 | mkdir a && | |
353 | echo 10 >a/file && | |
354 | git add a/file && | |
355 | test_tick && | |
356 | git commit -m C && | |
357 | ||
358 | git checkout B && | |
359 | echo 5 >a && | |
360 | git add a && | |
361 | test_tick && | |
362 | git commit -m B && | |
363 | ||
364 | git checkout B^0 && | |
365 | test_must_fail git merge C && | |
366 | git clean -f && | |
367 | rm -rf a/ && | |
368 | echo 5 >a && | |
369 | git add a && | |
370 | test_tick && | |
371 | git commit -m D && | |
372 | git tag D && | |
373 | ||
374 | git checkout C^0 && | |
375 | test_must_fail git merge B && | |
376 | git clean -f && | |
377 | git rm --cached a && | |
378 | echo 10 >a/file && | |
379 | git add a/file && | |
380 | test_tick && | |
381 | git commit -m E1 && | |
382 | git tag E1 && | |
383 | ||
384 | git checkout C^0 && | |
385 | test_must_fail git merge B && | |
386 | git clean -f && | |
387 | git rm --cached a && | |
388 | printf "10\n11\n" >a/file && | |
389 | git add a/file && | |
390 | test_tick && | |
391 | git commit -m E2 && | |
392 | git tag E2 | |
393 | ' | |
394 | ||
ed0148a5 | 395 | test_expect_success 'merge of D & E1 fails but has appropriate contents' ' |
827f2b7d EN |
396 | get_clean_checkout D^0 && |
397 | ||
398 | test_must_fail git merge -s recursive E1^0 && | |
399 | ||
400 | test 2 -eq $(git ls-files -s | wc -l) && | |
401 | test 1 -eq $(git ls-files -u | wc -l) && | |
402 | test 0 -eq $(git ls-files -o | wc -l) && | |
403 | ||
404 | test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) && | |
405 | test $(git rev-parse :2:a) = $(git rev-parse B:a) | |
406 | ' | |
407 | ||
7b1c610f | 408 | test_expect_success 'merge of E1 & D fails but has appropriate contents' ' |
827f2b7d EN |
409 | get_clean_checkout E1^0 && |
410 | ||
411 | test_must_fail git merge -s recursive D^0 && | |
412 | ||
413 | test 2 -eq $(git ls-files -s | wc -l) && | |
414 | test 1 -eq $(git ls-files -u | wc -l) && | |
415 | test 0 -eq $(git ls-files -o | wc -l) && | |
416 | ||
417 | test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) && | |
418 | test $(git rev-parse :3:a) = $(git rev-parse B:a) | |
419 | ' | |
420 | ||
421 | test_expect_success 'merge of D & E2 fails but has appropriate contents' ' | |
422 | get_clean_checkout D^0 && | |
423 | ||
424 | test_must_fail git merge -s recursive E2^0 && | |
425 | ||
426 | test 4 -eq $(git ls-files -s | wc -l) && | |
427 | test 3 -eq $(git ls-files -u | wc -l) && | |
428 | test 1 -eq $(git ls-files -o | wc -l) && | |
429 | ||
430 | test $(git rev-parse :2:a) = $(git rev-parse B:a) && | |
431 | test $(git rev-parse :3:a/file) = $(git rev-parse E2:a/file) && | |
432 | test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) && | |
433 | test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) && | |
434 | ||
435 | test -f a~HEAD | |
436 | ' | |
437 | ||
7b1c610f | 438 | test_expect_success 'merge of E2 & D fails but has appropriate contents' ' |
827f2b7d EN |
439 | get_clean_checkout E2^0 && |
440 | ||
441 | test_must_fail git merge -s recursive D^0 && | |
442 | ||
443 | test 4 -eq $(git ls-files -s | wc -l) && | |
444 | test 3 -eq $(git ls-files -u | wc -l) && | |
445 | test 1 -eq $(git ls-files -o | wc -l) && | |
446 | ||
447 | test $(git rev-parse :3:a) = $(git rev-parse B:a) && | |
448 | test $(git rev-parse :2:a/file) = $(git rev-parse E2:a/file) && | |
8fb26872 | 449 | test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) && |
827f2b7d EN |
450 | test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) && |
451 | ||
452 | test -f a~D^0 | |
453 | ' | |
454 | ||
a0d33116 EN |
455 | # |
456 | # criss-cross with rename/rename(1to2)/modify followed by | |
457 | # rename/rename(2to1)/modify: | |
458 | # | |
459 | # B D | |
460 | # o---o | |
461 | # / \ / \ | |
462 | # A o X ? F | |
463 | # \ / \ / | |
464 | # o---o | |
465 | # C E | |
466 | # | |
467 | # Commit A: new file: a | |
468 | # Commit B: rename a->b, modifying by adding a line | |
469 | # Commit C: rename a->c | |
470 | # Commit D: merge B&C, resolving conflict by keeping contents in newname | |
471 | # Commit E: merge B&C, resolving conflict similar to D but adding another line | |
472 | # | |
473 | # There is a conflict merging B & C, but one of filename not of file | |
474 | # content. Whoever created D and E chose specific resolutions for that | |
475 | # conflict resolution. Now, since: (1) there is no content conflict | |
476 | # merging B & C, (2) D does not modify that merged content further, and (3) | |
477 | # both D & E resolve the name conflict in the same way, the modification to | |
478 | # newname in E should not cause any conflicts when it is merged with D. | |
479 | # (Note that this can be accomplished by having the virtual merge base have | |
480 | # the merged contents of b and c stored in a file named a, which seems like | |
481 | # the most logical choice anyway.) | |
482 | # | |
483 | # Comment from Junio: I do not necessarily agree with the choice "a", but | |
484 | # it feels sound to say "B and C do not agree what the final pathname | |
485 | # should be, but we know this content was derived from the common A:a so we | |
486 | # use one path whose name is arbitrary in the virtual merge base X between | |
487 | # D and E" and then further let the rename detection to notice that that | |
488 | # arbitrary path gets renamed between X-D to "newname" and X-E also to | |
489 | # "newname" to resolve it as both sides renaming it to the same new | |
490 | # name. It is akin to what we do at the content level, i.e. "B and C do not | |
491 | # agree what the final contents should be, so we leave the conflict marker | |
492 | # but that may cancel out at the final merge stage". | |
493 | ||
494 | test_expect_success 'setup rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' ' | |
495 | git reset --hard && | |
496 | git rm -rf . && | |
497 | git clean -fdqx && | |
498 | rm -rf .git && | |
499 | git init && | |
500 | ||
501 | printf "1\n2\n3\n4\n5\n6\n" >a && | |
502 | git add a && | |
503 | git commit -m A && | |
504 | git tag A && | |
505 | ||
506 | git checkout -b B A && | |
507 | git mv a b && | |
508 | echo 7 >>b && | |
509 | git add -u && | |
510 | git commit -m B && | |
511 | ||
512 | git checkout -b C A && | |
513 | git mv a c && | |
514 | git commit -m C && | |
515 | ||
516 | git checkout -q B^0 && | |
517 | git merge --no-commit -s ours C^0 && | |
518 | git mv b newname && | |
519 | git commit -m "Merge commit C^0 into HEAD" && | |
520 | git tag D && | |
521 | ||
522 | git checkout -q C^0 && | |
523 | git merge --no-commit -s ours B^0 && | |
524 | git mv c newname && | |
525 | printf "7\n8\n" >>newname && | |
526 | git add -u && | |
527 | git commit -m "Merge commit B^0 into HEAD" && | |
528 | git tag E | |
529 | ' | |
530 | ||
c52ff85d | 531 | test_expect_success 'handle rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' ' |
a0d33116 EN |
532 | git checkout D^0 && |
533 | ||
534 | git merge -s recursive E^0 && | |
535 | ||
536 | test 1 -eq $(git ls-files -s | wc -l) && | |
537 | test 0 -eq $(git ls-files -u | wc -l) && | |
538 | test 0 -eq $(git ls-files -o | wc -l) && | |
539 | ||
540 | test $(git rev-parse HEAD:newname) = $(git rev-parse E:newname) | |
541 | ' | |
542 | ||
0b35deb3 EN |
543 | # |
544 | # criss-cross with rename/rename(1to2)/add-source + resolvable modify/modify: | |
545 | # | |
546 | # B D | |
547 | # o---o | |
548 | # / \ / \ | |
549 | # A o X ? F | |
550 | # \ / \ / | |
551 | # o---o | |
552 | # C E | |
553 | # | |
554 | # Commit A: new file: a | |
555 | # Commit B: rename a->b | |
556 | # Commit C: rename a->c, add different a | |
557 | # Commit D: merge B&C, keeping b&c and (new) a modified at beginning | |
558 | # Commit E: merge B&C, keeping b&c and (new) a modified at end | |
559 | # | |
560 | # Merging commits D & E should result in no conflict; doing so correctly | |
561 | # requires getting the virtual merge base (from merging B&C) right, handling | |
562 | # renaming carefully (both in the virtual merge base and later), and getting | |
563 | # content merge handled. | |
564 | ||
565 | test_expect_success 'setup criss-cross + rename/rename/add + modify/modify' ' | |
566 | git rm -rf . && | |
567 | git clean -fdqx && | |
568 | rm -rf .git && | |
569 | git init && | |
570 | ||
571 | printf "lots\nof\nwords\nand\ncontent\n" >a && | |
572 | git add a && | |
573 | git commit -m A && | |
574 | git tag A && | |
575 | ||
576 | git checkout -b B A && | |
577 | git mv a b && | |
578 | git commit -m B && | |
579 | ||
580 | git checkout -b C A && | |
581 | git mv a c && | |
582 | printf "2\n3\n4\n5\n6\n7\n" >a && | |
583 | git add a && | |
584 | git commit -m C && | |
585 | ||
586 | git checkout B^0 && | |
587 | git merge --no-commit -s ours C^0 && | |
588 | git checkout C -- a c && | |
589 | mv a old_a && | |
590 | echo 1 >a && | |
591 | cat old_a >>a && | |
592 | rm old_a && | |
593 | git add -u && | |
594 | git commit -m "Merge commit C^0 into HEAD" && | |
595 | git tag D && | |
596 | ||
597 | git checkout C^0 && | |
598 | git merge --no-commit -s ours B^0 && | |
599 | git checkout B -- b && | |
600 | echo 8 >>a && | |
601 | git add -u && | |
602 | git commit -m "Merge commit B^0 into HEAD" && | |
603 | git tag E | |
604 | ' | |
605 | ||
606 | test_expect_failure 'detect rename/rename/add-source for virtual merge-base' ' | |
607 | git checkout D^0 && | |
608 | ||
609 | git merge -s recursive E^0 && | |
610 | ||
611 | test 3 -eq $(git ls-files -s | wc -l) && | |
612 | test 0 -eq $(git ls-files -u | wc -l) && | |
613 | test 0 -eq $(git ls-files -o | wc -l) && | |
614 | ||
615 | test $(git rev-parse HEAD:b) = $(git rev-parse A:a) && | |
616 | test $(git rev-parse HEAD:c) = $(git rev-parse A:a) && | |
617 | test "$(cat a)" = "$(printf "1\n2\n3\n4\n5\n6\n7\n8\n")" | |
618 | ' | |
619 | ||
b630b814 EN |
620 | # |
621 | # criss-cross with rename/rename(1to2)/add-dest + simple modify: | |
622 | # | |
623 | # B D | |
624 | # o---o | |
625 | # / \ / \ | |
626 | # A o X ? F | |
627 | # \ / \ / | |
628 | # o---o | |
629 | # C E | |
630 | # | |
631 | # Commit A: new file: a | |
632 | # Commit B: rename a->b, add c | |
633 | # Commit C: rename a->c | |
634 | # Commit D: merge B&C, keeping A:a and B:c | |
635 | # Commit E: merge B&C, keeping A:a and slightly modified c from B | |
636 | # | |
637 | # Merging commits D & E should result in no conflict. The virtual merge | |
638 | # base of B & C needs to not delete B:c for that to work, though... | |
639 | ||
640 | test_expect_success 'setup criss-cross+rename/rename/add-dest + simple modify' ' | |
641 | git rm -rf . && | |
642 | git clean -fdqx && | |
643 | rm -rf .git && | |
644 | git init && | |
645 | ||
646 | >a && | |
647 | git add a && | |
648 | git commit -m A && | |
649 | git tag A && | |
650 | ||
651 | git checkout -b B A && | |
652 | git mv a b && | |
653 | printf "1\n2\n3\n4\n5\n6\n7\n" >c && | |
654 | git add c && | |
655 | git commit -m B && | |
656 | ||
657 | git checkout -b C A && | |
658 | git mv a c && | |
659 | git commit -m C && | |
660 | ||
661 | git checkout B^0 && | |
662 | git merge --no-commit -s ours C^0 && | |
663 | git mv b a && | |
664 | git commit -m "D is like B but renames b back to a" && | |
665 | git tag D && | |
666 | ||
667 | git checkout B^0 && | |
668 | git merge --no-commit -s ours C^0 && | |
669 | git mv b a && | |
670 | echo 8 >>c && | |
671 | git add c && | |
672 | git commit -m "E like D but has mod in c" && | |
673 | git tag E | |
674 | ' | |
675 | ||
6d63070c | 676 | test_expect_success 'virtual merge base handles rename/rename(1to2)/add-dest' ' |
b630b814 EN |
677 | git checkout D^0 && |
678 | ||
679 | git merge -s recursive E^0 && | |
680 | ||
681 | test 2 -eq $(git ls-files -s | wc -l) && | |
682 | test 0 -eq $(git ls-files -u | wc -l) && | |
683 | test 0 -eq $(git ls-files -o | wc -l) && | |
684 | ||
685 | test $(git rev-parse HEAD:a) = $(git rev-parse A:a) && | |
686 | test $(git rev-parse HEAD:c) = $(git rev-parse E:c) | |
687 | ' | |
688 | ||
c94736a2 | 689 | test_done |