]>
Commit | Line | Data |
---|---|---|
c94736a2 JH |
1 | #!/bin/sh |
2 | ||
695576fd | 3 | test_description='recursive merge corner cases involving criss-cross merges' |
c94736a2 | 4 | |
5902f5f4 | 5 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main |
334afbc7 JS |
6 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME |
7 | ||
716a6b2c | 8 | TEST_PASSES_SANITIZE_LEAK=true |
c94736a2 | 9 | . ./test-lib.sh |
f06481f1 | 10 | . "$TEST_DIRECTORY"/lib-merge.sh |
c94736a2 JH |
11 | |
12 | # | |
13 | # L1 L2 | |
14 | # o---o | |
15 | # / \ / \ | |
16 | # o X ? | |
17 | # \ / \ / | |
18 | # o---o | |
19 | # R1 R2 | |
20 | # | |
21 | ||
c976260d | 22 | test_expect_success 'setup basic criss-cross + rename with no modifications' ' |
6693fb3f | 23 | git init basic-rename && |
2a4c19ef EN |
24 | ( |
25 | cd basic-rename && | |
26 | ||
27 | ten="0 1 2 3 4 5 6 7 8 9" && | |
efe26b9e ES |
28 | printf "line %d in a sample file\n" $ten >one && |
29 | printf "line %d in another sample file\n" $ten >two && | |
2a4c19ef EN |
30 | git add one two && |
31 | test_tick && git commit -m initial && | |
32 | ||
33 | git branch L1 && | |
34 | git checkout -b R1 && | |
35 | git mv one three && | |
36 | test_tick && git commit -m R1 && | |
37 | ||
38 | git checkout L1 && | |
39 | git mv two three && | |
40 | test_tick && git commit -m L1 && | |
41 | ||
42 | git checkout L1^0 && | |
43 | test_tick && git merge -s ours R1 && | |
44 | git tag L2 && | |
45 | ||
46 | git checkout R1^0 && | |
47 | test_tick && git merge -s ours L1 && | |
48 | git tag R2 | |
49 | ) | |
c94736a2 JH |
50 | ' |
51 | ||
c976260d | 52 | test_expect_success 'merge simple rename+criss-cross with no modifications' ' |
2a4c19ef EN |
53 | ( |
54 | cd basic-rename && | |
55 | ||
56 | git reset --hard && | |
57 | git checkout L2^0 && | |
c94736a2 | 58 | |
2a4c19ef | 59 | test_must_fail git merge -s recursive R2^0 && |
c976260d | 60 | |
0cdabc10 | 61 | git ls-files -s >out && |
80205040 | 62 | test_line_count = 5 out && |
0cdabc10 | 63 | git ls-files -u >out && |
80205040 | 64 | test_line_count = 3 out && |
0cdabc10 | 65 | git ls-files -o >out && |
bbafc9c4 | 66 | test_line_count = 1 out && |
c976260d | 67 | |
6ac767e5 | 68 | git rev-parse >expect \ |
6ac767e5 EN |
69 | L2:three R2:three && |
70 | git rev-parse >actual \ | |
71 | :2:three :3:three && | |
6ac767e5 | 72 | test_cmp expect actual |
2a4c19ef | 73 | ) |
c94736a2 JH |
74 | ' |
75 | ||
583942df EN |
76 | # |
77 | # Same as before, but modify L1 slightly: | |
78 | # | |
79 | # L1m L2 | |
80 | # o---o | |
81 | # / \ / \ | |
82 | # o X ? | |
83 | # \ / \ / | |
84 | # o---o | |
85 | # R1 R2 | |
86 | # | |
87 | ||
88 | test_expect_success 'setup criss-cross + rename merges with basic modification' ' | |
6693fb3f | 89 | git init rename-modify && |
2a4c19ef EN |
90 | ( |
91 | cd rename-modify && | |
92 | ||
93 | ten="0 1 2 3 4 5 6 7 8 9" && | |
efe26b9e ES |
94 | printf "line %d in a sample file\n" $ten >one && |
95 | printf "line %d in another sample file\n" $ten >two && | |
2a4c19ef EN |
96 | git add one two && |
97 | test_tick && git commit -m initial && | |
98 | ||
99 | git branch L1 && | |
100 | git checkout -b R1 && | |
101 | git mv one three && | |
102 | echo more >>two && | |
103 | git add two && | |
104 | test_tick && git commit -m R1 && | |
105 | ||
106 | git checkout L1 && | |
107 | git mv two three && | |
108 | test_tick && git commit -m L1 && | |
109 | ||
110 | git checkout L1^0 && | |
111 | test_tick && git merge -s ours R1 && | |
112 | git tag L2 && | |
113 | ||
114 | git checkout R1^0 && | |
115 | test_tick && git merge -s ours L1 && | |
116 | git tag R2 | |
117 | ) | |
583942df EN |
118 | ' |
119 | ||
2a669c34 | 120 | test_expect_success 'merge criss-cross + rename merges with basic modification' ' |
2a4c19ef EN |
121 | ( |
122 | cd rename-modify && | |
123 | ||
124 | git checkout L2^0 && | |
583942df | 125 | |
2a4c19ef | 126 | test_must_fail git merge -s recursive R2^0 && |
583942df | 127 | |
0cdabc10 | 128 | git ls-files -s >out && |
80205040 | 129 | test_line_count = 5 out && |
0cdabc10 | 130 | git ls-files -u >out && |
80205040 | 131 | test_line_count = 3 out && |
0cdabc10 | 132 | git ls-files -o >out && |
bbafc9c4 | 133 | test_line_count = 1 out && |
583942df | 134 | |
6ac767e5 | 135 | git rev-parse >expect \ |
6ac767e5 EN |
136 | L2:three R2:three && |
137 | git rev-parse >actual \ | |
138 | :2:three :3:three && | |
6ac767e5 | 139 | test_cmp expect actual |
2a4c19ef | 140 | ) |
583942df EN |
141 | ' |
142 | ||
f63622c0 EN |
143 | # |
144 | # For the next test, we start with three commits in two lines of development | |
145 | # which setup a rename/add conflict: | |
146 | # Commit A: File 'a' exists | |
147 | # Commit B: Rename 'a' -> 'new_a' | |
148 | # Commit C: Modify 'a', create different 'new_a' | |
149 | # Later, two different people merge and resolve differently: | |
150 | # Commit D: Merge B & C, ignoring separately created 'new_a' | |
151 | # Commit E: Merge B & C making use of some piece of secondary 'new_a' | |
152 | # Finally, someone goes to merge D & E. Does git detect the conflict? | |
153 | # | |
154 | # B D | |
155 | # o---o | |
156 | # / \ / \ | |
157 | # A o X ? F | |
158 | # \ / \ / | |
159 | # o---o | |
160 | # C E | |
161 | # | |
162 | ||
163 | test_expect_success 'setup differently handled merges of rename/add conflict' ' | |
6693fb3f | 164 | git init rename-add && |
2a4c19ef EN |
165 | ( |
166 | cd rename-add && | |
167 | ||
168 | printf "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n" >a && | |
169 | git add a && | |
170 | test_tick && git commit -m A && | |
171 | ||
172 | git branch B && | |
173 | git checkout -b C && | |
174 | echo 10 >>a && | |
7f867165 | 175 | test_write_lines 0 1 2 3 4 5 6 7 foobar >new_a && |
2a4c19ef EN |
176 | git add a new_a && |
177 | test_tick && git commit -m C && | |
178 | ||
179 | git checkout B && | |
180 | git mv a new_a && | |
181 | test_tick && git commit -m B && | |
182 | ||
183 | git checkout B^0 && | |
184 | test_must_fail git merge C && | |
7f867165 EN |
185 | git show :2:new_a >new_a && |
186 | git add new_a && | |
2a4c19ef EN |
187 | test_tick && git commit -m D && |
188 | git tag D && | |
189 | ||
190 | git checkout C^0 && | |
191 | test_must_fail git merge B && | |
7f867165 | 192 | test_write_lines 0 1 2 3 4 5 6 7 bad_merge >new_a && |
2a4c19ef EN |
193 | git add -u && |
194 | test_tick && git commit -m E && | |
195 | git tag E | |
196 | ) | |
f63622c0 EN |
197 | ' |
198 | ||
2a669c34 | 199 | test_expect_success 'git detects differently handled merges conflict' ' |
2a4c19ef EN |
200 | ( |
201 | cd rename-add && | |
202 | ||
203 | git checkout D^0 && | |
204 | ||
205 | test_must_fail git merge -s recursive E^0 && | |
206 | ||
0cdabc10 EN |
207 | git ls-files -s >out && |
208 | test_line_count = 3 out && | |
209 | git ls-files -u >out && | |
210 | test_line_count = 3 out && | |
211 | git ls-files -o >out && | |
212 | test_line_count = 1 out && | |
2a4c19ef | 213 | |
80205040 EN |
214 | git cat-file -p C:new_a >ours && |
215 | git cat-file -p C:a >theirs && | |
216 | >empty && | |
217 | test_must_fail git merge-file \ | |
218 | -L "Temporary merge branch 1" \ | |
219 | -L "" \ | |
220 | -L "Temporary merge branch 2" \ | |
221 | ours empty theirs && | |
222 | sed -e "s/^\([<=>]\)/\1\1\1/" ours >ours-tweaked && | |
223 | git hash-object ours-tweaked >expect && | |
224 | git rev-parse >>expect \ | |
225 | D:new_a E:new_a && | |
6ac767e5 | 226 | git rev-parse >actual \ |
7f867165 | 227 | :1:new_a :2:new_a :3:new_a && |
c8ce3763 | 228 | test_cmp expect actual && |
2a4c19ef | 229 | |
7f867165 EN |
230 | # Test that the two-way merge in new_a is as expected |
231 | git cat-file -p D:new_a >ours && | |
232 | git cat-file -p E:new_a >theirs && | |
2a4c19ef EN |
233 | >empty && |
234 | test_must_fail git merge-file \ | |
7f867165 | 235 | -L "HEAD" \ |
4f445453 | 236 | -L "" \ |
7f867165 | 237 | -L "E^0" \ |
6ac767e5 EN |
238 | ours empty theirs && |
239 | sed -e "s/^\([<=>]\)/\1\1\1/" ours >expect && | |
7f867165 EN |
240 | git hash-object new_a >actual && |
241 | git hash-object ours >expect && | |
6ac767e5 | 242 | test_cmp expect actual |
2a4c19ef | 243 | ) |
c94736a2 JH |
244 | ' |
245 | ||
b8cd1bb7 EN |
246 | # Repeat the above testcase with precisely the same setup, other than with |
247 | # the two merge bases having different orderings of commit timestamps so | |
248 | # that they are reversed in the order they are provided to merge-recursive, | |
249 | # so that we can improve code coverage. | |
250 | test_expect_success 'git detects differently handled merges conflict, swapped' ' | |
251 | ( | |
252 | cd rename-add && | |
253 | ||
254 | # Difference #1: Do cleanup from previous testrun | |
255 | git reset --hard && | |
256 | git clean -fdqx && | |
257 | ||
258 | # Difference #2: Change commit timestamps | |
259 | btime=$(git log --no-walk --date=raw --format=%cd B | awk "{print \$1}") && | |
260 | ctime=$(git log --no-walk --date=raw --format=%cd C | awk "{print \$1}") && | |
261 | newctime=$(($btime+1)) && | |
262 | git fast-export --no-data --all | sed -e s/$ctime/$newctime/ | git fast-import --force --quiet && | |
80205040 EN |
263 | # End of most differences; rest is copy-paste of last test, |
264 | # other than swapping C:a and C:new_a due to order switch | |
b8cd1bb7 EN |
265 | |
266 | git checkout D^0 && | |
267 | test_must_fail git merge -s recursive E^0 && | |
268 | ||
269 | git ls-files -s >out && | |
270 | test_line_count = 3 out && | |
271 | git ls-files -u >out && | |
272 | test_line_count = 3 out && | |
273 | git ls-files -o >out && | |
274 | test_line_count = 1 out && | |
275 | ||
80205040 EN |
276 | git cat-file -p C:a >ours && |
277 | git cat-file -p C:new_a >theirs && | |
278 | >empty && | |
279 | test_must_fail git merge-file \ | |
280 | -L "Temporary merge branch 1" \ | |
281 | -L "" \ | |
282 | -L "Temporary merge branch 2" \ | |
283 | ours empty theirs && | |
284 | sed -e "s/^\([<=>]\)/\1\1\1/" ours >ours-tweaked && | |
285 | git hash-object ours-tweaked >expect && | |
286 | git rev-parse >>expect \ | |
287 | D:new_a E:new_a && | |
b8cd1bb7 EN |
288 | git rev-parse >actual \ |
289 | :1:new_a :2:new_a :3:new_a && | |
290 | test_cmp expect actual && | |
291 | ||
292 | # Test that the two-way merge in new_a is as expected | |
293 | git cat-file -p D:new_a >ours && | |
294 | git cat-file -p E:new_a >theirs && | |
295 | >empty && | |
296 | test_must_fail git merge-file \ | |
297 | -L "HEAD" \ | |
298 | -L "" \ | |
299 | -L "E^0" \ | |
300 | ours empty theirs && | |
301 | sed -e "s/^\([<=>]\)/\1\1\1/" ours >expect && | |
302 | git hash-object new_a >actual && | |
303 | git hash-object ours >expect && | |
304 | test_cmp expect actual | |
305 | ) | |
306 | ' | |
307 | ||
fe7e9c23 EN |
308 | # |
309 | # criss-cross + modify/delete: | |
310 | # | |
311 | # B D | |
312 | # o---o | |
313 | # / \ / \ | |
314 | # A o X ? F | |
315 | # \ / \ / | |
316 | # o---o | |
317 | # C E | |
318 | # | |
319 | # Commit A: file with contents 'A\n' | |
320 | # Commit B: file with contents 'B\n' | |
321 | # Commit C: file not present | |
322 | # Commit D: file with contents 'B\n' | |
323 | # Commit E: file not present | |
324 | # | |
325 | # Merging commits D & E should result in modify/delete conflict. | |
326 | ||
327 | test_expect_success 'setup criss-cross + modify/delete resolved differently' ' | |
6693fb3f | 328 | git init modify-delete && |
2a4c19ef EN |
329 | ( |
330 | cd modify-delete && | |
331 | ||
332 | echo A >file && | |
333 | git add file && | |
334 | test_tick && | |
335 | git commit -m A && | |
336 | ||
337 | git branch B && | |
338 | git checkout -b C && | |
339 | git rm file && | |
340 | test_tick && | |
341 | git commit -m C && | |
342 | ||
343 | git checkout B && | |
344 | echo B >file && | |
345 | git add file && | |
346 | test_tick && | |
347 | git commit -m B && | |
348 | ||
349 | git checkout B^0 && | |
350 | test_must_fail git merge C && | |
351 | echo B >file && | |
352 | git add file && | |
353 | test_tick && | |
354 | git commit -m D && | |
355 | git tag D && | |
356 | ||
357 | git checkout C^0 && | |
358 | test_must_fail git merge B && | |
359 | git rm file && | |
360 | test_tick && | |
361 | git commit -m E && | |
362 | git tag E | |
363 | ) | |
fe7e9c23 EN |
364 | ' |
365 | ||
ec61d149 | 366 | test_expect_success 'git detects conflict merging criss-cross+modify/delete' ' |
2a4c19ef EN |
367 | ( |
368 | cd modify-delete && | |
369 | ||
370 | git checkout D^0 && | |
fe7e9c23 | 371 | |
2a4c19ef | 372 | test_must_fail git merge -s recursive E^0 && |
fe7e9c23 | 373 | |
0cdabc10 EN |
374 | git ls-files -s >out && |
375 | test_line_count = 2 out && | |
376 | git ls-files -u >out && | |
377 | test_line_count = 2 out && | |
fe7e9c23 | 378 | |
6ac767e5 | 379 | git rev-parse >expect \ |
5902f5f4 | 380 | main:file B:file && |
6ac767e5 EN |
381 | git rev-parse >actual \ |
382 | :1:file :2:file && | |
383 | test_cmp expect actual | |
2a4c19ef | 384 | ) |
fe7e9c23 EN |
385 | ' |
386 | ||
ec61d149 | 387 | test_expect_success 'git detects conflict merging criss-cross+modify/delete, reverse direction' ' |
2a4c19ef EN |
388 | ( |
389 | cd modify-delete && | |
390 | ||
391 | git reset --hard && | |
392 | git checkout E^0 && | |
fe7e9c23 | 393 | |
2a4c19ef | 394 | test_must_fail git merge -s recursive D^0 && |
fe7e9c23 | 395 | |
0cdabc10 EN |
396 | git ls-files -s >out && |
397 | test_line_count = 2 out && | |
398 | git ls-files -u >out && | |
399 | test_line_count = 2 out && | |
fe7e9c23 | 400 | |
6ac767e5 | 401 | git rev-parse >expect \ |
5902f5f4 | 402 | main:file B:file && |
6ac767e5 EN |
403 | git rev-parse >actual \ |
404 | :1:file :3:file && | |
405 | test_cmp expect actual | |
2a4c19ef | 406 | ) |
fe7e9c23 EN |
407 | ' |
408 | ||
327ac9cb | 409 | # SORRY FOR THE SUPER LONG DESCRIPTION, BUT THIS NEXT ONE IS HAIRY |
827f2b7d EN |
410 | # |
411 | # criss-cross + d/f conflict via add/add: | |
235e8d59 | 412 | # Commit A: Neither file 'a' nor directory 'a/' exists. |
827f2b7d EN |
413 | # Commit B: Introduce 'a' |
414 | # Commit C: Introduce 'a/file' | |
327ac9cb | 415 | # Commit D1: Merge B & C, keeping 'a' and deleting 'a/' |
827f2b7d | 416 | # Commit E1: Merge B & C, deleting 'a' but keeping 'a/file' |
827f2b7d | 417 | # |
327ac9cb | 418 | # B D1 or D2 |
827f2b7d EN |
419 | # o---o |
420 | # / \ / \ | |
421 | # A o X ? F | |
422 | # \ / \ / | |
423 | # o---o | |
327ac9cb EN |
424 | # C E1 or E2 or E3 |
425 | # | |
426 | # I'll describe D2, E2, & E3 (which are alternatives for D1 & E1) more below... | |
427 | # | |
428 | # Merging D1 & E1 requires we first create a virtual merge base X from | |
429 | # merging A & B in memory. There are several possibilities for the merge-base: | |
430 | # 1: Keep both 'a' and 'a/file' (assuming crazy filesystem allowing a tree | |
431 | # with a directory and file at same path): results in merge of D1 & E1 | |
432 | # being clean with both files deleted. Bad (no conflict detected). | |
433 | # 2: Keep 'a' but not 'a/file': Merging D1 & E1 is clean and matches E1. Bad. | |
434 | # 3: Keep 'a/file' but not 'a': Merging D1 & E1 is clean and matches D1. Bad. | |
435 | # 4: Keep neither file: Merging D1 & E1 reports the D/F add/add conflict. | |
436 | # | |
437 | # So 4 sounds good for this case, but if we were to merge D1 & E3, where E3 | |
438 | # is defined as: | |
439 | # Commit E3: Merge B & C, keeping modified a, and deleting a/ | |
440 | # then we'd get an add/add conflict for 'a', which seems suboptimal. A little | |
441 | # creativity leads us to an alternate choice: | |
442 | # 5: Keep 'a' as 'a~$UNIQUE' and a/file; results: | |
443 | # Merge D1 & E1: rename/delete conflict for 'a'; a/file silently deleted | |
444 | # Merge D1 & E3 is clean, as expected. | |
445 | # | |
446 | # So choice 5 at least provides some kind of conflict for the original case, | |
447 | # and can merge cleanly as expected with D1 and E3. It also made things just | |
6c74948f | 448 | # slightly funny for merging D1 and E4, where E4 is defined as: |
327ac9cb EN |
449 | # Commit E4: Merge B & C, modifying 'a' and renaming to 'a2', and deleting 'a/' |
450 | # in this case, we'll get a rename/rename(1to2) conflict because a~$UNIQUE | |
451 | # gets renamed to 'a' in D1 and to 'a2' in E4. But that's better than having | |
452 | # two files (both 'a' and 'a2') sitting around without the user being notified | |
453 | # that we could detect they were related and need to be merged. Also, choice | |
454 | # 5 makes the handling of 'a/file' seem suboptimal. What if we were to merge | |
455 | # D2 and E4, where D2 is: | |
456 | # Commit D2: Merge B & C, renaming 'a'->'a2', keeping 'a/file' | |
457 | # This would result in a clean merge with 'a2' having three-way merged | |
458 | # contents (good), and deleting 'a/' (bad) -- it doesn't detect the | |
459 | # conflict in how the different sides treated a/file differently. | |
460 | # Continuing down the creative route: | |
461 | # 6: Keep 'a' as 'a~$UNIQUE1' and keep 'a/' as 'a~$UNIQUE2/'; results: | |
462 | # Merge D1 & E1: rename/delete conflict for 'a' and each path under 'a/'. | |
463 | # Merge D1 & E3: clean, as expected. | |
464 | # Merge D1 & E4: rename/rename(1to2) conflict on 'a' vs 'a2'. | |
465 | # Merge D2 & E4: clean for 'a2', rename/delete for a/file | |
827f2b7d | 466 | # |
327ac9cb EN |
467 | # Choice 6 could cause rename detection to take longer (providing more targets |
468 | # that need to be searched). Also, the conflict message for each path under | |
469 | # 'a/' might be annoying unless we can detect it at the directory level, print | |
470 | # it once, and then suppress it for individual filepaths underneath. | |
827f2b7d | 471 | # |
827f2b7d | 472 | # |
327ac9cb EN |
473 | # As of time of writing, git uses choice 5. Directory rename detection and |
474 | # rename detection performance improvements might make choice 6 a desirable | |
475 | # improvement. But we can at least document where we fall short for now... | |
476 | # | |
477 | # | |
478 | # Historically, this testcase also used: | |
479 | # Commit E2: Merge B & C, deleting 'a' but keeping slightly modified 'a/file' | |
480 | # The merge of D1 & E2 is very similar to D1 & E1 -- it has similar issues for | |
481 | # path 'a', but should always result in a modify/delete conflict for path | |
482 | # 'a/file'. These tests ran the two merges | |
483 | # D1 & E1 | |
484 | # D1 & E2 | |
485 | # in both directions, to check for directional issues with D/F conflict | |
486 | # handling. Later we added | |
487 | # D1 & E3 | |
488 | # D1 & E4 | |
489 | # D2 & E4 | |
490 | # for good measure, though we only ran those one way because we had pretty | |
491 | # good confidence in merge-recursive's directional handling of D/F issues. | |
492 | # | |
493 | # Just to summarize all the intermediate merge commits: | |
494 | # Commit D1: Merge B & C, keeping a and deleting a/ | |
495 | # Commit D2: Merge B & C, renaming a->a2, keeping a/file | |
496 | # Commit E1: Merge B & C, deleting a but keeping a/file | |
497 | # Commit E2: Merge B & C, deleting a but keeping slightly modified a/file | |
498 | # Commit E3: Merge B & C, keeping modified a, and deleting a/ | |
499 | # Commit E4: Merge B & C, modifying 'a' and renaming to 'a2', and deleting 'a/' | |
827f2b7d EN |
500 | # |
501 | ||
502 | test_expect_success 'setup differently handled merges of directory/file conflict' ' | |
6693fb3f | 503 | git init directory-file && |
2a4c19ef EN |
504 | ( |
505 | cd directory-file && | |
506 | ||
507 | >ignore-me && | |
508 | git add ignore-me && | |
509 | test_tick && | |
510 | git commit -m A && | |
511 | git tag A && | |
512 | ||
513 | git branch B && | |
514 | git checkout -b C && | |
515 | mkdir a && | |
327ac9cb | 516 | test_write_lines a b c d e f g >a/file && |
2a4c19ef EN |
517 | git add a/file && |
518 | test_tick && | |
519 | git commit -m C && | |
520 | ||
521 | git checkout B && | |
327ac9cb | 522 | test_write_lines 1 2 3 4 5 6 7 >a && |
2a4c19ef EN |
523 | git add a && |
524 | test_tick && | |
525 | git commit -m B && | |
526 | ||
527 | git checkout B^0 && | |
327ac9cb EN |
528 | git merge -s ours -m D1 C^0 && |
529 | git tag D1 && | |
530 | ||
531 | git checkout B^0 && | |
532 | test_must_fail git merge C^0 && | |
ef527787 EN |
533 | if test "$GIT_TEST_MERGE_ALGORITHM" = ort |
534 | then | |
535 | git rm -rf a/ && | |
536 | git rm a~HEAD | |
537 | else | |
538 | git clean -fd && | |
539 | git rm -rf a/ && | |
540 | git rm a | |
541 | fi && | |
327ac9cb EN |
542 | git cat-file -p B:a >a2 && |
543 | git add a2 && | |
544 | git commit -m D2 && | |
545 | git tag D2 && | |
2a4c19ef EN |
546 | |
547 | git checkout C^0 && | |
327ac9cb | 548 | git merge -s ours -m E1 B^0 && |
2a4c19ef EN |
549 | git tag E1 && |
550 | ||
551 | git checkout C^0 && | |
327ac9cb EN |
552 | git merge -s ours -m E2 B^0 && |
553 | test_write_lines a b c d e f g h >a/file && | |
2a4c19ef | 554 | git add a/file && |
327ac9cb EN |
555 | git commit --amend -C HEAD && |
556 | git tag E2 && | |
557 | ||
558 | git checkout C^0 && | |
559 | test_must_fail git merge B^0 && | |
ef527787 EN |
560 | if test "$GIT_TEST_MERGE_ALGORITHM" = ort |
561 | then | |
562 | git rm a~B^0 | |
563 | else | |
564 | git clean -fd | |
565 | fi && | |
327ac9cb EN |
566 | git rm -rf a/ && |
567 | test_write_lines 1 2 3 4 5 6 7 8 >a && | |
568 | git add a && | |
569 | git commit -m E3 && | |
6b82db9b | 570 | git tag E3 && |
327ac9cb EN |
571 | |
572 | git checkout C^0 && | |
573 | test_must_fail git merge B^0 && | |
ef527787 EN |
574 | if test "$GIT_TEST_MERGE_ALGORITHM" = ort |
575 | then | |
576 | git rm -rf a/ && | |
577 | git rm a~B^0 | |
578 | else | |
579 | git clean -fd && | |
580 | git rm -rf a/ && | |
581 | git rm a | |
582 | fi && | |
327ac9cb EN |
583 | test_write_lines 1 2 3 4 5 6 7 8 >a2 && |
584 | git add a2 && | |
585 | git commit -m E4 && | |
586 | git tag E4 | |
2a4c19ef | 587 | ) |
827f2b7d EN |
588 | ' |
589 | ||
327ac9cb | 590 | test_expect_success 'merge of D1 & E1 fails but has appropriate contents' ' |
d43eba0a EN |
591 | test_when_finished "git -C directory-file reset --hard" && |
592 | test_when_finished "git -C directory-file clean -fdqx" && | |
2a4c19ef EN |
593 | ( |
594 | cd directory-file && | |
827f2b7d | 595 | |
327ac9cb | 596 | git checkout D1^0 && |
827f2b7d | 597 | |
2a4c19ef | 598 | test_must_fail git merge -s recursive E1^0 && |
827f2b7d | 599 | |
ef527787 EN |
600 | if test "$GIT_TEST_MERGE_ALGORITHM" = ort |
601 | then | |
602 | git ls-files -s >out && | |
603 | test_line_count = 3 out && | |
604 | git ls-files -u >out && | |
605 | test_line_count = 2 out && | |
606 | git ls-files -o >out && | |
607 | test_line_count = 1 out && | |
608 | ||
609 | git rev-parse >expect \ | |
610 | A:ignore-me B:a D1:a && | |
611 | git rev-parse >actual \ | |
612 | :0:ignore-me :1:a :2:a && | |
613 | test_cmp expect actual | |
614 | else | |
615 | git ls-files -s >out && | |
616 | test_line_count = 2 out && | |
617 | git ls-files -u >out && | |
618 | test_line_count = 1 out && | |
619 | git ls-files -o >out && | |
620 | test_line_count = 1 out && | |
621 | ||
622 | git rev-parse >expect \ | |
623 | A:ignore-me B:a && | |
624 | git rev-parse >actual \ | |
625 | :0:ignore-me :2:a && | |
626 | test_cmp expect actual | |
627 | fi | |
2a4c19ef | 628 | ) |
827f2b7d EN |
629 | ' |
630 | ||
327ac9cb | 631 | test_expect_success 'merge of E1 & D1 fails but has appropriate contents' ' |
d43eba0a EN |
632 | test_when_finished "git -C directory-file reset --hard" && |
633 | test_when_finished "git -C directory-file clean -fdqx" && | |
2a4c19ef EN |
634 | ( |
635 | cd directory-file && | |
636 | ||
d43eba0a | 637 | git checkout E1^0 && |
827f2b7d | 638 | |
327ac9cb | 639 | test_must_fail git merge -s recursive D1^0 && |
827f2b7d | 640 | |
ef527787 EN |
641 | if test "$GIT_TEST_MERGE_ALGORITHM" = ort |
642 | then | |
643 | git ls-files -s >out && | |
644 | test_line_count = 3 out && | |
645 | git ls-files -u >out && | |
646 | test_line_count = 2 out && | |
647 | git ls-files -o >out && | |
648 | test_line_count = 1 out && | |
649 | ||
650 | git rev-parse >expect \ | |
651 | A:ignore-me B:a D1:a && | |
652 | git rev-parse >actual \ | |
653 | :0:ignore-me :1:a :3:a && | |
654 | test_cmp expect actual | |
655 | else | |
656 | git ls-files -s >out && | |
657 | test_line_count = 2 out && | |
658 | git ls-files -u >out && | |
659 | test_line_count = 1 out && | |
660 | git ls-files -o >out && | |
661 | test_line_count = 1 out && | |
662 | ||
663 | git rev-parse >expect \ | |
664 | A:ignore-me B:a && | |
665 | git rev-parse >actual \ | |
666 | :0:ignore-me :3:a && | |
667 | test_cmp expect actual | |
668 | fi | |
2a4c19ef | 669 | ) |
827f2b7d EN |
670 | ' |
671 | ||
327ac9cb | 672 | test_expect_success 'merge of D1 & E2 fails but has appropriate contents' ' |
d43eba0a EN |
673 | test_when_finished "git -C directory-file reset --hard" && |
674 | test_when_finished "git -C directory-file clean -fdqx" && | |
2a4c19ef EN |
675 | ( |
676 | cd directory-file && | |
677 | ||
327ac9cb | 678 | git checkout D1^0 && |
827f2b7d | 679 | |
2a4c19ef | 680 | test_must_fail git merge -s recursive E2^0 && |
827f2b7d | 681 | |
ef527787 EN |
682 | if test "$GIT_TEST_MERGE_ALGORITHM" = ort |
683 | then | |
684 | git ls-files -s >out && | |
685 | test_line_count = 5 out && | |
686 | git ls-files -u >out && | |
687 | test_line_count = 4 out && | |
688 | git ls-files -o >out && | |
689 | test_line_count = 1 out && | |
690 | ||
691 | git rev-parse >expect \ | |
692 | B:a D1:a E2:a/file C:a/file A:ignore-me && | |
693 | git rev-parse >actual \ | |
694 | :1:a~HEAD :2:a~HEAD :3:a/file :1:a/file :0:ignore-me | |
695 | else | |
696 | git ls-files -s >out && | |
697 | test_line_count = 4 out && | |
698 | git ls-files -u >out && | |
699 | test_line_count = 3 out && | |
700 | git ls-files -o >out && | |
701 | test_line_count = 2 out && | |
702 | ||
703 | git rev-parse >expect \ | |
704 | B:a E2:a/file C:a/file A:ignore-me && | |
705 | git rev-parse >actual \ | |
706 | :2:a :3:a/file :1:a/file :0:ignore-me | |
707 | fi && | |
f1e12398 | 708 | test_cmp expect actual && |
827f2b7d | 709 | |
5b0b9712 | 710 | test_path_is_file a~HEAD |
2a4c19ef | 711 | ) |
827f2b7d EN |
712 | ' |
713 | ||
327ac9cb | 714 | test_expect_success 'merge of E2 & D1 fails but has appropriate contents' ' |
d43eba0a EN |
715 | test_when_finished "git -C directory-file reset --hard" && |
716 | test_when_finished "git -C directory-file clean -fdqx" && | |
2a4c19ef EN |
717 | ( |
718 | cd directory-file && | |
827f2b7d | 719 | |
d43eba0a | 720 | git checkout E2^0 && |
827f2b7d | 721 | |
327ac9cb | 722 | test_must_fail git merge -s recursive D1^0 && |
827f2b7d | 723 | |
ef527787 EN |
724 | if test "$GIT_TEST_MERGE_ALGORITHM" = ort |
725 | then | |
726 | git ls-files -s >out && | |
727 | test_line_count = 5 out && | |
728 | git ls-files -u >out && | |
729 | test_line_count = 4 out && | |
730 | git ls-files -o >out && | |
731 | test_line_count = 1 out && | |
732 | ||
733 | git rev-parse >expect \ | |
734 | B:a D1:a E2:a/file C:a/file A:ignore-me && | |
735 | git rev-parse >actual \ | |
736 | :1:a~D1^0 :3:a~D1^0 :2:a/file :1:a/file :0:ignore-me | |
737 | else | |
738 | git ls-files -s >out && | |
739 | test_line_count = 4 out && | |
740 | git ls-files -u >out && | |
741 | test_line_count = 3 out && | |
742 | git ls-files -o >out && | |
743 | test_line_count = 2 out && | |
744 | ||
745 | git rev-parse >expect \ | |
746 | B:a E2:a/file C:a/file A:ignore-me && | |
747 | git rev-parse >actual \ | |
748 | :3:a :2:a/file :1:a/file :0:ignore-me | |
749 | fi && | |
f1e12398 | 750 | test_cmp expect actual && |
2a4c19ef | 751 | |
327ac9cb EN |
752 | test_path_is_file a~D1^0 |
753 | ) | |
754 | ' | |
755 | ||
756 | test_expect_success 'merge of D1 & E3 succeeds' ' | |
757 | test_when_finished "git -C directory-file reset --hard" && | |
758 | test_when_finished "git -C directory-file clean -fdqx" && | |
759 | ( | |
760 | cd directory-file && | |
761 | ||
762 | git checkout D1^0 && | |
763 | ||
764 | git merge -s recursive E3^0 && | |
765 | ||
766 | git ls-files -s >out && | |
767 | test_line_count = 2 out && | |
768 | git ls-files -u >out && | |
769 | test_line_count = 0 out && | |
770 | git ls-files -o >out && | |
771 | test_line_count = 1 out && | |
772 | ||
773 | git rev-parse >expect \ | |
774 | A:ignore-me E3:a && | |
775 | git rev-parse >actual \ | |
776 | :0:ignore-me :0:a && | |
777 | test_cmp expect actual | |
778 | ) | |
779 | ' | |
780 | ||
489c85ff | 781 | test_expect_merge_algorithm failure success 'merge of D1 & E4 puts merge of a and a2 in both a and a2' ' |
327ac9cb EN |
782 | test_when_finished "git -C directory-file reset --hard" && |
783 | test_when_finished "git -C directory-file clean -fdqx" && | |
784 | ( | |
785 | cd directory-file && | |
786 | ||
787 | git checkout D1^0 && | |
788 | ||
789 | test_must_fail git merge -s recursive E4^0 && | |
790 | ||
791 | git ls-files -s >out && | |
792 | test_line_count = 4 out && | |
793 | git ls-files -u >out && | |
794 | test_line_count = 3 out && | |
795 | git ls-files -o >out && | |
796 | test_line_count = 1 out && | |
797 | ||
798 | git rev-parse >expect \ | |
489c85ff | 799 | A:ignore-me B:a E4:a2 E4:a2 && |
327ac9cb EN |
800 | git rev-parse >actual \ |
801 | :0:ignore-me :1:a~Temporary\ merge\ branch\ 2 :2:a :3:a2 && | |
802 | test_cmp expect actual | |
803 | ) | |
804 | ' | |
805 | ||
806 | test_expect_failure 'merge of D2 & E4 merges a2s & reports conflict for a/file' ' | |
807 | test_when_finished "git -C directory-file reset --hard" && | |
808 | test_when_finished "git -C directory-file clean -fdqx" && | |
809 | ( | |
810 | cd directory-file && | |
811 | ||
812 | git checkout D2^0 && | |
813 | ||
814 | test_must_fail git merge -s recursive E4^0 && | |
815 | ||
816 | git ls-files -s >out && | |
817 | test_line_count = 3 out && | |
818 | git ls-files -u >out && | |
819 | test_line_count = 1 out && | |
820 | git ls-files -o >out && | |
821 | test_line_count = 1 out && | |
822 | ||
823 | git rev-parse >expect \ | |
824 | A:ignore-me E4:a2 D2:a/file && | |
825 | git rev-parse >actual \ | |
826 | :0:ignore-me :0:a2 :2:a/file && | |
827 | test_cmp expect actual | |
2a4c19ef | 828 | ) |
827f2b7d EN |
829 | ' |
830 | ||
a0d33116 EN |
831 | # |
832 | # criss-cross with rename/rename(1to2)/modify followed by | |
833 | # rename/rename(2to1)/modify: | |
834 | # | |
835 | # B D | |
836 | # o---o | |
837 | # / \ / \ | |
838 | # A o X ? F | |
839 | # \ / \ / | |
840 | # o---o | |
841 | # C E | |
842 | # | |
843 | # Commit A: new file: a | |
844 | # Commit B: rename a->b, modifying by adding a line | |
845 | # Commit C: rename a->c | |
846 | # Commit D: merge B&C, resolving conflict by keeping contents in newname | |
847 | # Commit E: merge B&C, resolving conflict similar to D but adding another line | |
848 | # | |
849 | # There is a conflict merging B & C, but one of filename not of file | |
850 | # content. Whoever created D and E chose specific resolutions for that | |
851 | # conflict resolution. Now, since: (1) there is no content conflict | |
852 | # merging B & C, (2) D does not modify that merged content further, and (3) | |
853 | # both D & E resolve the name conflict in the same way, the modification to | |
854 | # newname in E should not cause any conflicts when it is merged with D. | |
855 | # (Note that this can be accomplished by having the virtual merge base have | |
856 | # the merged contents of b and c stored in a file named a, which seems like | |
857 | # the most logical choice anyway.) | |
858 | # | |
859 | # Comment from Junio: I do not necessarily agree with the choice "a", but | |
860 | # it feels sound to say "B and C do not agree what the final pathname | |
861 | # should be, but we know this content was derived from the common A:a so we | |
862 | # use one path whose name is arbitrary in the virtual merge base X between | |
863 | # D and E" and then further let the rename detection to notice that that | |
864 | # arbitrary path gets renamed between X-D to "newname" and X-E also to | |
865 | # "newname" to resolve it as both sides renaming it to the same new | |
866 | # name. It is akin to what we do at the content level, i.e. "B and C do not | |
867 | # agree what the final contents should be, so we leave the conflict marker | |
868 | # but that may cancel out at the final merge stage". | |
869 | ||
870 | test_expect_success 'setup rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' ' | |
6693fb3f | 871 | git init rename-squared-squared && |
2a4c19ef EN |
872 | ( |
873 | cd rename-squared-squared && | |
874 | ||
875 | printf "1\n2\n3\n4\n5\n6\n" >a && | |
876 | git add a && | |
877 | git commit -m A && | |
878 | git tag A && | |
879 | ||
880 | git checkout -b B A && | |
881 | git mv a b && | |
882 | echo 7 >>b && | |
883 | git add -u && | |
884 | git commit -m B && | |
885 | ||
886 | git checkout -b C A && | |
887 | git mv a c && | |
888 | git commit -m C && | |
889 | ||
890 | git checkout -q B^0 && | |
891 | git merge --no-commit -s ours C^0 && | |
892 | git mv b newname && | |
893 | git commit -m "Merge commit C^0 into HEAD" && | |
894 | git tag D && | |
895 | ||
896 | git checkout -q C^0 && | |
897 | git merge --no-commit -s ours B^0 && | |
898 | git mv c newname && | |
899 | printf "7\n8\n" >>newname && | |
900 | git add -u && | |
901 | git commit -m "Merge commit B^0 into HEAD" && | |
902 | git tag E | |
903 | ) | |
a0d33116 EN |
904 | ' |
905 | ||
c52ff85d | 906 | test_expect_success 'handle rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' ' |
2a4c19ef EN |
907 | ( |
908 | cd rename-squared-squared && | |
a0d33116 | 909 | |
2a4c19ef | 910 | git checkout D^0 && |
a0d33116 | 911 | |
2a4c19ef | 912 | git merge -s recursive E^0 && |
a0d33116 | 913 | |
0cdabc10 EN |
914 | git ls-files -s >out && |
915 | test_line_count = 1 out && | |
916 | git ls-files -u >out && | |
917 | test_line_count = 0 out && | |
918 | git ls-files -o >out && | |
919 | test_line_count = 1 out && | |
2a4c19ef EN |
920 | |
921 | test $(git rev-parse HEAD:newname) = $(git rev-parse E:newname) | |
922 | ) | |
a0d33116 EN |
923 | ' |
924 | ||
0b35deb3 EN |
925 | # |
926 | # criss-cross with rename/rename(1to2)/add-source + resolvable modify/modify: | |
927 | # | |
928 | # B D | |
929 | # o---o | |
930 | # / \ / \ | |
931 | # A o X ? F | |
932 | # \ / \ / | |
933 | # o---o | |
934 | # C E | |
935 | # | |
936 | # Commit A: new file: a | |
937 | # Commit B: rename a->b | |
938 | # Commit C: rename a->c, add different a | |
939 | # Commit D: merge B&C, keeping b&c and (new) a modified at beginning | |
940 | # Commit E: merge B&C, keeping b&c and (new) a modified at end | |
941 | # | |
942 | # Merging commits D & E should result in no conflict; doing so correctly | |
943 | # requires getting the virtual merge base (from merging B&C) right, handling | |
944 | # renaming carefully (both in the virtual merge base and later), and getting | |
945 | # content merge handled. | |
946 | ||
2a4c19ef | 947 | test_expect_success 'setup criss-cross + rename/rename/add-source + modify/modify' ' |
6693fb3f | 948 | git init rename-rename-add-source && |
2a4c19ef EN |
949 | ( |
950 | cd rename-rename-add-source && | |
951 | ||
952 | printf "lots\nof\nwords\nand\ncontent\n" >a && | |
953 | git add a && | |
954 | git commit -m A && | |
955 | git tag A && | |
956 | ||
957 | git checkout -b B A && | |
958 | git mv a b && | |
959 | git commit -m B && | |
960 | ||
961 | git checkout -b C A && | |
962 | git mv a c && | |
963 | printf "2\n3\n4\n5\n6\n7\n" >a && | |
964 | git add a && | |
965 | git commit -m C && | |
966 | ||
967 | git checkout B^0 && | |
968 | git merge --no-commit -s ours C^0 && | |
969 | git checkout C -- a c && | |
970 | mv a old_a && | |
971 | echo 1 >a && | |
972 | cat old_a >>a && | |
973 | rm old_a && | |
974 | git add -u && | |
975 | git commit -m "Merge commit C^0 into HEAD" && | |
976 | git tag D && | |
977 | ||
978 | git checkout C^0 && | |
979 | git merge --no-commit -s ours B^0 && | |
980 | git checkout B -- b && | |
981 | echo 8 >>a && | |
982 | git add -u && | |
983 | git commit -m "Merge commit B^0 into HEAD" && | |
984 | git tag E | |
985 | ) | |
0b35deb3 EN |
986 | ' |
987 | ||
988 | test_expect_failure 'detect rename/rename/add-source for virtual merge-base' ' | |
2a4c19ef EN |
989 | ( |
990 | cd rename-rename-add-source && | |
991 | ||
992 | git checkout D^0 && | |
0b35deb3 | 993 | |
2a4c19ef | 994 | git merge -s recursive E^0 && |
0b35deb3 | 995 | |
0cdabc10 EN |
996 | git ls-files -s >out && |
997 | test_line_count = 3 out && | |
998 | git ls-files -u >out && | |
999 | test_line_count = 0 out && | |
1000 | git ls-files -o >out && | |
1001 | test_line_count = 1 out && | |
0b35deb3 | 1002 | |
6ac767e5 EN |
1003 | printf "1\n2\n3\n4\n5\n6\n7\n8\n" >correct && |
1004 | git rev-parse >expect \ | |
1005 | A:a A:a \ | |
1006 | correct && | |
1007 | git rev-parse >actual \ | |
1008 | :0:b :0:c && | |
1009 | git hash-object >>actual \ | |
1010 | a && | |
1011 | test_cmp expect actual | |
2a4c19ef | 1012 | ) |
0b35deb3 EN |
1013 | ' |
1014 | ||
b630b814 EN |
1015 | # |
1016 | # criss-cross with rename/rename(1to2)/add-dest + simple modify: | |
1017 | # | |
1018 | # B D | |
1019 | # o---o | |
1020 | # / \ / \ | |
1021 | # A o X ? F | |
1022 | # \ / \ / | |
1023 | # o---o | |
1024 | # C E | |
1025 | # | |
1026 | # Commit A: new file: a | |
1027 | # Commit B: rename a->b, add c | |
1028 | # Commit C: rename a->c | |
1029 | # Commit D: merge B&C, keeping A:a and B:c | |
1030 | # Commit E: merge B&C, keeping A:a and slightly modified c from B | |
1031 | # | |
1032 | # Merging commits D & E should result in no conflict. The virtual merge | |
1033 | # base of B & C needs to not delete B:c for that to work, though... | |
1034 | ||
1035 | test_expect_success 'setup criss-cross+rename/rename/add-dest + simple modify' ' | |
6693fb3f | 1036 | git init rename-rename-add-dest && |
2a4c19ef EN |
1037 | ( |
1038 | cd rename-rename-add-dest && | |
1039 | ||
1040 | >a && | |
1041 | git add a && | |
1042 | git commit -m A && | |
1043 | git tag A && | |
1044 | ||
1045 | git checkout -b B A && | |
1046 | git mv a b && | |
1047 | printf "1\n2\n3\n4\n5\n6\n7\n" >c && | |
1048 | git add c && | |
1049 | git commit -m B && | |
1050 | ||
1051 | git checkout -b C A && | |
1052 | git mv a c && | |
1053 | git commit -m C && | |
1054 | ||
1055 | git checkout B^0 && | |
1056 | git merge --no-commit -s ours C^0 && | |
1057 | git mv b a && | |
1058 | git commit -m "D is like B but renames b back to a" && | |
1059 | git tag D && | |
1060 | ||
1061 | git checkout B^0 && | |
1062 | git merge --no-commit -s ours C^0 && | |
1063 | git mv b a && | |
1064 | echo 8 >>c && | |
1065 | git add c && | |
1066 | git commit -m "E like D but has mod in c" && | |
1067 | git tag E | |
1068 | ) | |
b630b814 EN |
1069 | ' |
1070 | ||
6d63070c | 1071 | test_expect_success 'virtual merge base handles rename/rename(1to2)/add-dest' ' |
2a4c19ef EN |
1072 | ( |
1073 | cd rename-rename-add-dest && | |
1074 | ||
1075 | git checkout D^0 && | |
b630b814 | 1076 | |
2a4c19ef | 1077 | git merge -s recursive E^0 && |
b630b814 | 1078 | |
0cdabc10 EN |
1079 | git ls-files -s >out && |
1080 | test_line_count = 2 out && | |
1081 | git ls-files -u >out && | |
1082 | test_line_count = 0 out && | |
1083 | git ls-files -o >out && | |
1084 | test_line_count = 1 out && | |
b630b814 | 1085 | |
6ac767e5 EN |
1086 | git rev-parse >expect \ |
1087 | A:a E:c && | |
1088 | git rev-parse >actual \ | |
1089 | :0:a :0:c && | |
1090 | test_cmp expect actual | |
2a4c19ef | 1091 | ) |
b630b814 EN |
1092 | ' |
1093 | ||
c6d3dd5d EN |
1094 | # |
1095 | # criss-cross with modify/modify on a symlink: | |
1096 | # | |
1097 | # B D | |
1098 | # o---o | |
1099 | # / \ / \ | |
1100 | # A o X ? F | |
1101 | # \ / \ / | |
1102 | # o---o | |
1103 | # C E | |
1104 | # | |
1105 | # Commit A: simple simlink fickle->lagoon | |
1106 | # Commit B: redirect fickle->disneyland | |
1107 | # Commit C: redirect fickle->home | |
1108 | # Commit D: merge B&C, resolving in favor of B | |
1109 | # Commit E: merge B&C, resolving in favor of C | |
1110 | # | |
1111 | # This is an obvious modify/modify conflict for the symlink 'fickle'. Can | |
1112 | # git detect it? | |
1113 | ||
1114 | test_expect_success 'setup symlink modify/modify' ' | |
6693fb3f | 1115 | git init symlink-modify-modify && |
c6d3dd5d EN |
1116 | ( |
1117 | cd symlink-modify-modify && | |
1118 | ||
1119 | test_ln_s_add lagoon fickle && | |
1120 | git commit -m A && | |
1121 | git tag A && | |
1122 | ||
1123 | git checkout -b B A && | |
1124 | git rm fickle && | |
1125 | test_ln_s_add disneyland fickle && | |
1126 | git commit -m B && | |
1127 | ||
1128 | git checkout -b C A && | |
1129 | git rm fickle && | |
1130 | test_ln_s_add home fickle && | |
1131 | git add fickle && | |
1132 | git commit -m C && | |
1133 | ||
1134 | git checkout -q B^0 && | |
1135 | git merge -s ours -m D C^0 && | |
1136 | git tag D && | |
1137 | ||
1138 | git checkout -q C^0 && | |
1139 | git merge -s ours -m E B^0 && | |
1140 | git tag E | |
1141 | ) | |
1142 | ' | |
1143 | ||
f06481f1 | 1144 | test_expect_merge_algorithm failure success 'check symlink modify/modify' ' |
c6d3dd5d EN |
1145 | ( |
1146 | cd symlink-modify-modify && | |
1147 | ||
1148 | git checkout D^0 && | |
1149 | ||
1150 | test_must_fail git merge -s recursive E^0 && | |
1151 | ||
1152 | git ls-files -s >out && | |
1153 | test_line_count = 3 out && | |
1154 | git ls-files -u >out && | |
1155 | test_line_count = 3 out && | |
1156 | git ls-files -o >out && | |
1157 | test_line_count = 1 out | |
1158 | ) | |
1159 | ' | |
1160 | ||
81f5a2ce EN |
1161 | # |
1162 | # criss-cross with add/add of a symlink: | |
1163 | # | |
1164 | # B D | |
1165 | # o---o | |
1166 | # / \ / \ | |
1167 | # A o X ? F | |
1168 | # \ / \ / | |
1169 | # o---o | |
1170 | # C E | |
1171 | # | |
1172 | # Commit A: No symlink or path exists yet | |
1173 | # Commit B: set up symlink: fickle->disneyland | |
1174 | # Commit C: set up symlink: fickle->home | |
1175 | # Commit D: merge B&C, resolving in favor of B | |
1176 | # Commit E: merge B&C, resolving in favor of C | |
1177 | # | |
1178 | # This is an obvious add/add conflict for the symlink 'fickle'. Can | |
1179 | # git detect it? | |
1180 | ||
1181 | test_expect_success 'setup symlink add/add' ' | |
6693fb3f | 1182 | git init symlink-add-add && |
81f5a2ce EN |
1183 | ( |
1184 | cd symlink-add-add && | |
1185 | ||
1186 | touch ignoreme && | |
1187 | git add ignoreme && | |
1188 | git commit -m A && | |
1189 | git tag A && | |
1190 | ||
1191 | git checkout -b B A && | |
1192 | test_ln_s_add disneyland fickle && | |
1193 | git commit -m B && | |
1194 | ||
1195 | git checkout -b C A && | |
1196 | test_ln_s_add home fickle && | |
1197 | git add fickle && | |
1198 | git commit -m C && | |
1199 | ||
1200 | git checkout -q B^0 && | |
1201 | git merge -s ours -m D C^0 && | |
1202 | git tag D && | |
1203 | ||
1204 | git checkout -q C^0 && | |
1205 | git merge -s ours -m E B^0 && | |
1206 | git tag E | |
1207 | ) | |
1208 | ' | |
1209 | ||
f06481f1 | 1210 | test_expect_merge_algorithm failure success 'check symlink add/add' ' |
81f5a2ce EN |
1211 | ( |
1212 | cd symlink-add-add && | |
1213 | ||
1214 | git checkout D^0 && | |
1215 | ||
1216 | test_must_fail git merge -s recursive E^0 && | |
1217 | ||
1218 | git ls-files -s >out && | |
3df4e3bb | 1219 | test_line_count = 3 out && |
81f5a2ce EN |
1220 | git ls-files -u >out && |
1221 | test_line_count = 2 out && | |
1222 | git ls-files -o >out && | |
1223 | test_line_count = 1 out | |
1224 | ) | |
1225 | ' | |
1226 | ||
d4d17180 EN |
1227 | # |
1228 | # criss-cross with modify/modify on a submodule: | |
1229 | # | |
1230 | # B D | |
1231 | # o---o | |
1232 | # / \ / \ | |
1233 | # A o X ? F | |
1234 | # \ / \ / | |
1235 | # o---o | |
1236 | # C E | |
1237 | # | |
1238 | # Commit A: simple submodule repo | |
1239 | # Commit B: update repo | |
1240 | # Commit C: update repo differently | |
1241 | # Commit D: merge B&C, resolving in favor of B | |
1242 | # Commit E: merge B&C, resolving in favor of C | |
1243 | # | |
1244 | # This is an obvious modify/modify conflict for the submodule 'repo'. Can | |
1245 | # git detect it? | |
1246 | ||
1247 | test_expect_success 'setup submodule modify/modify' ' | |
6693fb3f | 1248 | git init submodule-modify-modify && |
d4d17180 EN |
1249 | ( |
1250 | cd submodule-modify-modify && | |
1251 | ||
6693fb3f | 1252 | git init submod && |
d4d17180 EN |
1253 | ( |
1254 | cd submod && | |
1255 | touch file-A && | |
1256 | git add file-A && | |
1257 | git commit -m A && | |
1258 | git tag A && | |
1259 | ||
1260 | git checkout -b B A && | |
1261 | touch file-B && | |
1262 | git add file-B && | |
1263 | git commit -m B && | |
1264 | git tag B && | |
1265 | ||
1266 | git checkout -b C A && | |
1267 | touch file-C && | |
1268 | git add file-C && | |
1269 | git commit -m C && | |
1270 | git tag C | |
1271 | ) && | |
1272 | ||
1273 | git -C submod reset --hard A && | |
1274 | git add submod && | |
1275 | git commit -m A && | |
1276 | git tag A && | |
1277 | ||
1278 | git checkout -b B A && | |
1279 | git -C submod reset --hard B && | |
1280 | git add submod && | |
1281 | git commit -m B && | |
1282 | ||
1283 | git checkout -b C A && | |
1284 | git -C submod reset --hard C && | |
1285 | git add submod && | |
1286 | git commit -m C && | |
1287 | ||
1288 | git checkout -q B^0 && | |
1289 | git merge -s ours -m D C^0 && | |
1290 | git tag D && | |
1291 | ||
1292 | git checkout -q C^0 && | |
1293 | git merge -s ours -m E B^0 && | |
1294 | git tag E | |
1295 | ) | |
1296 | ' | |
1297 | ||
f06481f1 | 1298 | test_expect_merge_algorithm failure success 'check submodule modify/modify' ' |
d4d17180 EN |
1299 | ( |
1300 | cd submodule-modify-modify && | |
1301 | ||
1302 | git checkout D^0 && | |
1303 | ||
1304 | test_must_fail git merge -s recursive E^0 && | |
1305 | ||
1306 | git ls-files -s >out && | |
1307 | test_line_count = 3 out && | |
1308 | git ls-files -u >out && | |
1309 | test_line_count = 3 out && | |
1310 | git ls-files -o >out && | |
1311 | test_line_count = 1 out | |
1312 | ) | |
1313 | ' | |
1314 | ||
a79968be EN |
1315 | # |
1316 | # criss-cross with add/add on a submodule: | |
1317 | # | |
1318 | # B D | |
1319 | # o---o | |
1320 | # / \ / \ | |
1321 | # A o X ? F | |
1322 | # \ / \ / | |
1323 | # o---o | |
1324 | # C E | |
1325 | # | |
1326 | # Commit A: nothing of note | |
1327 | # Commit B: introduce submodule repo | |
1328 | # Commit C: introduce submodule repo at different commit | |
1329 | # Commit D: merge B&C, resolving in favor of B | |
1330 | # Commit E: merge B&C, resolving in favor of C | |
1331 | # | |
1332 | # This is an obvious add/add conflict for the submodule 'repo'. Can | |
1333 | # git detect it? | |
1334 | ||
1335 | test_expect_success 'setup submodule add/add' ' | |
6693fb3f | 1336 | git init submodule-add-add && |
a79968be EN |
1337 | ( |
1338 | cd submodule-add-add && | |
1339 | ||
6693fb3f | 1340 | git init submod && |
a79968be EN |
1341 | ( |
1342 | cd submod && | |
1343 | touch file-A && | |
1344 | git add file-A && | |
1345 | git commit -m A && | |
1346 | git tag A && | |
1347 | ||
1348 | git checkout -b B A && | |
1349 | touch file-B && | |
1350 | git add file-B && | |
1351 | git commit -m B && | |
1352 | git tag B && | |
1353 | ||
1354 | git checkout -b C A && | |
1355 | touch file-C && | |
1356 | git add file-C && | |
1357 | git commit -m C && | |
1358 | git tag C | |
1359 | ) && | |
1360 | ||
1361 | touch irrelevant-file && | |
1362 | git add irrelevant-file && | |
1363 | git commit -m A && | |
1364 | git tag A && | |
1365 | ||
1366 | git checkout -b B A && | |
1367 | git -C submod reset --hard B && | |
1368 | git add submod && | |
1369 | git commit -m B && | |
1370 | ||
1371 | git checkout -b C A && | |
1372 | git -C submod reset --hard C && | |
1373 | git add submod && | |
1374 | git commit -m C && | |
1375 | ||
1376 | git checkout -q B^0 && | |
1377 | git merge -s ours -m D C^0 && | |
1378 | git tag D && | |
1379 | ||
1380 | git checkout -q C^0 && | |
1381 | git merge -s ours -m E B^0 && | |
1382 | git tag E | |
1383 | ) | |
1384 | ' | |
1385 | ||
f06481f1 | 1386 | test_expect_merge_algorithm failure success 'check submodule add/add' ' |
a79968be EN |
1387 | ( |
1388 | cd submodule-add-add && | |
1389 | ||
1390 | git checkout D^0 && | |
1391 | ||
1392 | test_must_fail git merge -s recursive E^0 && | |
1393 | ||
1394 | git ls-files -s >out && | |
1395 | test_line_count = 3 out && | |
1396 | git ls-files -u >out && | |
1397 | test_line_count = 2 out && | |
1398 | git ls-files -o >out && | |
1399 | test_line_count = 1 out | |
1400 | ) | |
1401 | ' | |
1402 | ||
451a3abc EN |
1403 | # |
1404 | # criss-cross with conflicting entry types: | |
1405 | # | |
1406 | # B D | |
1407 | # o---o | |
1408 | # / \ / \ | |
1409 | # A o X ? F | |
1410 | # \ / \ / | |
1411 | # o---o | |
1412 | # C E | |
1413 | # | |
1414 | # Commit A: nothing of note | |
1415 | # Commit B: introduce submodule 'path' | |
1416 | # Commit C: introduce symlink 'path' | |
1417 | # Commit D: merge B&C, resolving in favor of B | |
1418 | # Commit E: merge B&C, resolving in favor of C | |
1419 | # | |
1420 | # This is an obvious add/add conflict for 'path'. Can git detect it? | |
1421 | ||
1422 | test_expect_success 'setup conflicting entry types (submodule vs symlink)' ' | |
6693fb3f | 1423 | git init submodule-symlink-add-add && |
451a3abc EN |
1424 | ( |
1425 | cd submodule-symlink-add-add && | |
1426 | ||
6693fb3f | 1427 | git init path && |
451a3abc EN |
1428 | ( |
1429 | cd path && | |
1430 | touch file-B && | |
1431 | git add file-B && | |
1432 | git commit -m B && | |
1433 | git tag B | |
1434 | ) && | |
1435 | ||
1436 | touch irrelevant-file && | |
1437 | git add irrelevant-file && | |
1438 | git commit -m A && | |
1439 | git tag A && | |
1440 | ||
1441 | git checkout -b B A && | |
1442 | git -C path reset --hard B && | |
1443 | git add path && | |
1444 | git commit -m B && | |
1445 | ||
1446 | git checkout -b C A && | |
1447 | rm -rf path/ && | |
1448 | test_ln_s_add irrelevant-file path && | |
1449 | git commit -m C && | |
1450 | ||
1451 | git checkout -q B^0 && | |
1452 | git merge -s ours -m D C^0 && | |
1453 | git tag D && | |
1454 | ||
1455 | git checkout -q C^0 && | |
1456 | git merge -s ours -m E B^0 && | |
1457 | git tag E | |
1458 | ) | |
1459 | ' | |
1460 | ||
f06481f1 | 1461 | test_expect_merge_algorithm failure success 'check conflicting entry types (submodule vs symlink)' ' |
451a3abc EN |
1462 | ( |
1463 | cd submodule-symlink-add-add && | |
1464 | ||
1465 | git checkout D^0 && | |
1466 | ||
1467 | test_must_fail git merge -s recursive E^0 && | |
1468 | ||
1469 | git ls-files -s >out && | |
1470 | test_line_count = 3 out && | |
1471 | git ls-files -u >out && | |
1472 | test_line_count = 2 out && | |
1473 | git ls-files -o >out && | |
1474 | test_line_count = 1 out | |
1475 | ) | |
1476 | ' | |
1477 | ||
5d1daf30 EN |
1478 | # |
1479 | # criss-cross with regular files that have conflicting modes: | |
1480 | # | |
1481 | # B D | |
1482 | # o---o | |
1483 | # / \ / \ | |
1484 | # A o X ? F | |
1485 | # \ / \ / | |
1486 | # o---o | |
1487 | # C E | |
1488 | # | |
1489 | # Commit A: nothing of note | |
1490 | # Commit B: introduce file source_me.bash, not executable | |
1491 | # Commit C: introduce file source_me.bash, executable | |
1492 | # Commit D: merge B&C, resolving in favor of B | |
1493 | # Commit E: merge B&C, resolving in favor of C | |
1494 | # | |
1495 | # This is an obvious add/add mode conflict. Can git detect it? | |
1496 | ||
1497 | test_expect_success 'setup conflicting modes for regular file' ' | |
6693fb3f | 1498 | git init regular-file-mode-conflict && |
5d1daf30 EN |
1499 | ( |
1500 | cd regular-file-mode-conflict && | |
1501 | ||
1502 | touch irrelevant-file && | |
1503 | git add irrelevant-file && | |
1504 | git commit -m A && | |
1505 | git tag A && | |
1506 | ||
1507 | git checkout -b B A && | |
1508 | echo "command_to_run" >source_me.bash && | |
1509 | git add source_me.bash && | |
1510 | git commit -m B && | |
1511 | ||
1512 | git checkout -b C A && | |
1513 | echo "command_to_run" >source_me.bash && | |
1514 | git add source_me.bash && | |
1515 | test_chmod +x source_me.bash && | |
1516 | git commit -m C && | |
1517 | ||
1518 | git checkout -q B^0 && | |
1519 | git merge -s ours -m D C^0 && | |
1520 | git tag D && | |
1521 | ||
1522 | git checkout -q C^0 && | |
1523 | git merge -s ours -m E B^0 && | |
1524 | git tag E | |
1525 | ) | |
1526 | ' | |
1527 | ||
1528 | test_expect_failure 'check conflicting modes for regular file' ' | |
1529 | ( | |
1530 | cd regular-file-mode-conflict && | |
1531 | ||
1532 | git checkout D^0 && | |
1533 | ||
1534 | test_must_fail git merge -s recursive E^0 && | |
1535 | ||
1536 | git ls-files -s >out && | |
1537 | test_line_count = 3 out && | |
1538 | git ls-files -u >out && | |
1539 | test_line_count = 2 out && | |
1540 | git ls-files -o >out && | |
1541 | test_line_count = 1 out | |
1542 | ) | |
1543 | ' | |
1544 | ||
b28eeb30 EN |
1545 | # Setup: |
1546 | # L1---L2 | |
1547 | # / \ / \ | |
5902f5f4 | 1548 | # main X ? |
b28eeb30 EN |
1549 | # \ / \ / |
1550 | # R1---R2 | |
1551 | # | |
1552 | # Where: | |
5902f5f4 | 1553 | # main has two files, named 'b' and 'a' |
b28eeb30 EN |
1554 | # branches L1 and R1 both modify each of the two files in conflicting ways |
1555 | # | |
1556 | # L2 is a merge of R1 into L1; more on it later. | |
1557 | # R2 is a merge of L1 into R1; more on it later. | |
1558 | # | |
1559 | # X is an auto-generated merge-base used when merging L2 and R2. | |
1560 | # since X is a merge of L1 and R1, it has conflicting versions of each file | |
1561 | # | |
1562 | # More about L2 and R2: | |
1563 | # - both resolve the conflicts in 'b' and 'a' differently | |
1564 | # - L2 renames 'b' to 'm' | |
1565 | # - R2 renames 'a' to 'm' | |
1566 | # | |
1567 | # In the end, in file 'm' we have four different conflicting files (from | |
1568 | # two versions of 'b' and two of 'a'). In addition, if | |
1569 | # merge.conflictstyle is diff3, then the base version also has | |
1570 | # conflict markers of its own, leading to a total of three levels of | |
1571 | # conflict markers. This is a pretty weird corner case, but we just want | |
1572 | # to ensure that we handle it as well as practical. | |
1573 | ||
1574 | test_expect_success 'setup nested conflicts' ' | |
6693fb3f | 1575 | git init nested_conflicts && |
b28eeb30 EN |
1576 | ( |
1577 | cd nested_conflicts && | |
1578 | ||
1579 | # Create some related files now | |
efe26b9e | 1580 | printf "Random base content line %d\n" $(test_seq 1 10) >initial && |
b28eeb30 EN |
1581 | |
1582 | cp initial b_L1 && | |
1583 | cp initial b_R1 && | |
1584 | cp initial b_L2 && | |
1585 | cp initial b_R2 && | |
1586 | cp initial a_L1 && | |
1587 | cp initial a_R1 && | |
1588 | cp initial a_L2 && | |
1589 | cp initial a_R2 && | |
1590 | ||
1591 | test_write_lines b b_L1 >>b_L1 && | |
1592 | test_write_lines b b_R1 >>b_R1 && | |
1593 | test_write_lines b b_L2 >>b_L2 && | |
1594 | test_write_lines b b_R2 >>b_R2 && | |
1595 | test_write_lines a a_L1 >>a_L1 && | |
1596 | test_write_lines a a_R1 >>a_R1 && | |
1597 | test_write_lines a a_L2 >>a_L2 && | |
1598 | test_write_lines a a_R2 >>a_R2 && | |
1599 | ||
1600 | # Setup original commit (or merge-base), consisting of | |
1601 | # files named "b" and "a" | |
1602 | cp initial b && | |
1603 | cp initial a && | |
1604 | echo b >>b && | |
1605 | echo a >>a && | |
1606 | git add b a && | |
1607 | test_tick && git commit -m initial && | |
1608 | ||
1609 | git branch L && | |
1610 | git branch R && | |
1611 | ||
1612 | # Handle the left side | |
1613 | git checkout L && | |
1614 | mv -f b_L1 b && | |
1615 | mv -f a_L1 a && | |
1616 | git add b a && | |
1617 | test_tick && git commit -m "version L1 of files" && | |
1618 | git tag L1 && | |
1619 | ||
1620 | # Handle the right side | |
1621 | git checkout R && | |
1622 | mv -f b_R1 b && | |
1623 | mv -f a_R1 a && | |
1624 | git add b a && | |
aa74be31 | 1625 | test_tick && git commit -m "version R1 of files" && |
b28eeb30 EN |
1626 | git tag R1 && |
1627 | ||
1628 | # Create first merge on left side | |
1629 | git checkout L && | |
1630 | test_must_fail git merge R1 && | |
1631 | mv -f b_L2 b && | |
1632 | mv -f a_L2 a && | |
1633 | git add b a && | |
1634 | git mv b m && | |
1635 | test_tick && git commit -m "left merge, rename b->m" && | |
1636 | git tag L2 && | |
1637 | ||
1638 | # Create first merge on right side | |
1639 | git checkout R && | |
1640 | test_must_fail git merge L1 && | |
1641 | mv -f b_R2 b && | |
1642 | mv -f a_R2 a && | |
1643 | git add b a && | |
1644 | git mv a m && | |
1645 | test_tick && git commit -m "right merge, rename a->m" && | |
1646 | git tag R2 | |
1647 | ) | |
1648 | ' | |
1649 | ||
bbafc9c4 | 1650 | test_expect_success 'check nested conflicts' ' |
b28eeb30 EN |
1651 | ( |
1652 | cd nested_conflicts && | |
1653 | ||
1654 | git clean -f && | |
5902f5f4 | 1655 | MAIN=$(git rev-parse --short main) && |
b28eeb30 EN |
1656 | git checkout L2^0 && |
1657 | ||
1658 | # Merge must fail; there is a conflict | |
1659 | test_must_fail git -c merge.conflictstyle=diff3 merge -s recursive R2^0 && | |
1660 | ||
1661 | # Make sure the index has the right number of entries | |
1662 | git ls-files -s >out && | |
1663 | test_line_count = 2 out && | |
1664 | git ls-files -u >out && | |
1665 | test_line_count = 2 out && | |
1666 | # Ensure we have the correct number of untracked files | |
1667 | git ls-files -o >out && | |
1668 | test_line_count = 1 out && | |
1669 | ||
1670 | # Create a and b from virtual merge base X | |
5902f5f4 | 1671 | git cat-file -p main:a >base && |
b28eeb30 EN |
1672 | git cat-file -p L1:a >ours && |
1673 | git cat-file -p R1:a >theirs && | |
1674 | test_must_fail git merge-file --diff3 \ | |
1675 | -L "Temporary merge branch 1" \ | |
5902f5f4 | 1676 | -L "$MAIN" \ |
b28eeb30 EN |
1677 | -L "Temporary merge branch 2" \ |
1678 | ours \ | |
1679 | base \ | |
1680 | theirs && | |
1681 | sed -e "s/^\([<|=>]\)/\1\1/" ours >vmb_a && | |
1682 | ||
5902f5f4 | 1683 | git cat-file -p main:b >base && |
b28eeb30 EN |
1684 | git cat-file -p L1:b >ours && |
1685 | git cat-file -p R1:b >theirs && | |
1686 | test_must_fail git merge-file --diff3 \ | |
1687 | -L "Temporary merge branch 1" \ | |
5902f5f4 | 1688 | -L "$MAIN" \ |
b28eeb30 EN |
1689 | -L "Temporary merge branch 2" \ |
1690 | ours \ | |
1691 | base \ | |
1692 | theirs && | |
1693 | sed -e "s/^\([<|=>]\)/\1\1/" ours >vmb_b && | |
1694 | ||
1695 | # Compare :2:m to expected values | |
1696 | git cat-file -p L2:m >ours && | |
1697 | git cat-file -p R2:b >theirs && | |
1698 | test_must_fail git merge-file --diff3 \ | |
1699 | -L "HEAD:m" \ | |
1700 | -L "merged common ancestors:b" \ | |
1701 | -L "R2^0:b" \ | |
1702 | ours \ | |
1703 | vmb_b \ | |
1704 | theirs && | |
1705 | sed -e "s/^\([<|=>]\)/\1\1/" ours >m_stage_2 && | |
1706 | git cat-file -p :2:m >actual && | |
1707 | test_cmp m_stage_2 actual && | |
1708 | ||
1709 | # Compare :3:m to expected values | |
1710 | git cat-file -p L2:a >ours && | |
1711 | git cat-file -p R2:m >theirs && | |
1712 | test_must_fail git merge-file --diff3 \ | |
1713 | -L "HEAD:a" \ | |
1714 | -L "merged common ancestors:a" \ | |
1715 | -L "R2^0:m" \ | |
1716 | ours \ | |
1717 | vmb_a \ | |
1718 | theirs && | |
1719 | sed -e "s/^\([<|=>]\)/\1\1/" ours >m_stage_3 && | |
1720 | git cat-file -p :3:m >actual && | |
1721 | test_cmp m_stage_3 actual && | |
1722 | ||
1723 | # Compare m to expected contents | |
1724 | >empty && | |
cc4cb090 | 1725 | cp m_stage_2 expected_final_m && |
b28eeb30 EN |
1726 | test_must_fail git merge-file --diff3 \ |
1727 | -L "HEAD" \ | |
1728 | -L "merged common ancestors" \ | |
1729 | -L "R2^0" \ | |
1730 | expected_final_m \ | |
1731 | empty \ | |
1732 | m_stage_3 && | |
1733 | test_cmp expected_final_m m | |
1734 | ) | |
1735 | ' | |
1736 | ||
b2a7942b EN |
1737 | # Setup: |
1738 | # L1---L2---L3 | |
1739 | # / \ / \ / \ | |
5902f5f4 | 1740 | # main X1 X2 ? |
b2a7942b EN |
1741 | # \ / \ / \ / |
1742 | # R1---R2---R3 | |
1743 | # | |
1744 | # Where: | |
5902f5f4 | 1745 | # main has one file named 'content' |
b2a7942b EN |
1746 | # branches L1 and R1 both modify each of the two files in conflicting ways |
1747 | # | |
1748 | # L<n> (n>1) is a merge of R<n-1> into L<n-1> | |
1749 | # R<n> (n>1) is a merge of L<n-1> into R<n-1> | |
1750 | # L<n> and R<n> resolve the conflicts differently. | |
1751 | # | |
1752 | # X<n> is an auto-generated merge-base used when merging L<n+1> and R<n+1>. | |
1753 | # By construction, X1 has conflict markers due to conflicting versions. | |
1754 | # X2, due to using merge.conflictstyle=3, has nested conflict markers. | |
1755 | # | |
1756 | # So, merging R3 into L3 using merge.conflictstyle=3 should show the | |
1757 | # nested conflict markers from X2 in the base version -- that means we | |
1758 | # have three levels of conflict markers. Can we distinguish all three? | |
1759 | ||
1760 | test_expect_success 'setup virtual merge base with nested conflicts' ' | |
6693fb3f | 1761 | git init virtual_merge_base_has_nested_conflicts && |
b2a7942b EN |
1762 | ( |
1763 | cd virtual_merge_base_has_nested_conflicts && | |
1764 | ||
1765 | # Create some related files now | |
efe26b9e | 1766 | printf "Random base content line %d\n" $(test_seq 1 10) >content && |
b2a7942b EN |
1767 | |
1768 | # Setup original commit | |
1769 | git add content && | |
1770 | test_tick && git commit -m initial && | |
1771 | ||
1772 | git branch L && | |
1773 | git branch R && | |
1774 | ||
1775 | # Create L1 | |
1776 | git checkout L && | |
1777 | echo left >>content && | |
1778 | git add content && | |
1779 | test_tick && git commit -m "version L1 of content" && | |
1780 | git tag L1 && | |
1781 | ||
1782 | # Create R1 | |
1783 | git checkout R && | |
1784 | echo right >>content && | |
1785 | git add content && | |
aa74be31 | 1786 | test_tick && git commit -m "version R1 of content" && |
b2a7942b EN |
1787 | git tag R1 && |
1788 | ||
1789 | # Create L2 | |
1790 | git checkout L && | |
1791 | test_must_fail git -c merge.conflictstyle=diff3 merge R1 && | |
1792 | git checkout L1 content && | |
1793 | test_tick && git commit -m "version L2 of content" && | |
1794 | git tag L2 && | |
1795 | ||
1796 | # Create R2 | |
1797 | git checkout R && | |
1798 | test_must_fail git -c merge.conflictstyle=diff3 merge L1 && | |
1799 | git checkout R1 content && | |
1800 | test_tick && git commit -m "version R2 of content" && | |
1801 | git tag R2 && | |
1802 | ||
1803 | # Create L3 | |
1804 | git checkout L && | |
1805 | test_must_fail git -c merge.conflictstyle=diff3 merge R2 && | |
1806 | git checkout L1 content && | |
1807 | test_tick && git commit -m "version L3 of content" && | |
1808 | git tag L3 && | |
1809 | ||
1810 | # Create R3 | |
1811 | git checkout R && | |
1812 | test_must_fail git -c merge.conflictstyle=diff3 merge L2 && | |
1813 | git checkout R1 content && | |
1814 | test_tick && git commit -m "version R3 of content" && | |
1815 | git tag R3 | |
1816 | ) | |
1817 | ' | |
1818 | ||
1819 | test_expect_success 'check virtual merge base with nested conflicts' ' | |
1820 | ( | |
1821 | cd virtual_merge_base_has_nested_conflicts && | |
1822 | ||
5902f5f4 | 1823 | MAIN=$(git rev-parse --short main) && |
b2a7942b EN |
1824 | git checkout L3^0 && |
1825 | ||
1826 | # Merge must fail; there is a conflict | |
1827 | test_must_fail git -c merge.conflictstyle=diff3 merge -s recursive R3^0 && | |
1828 | ||
1829 | # Make sure the index has the right number of entries | |
1830 | git ls-files -s >out && | |
1831 | test_line_count = 3 out && | |
1832 | git ls-files -u >out && | |
1833 | test_line_count = 3 out && | |
1834 | # Ensure we have the correct number of untracked files | |
1835 | git ls-files -o >out && | |
1836 | test_line_count = 1 out && | |
1837 | ||
1838 | # Compare :[23]:content to expected values | |
1839 | git rev-parse L1:content R1:content >expect && | |
1840 | git rev-parse :2:content :3:content >actual && | |
1841 | test_cmp expect actual && | |
1842 | ||
1843 | # Imitate X1 merge base, except without long enough conflict | |
1844 | # markers because a subsequent sed will modify them. Put | |
1845 | # result into vmb. | |
5902f5f4 | 1846 | git cat-file -p main:content >base && |
b2a7942b EN |
1847 | git cat-file -p L:content >left && |
1848 | git cat-file -p R:content >right && | |
1849 | cp left merged-once && | |
1850 | test_must_fail git merge-file --diff3 \ | |
1851 | -L "Temporary merge branch 1" \ | |
5902f5f4 | 1852 | -L "$MAIN" \ |
b2a7942b EN |
1853 | -L "Temporary merge branch 2" \ |
1854 | merged-once \ | |
1855 | base \ | |
1856 | right && | |
1857 | sed -e "s/^\([<|=>]\)/\1\1\1/" merged-once >vmb && | |
1858 | ||
1859 | # Imitate X2 merge base, overwriting vmb. Note that we | |
1860 | # extend both sets of conflict markers to make them longer | |
1861 | # with the sed command. | |
1862 | cp left merged-twice && | |
1863 | test_must_fail git merge-file --diff3 \ | |
1864 | -L "Temporary merge branch 1" \ | |
1865 | -L "merged common ancestors" \ | |
1866 | -L "Temporary merge branch 2" \ | |
1867 | merged-twice \ | |
1868 | vmb \ | |
1869 | right && | |
1870 | sed -e "s/^\([<|=>]\)/\1\1\1/" merged-twice >vmb && | |
1871 | ||
1872 | # Compare :1:content to expected value | |
1873 | git cat-file -p :1:content >actual && | |
1874 | test_cmp vmb actual && | |
1875 | ||
1876 | # Determine expected content in final outer merge, compare to | |
1877 | # what the merge generated. | |
1878 | cp -f left expect && | |
1879 | test_must_fail git merge-file --diff3 \ | |
1880 | -L "HEAD" -L "merged common ancestors" -L "R3^0" \ | |
1881 | expect vmb right && | |
1882 | test_cmp expect content | |
1883 | ) | |
1884 | ' | |
1885 | ||
c94736a2 | 1886 | test_done |