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