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