Git fork
at reftables-rust 1030 lines 30 kB view raw
1#!/bin/sh 2 3test_description='git merge-tree --write-tree' 4 5. ./test-lib.sh 6 7test_expect_success setup ' 8 test_write_lines 1 2 3 4 5 >numbers && 9 echo hello >greeting && 10 echo foo >whatever && 11 git add numbers greeting whatever && 12 test_tick && 13 git commit -m initial && 14 15 git branch side1 && 16 git branch side2 && 17 git branch side3 && 18 git branch side4 && 19 20 git checkout side1 && 21 test_write_lines 1 2 3 4 5 6 >numbers && 22 echo hi >greeting && 23 echo bar >whatever && 24 git add numbers greeting whatever && 25 test_tick && 26 git commit -m modify-stuff && 27 28 git checkout side2 && 29 test_write_lines 0 1 2 3 4 5 >numbers && 30 echo yo >greeting && 31 git rm whatever && 32 mkdir whatever && 33 >whatever/empty && 34 git add numbers greeting whatever/empty && 35 test_tick && 36 git commit -m other-modifications && 37 38 git checkout side3 && 39 git mv numbers sequence && 40 test_tick && 41 git commit -m rename-numbers && 42 43 git checkout side4 && 44 test_write_lines 0 1 2 3 4 5 >numbers && 45 echo yo >greeting && 46 git add numbers greeting && 47 test_tick && 48 git commit -m other-content-modifications && 49 50 git switch --orphan unrelated && 51 >something-else && 52 git add something-else && 53 test_tick && 54 git commit -m first-commit 55' 56 57test_expect_success '--quiet on clean merge' ' 58 # Get rid of loose objects to start with 59 git gc && 60 echo "0 objects, 0 kilobytes" >expect && 61 git count-objects >actual && 62 test_cmp expect actual && 63 64 # Ensure merge is successful (exit code of 0) 65 git merge-tree --write-tree --quiet side1 side3 >output && 66 67 # Ensure there is no output 68 test_must_be_empty output && 69 70 # Ensure no loose objects written (all new objects written would have 71 # been in "outer layer" of the merge) 72 git count-objects >actual && 73 test_cmp expect actual 74' 75 76test_expect_success 'Clean merge' ' 77 TREE_OID=$(git merge-tree --write-tree side1 side3) && 78 q_to_tab <<-EOF >expect && 79 100644 blob $(git rev-parse side1:greeting)Qgreeting 80 100644 blob $(git rev-parse side1:numbers)Qsequence 81 100644 blob $(git rev-parse side1:whatever)Qwhatever 82 EOF 83 84 git ls-tree $TREE_OID >actual && 85 test_cmp expect actual 86' 87 88# Repeat the previous test, but turn off rename detection 89test_expect_success 'Failed merge without rename detection' ' 90 test_must_fail git -c diff.renames=false merge-tree --write-tree side1 side3 >out && 91 grep "CONFLICT (modify/delete): numbers deleted" out 92' 93 94test_expect_success '--quiet on conflicted merge' ' 95 # Get rid of loose objects to start with 96 git gc && 97 echo "0 objects, 0 kilobytes" >expect && 98 git count-objects >actual && 99 test_cmp expect actual && 100 101 # Ensure merge has conflict 102 test_expect_code 1 git merge-tree --write-tree --quiet side1 side2 >output && 103 104 # Ensure there is no output 105 test_must_be_empty output && 106 107 # Ensure no loose objects written (all new objects written would have 108 # been in "outer layer" of the merge) 109 git count-objects >actual && 110 test_cmp expect actual 111' 112 113test_expect_success 'Content merge and a few conflicts' ' 114 git checkout side1^0 && 115 test_must_fail git merge side2 && 116 expected_tree=$(git rev-parse AUTO_MERGE) && 117 118 # We will redo the merge, while we are still in a conflicted state! 119 git ls-files -u >conflicted-file-info && 120 test_when_finished "git reset --hard" && 121 122 test_expect_code 1 git merge-tree --write-tree side1 side2 >RESULT && 123 actual_tree=$(head -n 1 RESULT) && 124 125 # Due to differences of e.g. "HEAD" vs "side1", the results will not 126 # exactly match. Dig into individual files. 127 128 # Numbers should have three-way merged cleanly 129 test_write_lines 0 1 2 3 4 5 6 >expect && 130 git show ${actual_tree}:numbers >actual && 131 test_cmp expect actual && 132 133 # whatever and whatever~<branch> should have same HASHES 134 git rev-parse ${expected_tree}:whatever ${expected_tree}:whatever~HEAD >expect && 135 git rev-parse ${actual_tree}:whatever ${actual_tree}:whatever~side1 >actual && 136 test_cmp expect actual && 137 138 # greeting should have a merge conflict 139 git show ${expected_tree}:greeting >tmp && 140 sed -e s/HEAD/side1/ tmp >expect && 141 git show ${actual_tree}:greeting >actual && 142 test_cmp expect actual 143' 144 145test_expect_success 'Auto resolve conflicts by "ours" strategy option' ' 146 git checkout side1^0 && 147 148 # make sure merge conflict exists 149 test_must_fail git merge side4 && 150 git merge --abort && 151 152 git merge -X ours side4 && 153 git rev-parse HEAD^{tree} >expected && 154 155 git merge-tree -X ours side1 side4 >actual && 156 157 test_cmp expected actual 158' 159 160test_expect_success 'Barf on misspelled option, with exit code other than 0 or 1' ' 161 # Mis-spell with single "s" instead of double "s" 162 test_expect_code 129 git merge-tree --write-tree --mesages FOOBAR side1 side2 2>expect && 163 164 grep "error: unknown option.*mesages" expect 165' 166 167test_expect_success 'Barf on too many arguments' ' 168 test_expect_code 129 git merge-tree --write-tree side1 side2 invalid 2>expect && 169 170 grep "^usage: git merge-tree" expect 171' 172 173anonymize_hash() { 174 sed -e "s/[0-9a-f]\{40,\}/HASH/g" "$@" 175} 176 177test_expect_success 'test conflict notices and such' ' 178 test_expect_code 1 git merge-tree --write-tree --name-only side1 side2 >out && 179 anonymize_hash out >actual && 180 181 # Expected results: 182 # "greeting" should merge with conflicts 183 # "numbers" should merge cleanly 184 # "whatever" has *both* a modify/delete and a file/directory conflict 185 cat <<-EOF >expect && 186 HASH 187 greeting 188 whatever~side1 189 190 Auto-merging greeting 191 CONFLICT (content): Merge conflict in greeting 192 Auto-merging numbers 193 CONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead. 194 CONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1. Version side1 of whatever~side1 left in tree. 195 EOF 196 197 test_cmp expect actual 198' 199 200# directory rename + content conflict 201# Commit O: foo, olddir/{a,b,c} 202# Commit A: modify foo, newdir/{a,b,c} 203# Commit B: modify foo differently & rename foo -> olddir/bar 204# Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo) 205 206test_expect_success 'directory rename + content conflict' ' 207 # Setup 208 git init dir-rename-and-content && 209 ( 210 cd dir-rename-and-content && 211 test_write_lines 1 2 3 4 5 >foo && 212 mkdir olddir && 213 for i in a b c; do echo $i >olddir/$i || exit 1; done && 214 git add foo olddir && 215 git commit -m "original" && 216 217 git branch O && 218 git branch A && 219 git branch B && 220 221 git checkout A && 222 test_write_lines 1 2 3 4 5 6 >foo && 223 git add foo && 224 git mv olddir newdir && 225 git commit -m "Modify foo, rename olddir to newdir" && 226 227 git checkout B && 228 test_write_lines 1 2 3 4 5 six >foo && 229 git add foo && 230 git mv foo olddir/bar && 231 git commit -m "Modify foo & rename foo -> olddir/bar" 232 ) && 233 # Testing 234 ( 235 cd dir-rename-and-content && 236 237 test_expect_code 1 \ 238 git merge-tree -z A^0 B^0 >out && 239 echo >>out && 240 anonymize_hash out >actual && 241 q_to_tab <<-\EOF | lf_to_nul >expect && 242 HASH 243 100644 HASH 1Qnewdir/bar 244 100644 HASH 2Qnewdir/bar 245 100644 HASH 3Qnewdir/bar 246 EOF 247 248 q_to_nul <<-EOF >>expect && 249 Q2Qnewdir/barQolddir/barQCONFLICT (directory rename suggested)QCONFLICT (file location): foo renamed to olddir/bar in B^0, inside a directory that was renamed in A^0, suggesting it should perhaps be moved to newdir/bar. 250 Q1Qnewdir/barQAuto-mergingQAuto-merging newdir/bar 251 Q1Qnewdir/barQCONFLICT (contents)QCONFLICT (content): Merge conflict in newdir/bar 252 Q 253 EOF 254 test_cmp expect actual 255 ) 256' 257 258# rename/delete + modify/delete handling 259# Commit O: foo 260# Commit A: modify foo + rename to bar 261# Commit B: delete foo 262# Expected: CONFLICT(rename/delete) + CONFLICT(modify/delete) 263 264test_expect_success 'rename/delete handling' ' 265 # Setup 266 git init rename-delete && 267 ( 268 cd rename-delete && 269 test_write_lines 1 2 3 4 5 >foo && 270 git add foo && 271 git commit -m "original" && 272 273 git branch O && 274 git branch A && 275 git branch B && 276 277 git checkout A && 278 test_write_lines 1 2 3 4 5 6 >foo && 279 git add foo && 280 git mv foo bar && 281 git commit -m "Modify foo, rename to bar" && 282 283 git checkout B && 284 git rm foo && 285 git commit -m "remove foo" 286 ) && 287 # Testing 288 ( 289 cd rename-delete && 290 291 test_expect_code 1 \ 292 git merge-tree -z A^0 B^0 >out && 293 echo >>out && 294 anonymize_hash out >actual && 295 q_to_tab <<-\EOF | lf_to_nul >expect && 296 HASH 297 100644 HASH 1Qbar 298 100644 HASH 2Qbar 299 EOF 300 301 q_to_nul <<-EOF >>expect && 302 Q2QbarQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to bar in A^0, but deleted in B^0. 303 Q1QbarQCONFLICT (modify/delete)QCONFLICT (modify/delete): bar deleted in B^0 and modified in A^0. Version A^0 of bar left in tree. 304 Q 305 EOF 306 test_cmp expect actual 307 ) 308' 309 310# rename/add handling 311# Commit O: foo 312# Commit A: modify foo, add different bar 313# Commit B: modify & rename foo->bar 314# Expected: CONFLICT(add/add) [via rename collide] for bar 315 316test_expect_success 'rename/add handling' ' 317 # Setup 318 git init rename-add && 319 ( 320 cd rename-add && 321 test_write_lines original 1 2 3 4 5 >foo && 322 git add foo && 323 git commit -m "original" && 324 325 git branch O && 326 git branch A && 327 git branch B && 328 329 git checkout A && 330 test_write_lines 1 2 3 4 5 >foo && 331 echo "different file" >bar && 332 git add foo bar && 333 git commit -m "Modify foo, add bar" && 334 335 git checkout B && 336 test_write_lines original 1 2 3 4 5 6 >foo && 337 git add foo && 338 git mv foo bar && 339 git commit -m "rename foo to bar" 340 ) && 341 # Testing 342 ( 343 cd rename-add && 344 345 test_expect_code 1 \ 346 git merge-tree -z A^0 B^0 >out && 347 echo >>out && 348 349 # 350 # First, check that the bar that appears at stage 3 does not 351 # correspond to an individual blob anywhere in history 352 # 353 hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") && 354 git rev-list --objects --all >all_blobs && 355 ! grep $hash all_blobs && 356 357 # 358 # Second, check anonymized hash output against expectation 359 # 360 anonymize_hash out >actual && 361 q_to_tab <<-\EOF | lf_to_nul >expect && 362 HASH 363 100644 HASH 2Qbar 364 100644 HASH 3Qbar 365 EOF 366 367 q_to_nul <<-EOF >>expect && 368 Q1QbarQAuto-mergingQAuto-merging bar 369 Q1QbarQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in bar 370 Q1QfooQAuto-mergingQAuto-merging foo 371 Q 372 EOF 373 test_cmp expect actual 374 ) 375' 376 377# rename/add, where add is a mode conflict 378# Commit O: foo 379# Commit A: modify foo, add symlink bar 380# Commit B: modify & rename foo->bar 381# Expected: CONFLICT(distinct modes) for bar 382 383test_expect_success SYMLINKS 'rename/add, where add is a mode conflict' ' 384 # Setup 385 git init rename-add-symlink && 386 ( 387 cd rename-add-symlink && 388 test_write_lines original 1 2 3 4 5 >foo && 389 git add foo && 390 git commit -m "original" && 391 392 git branch O && 393 git branch A && 394 git branch B && 395 396 git checkout A && 397 test_write_lines 1 2 3 4 5 >foo && 398 ln -s foo bar && 399 git add foo bar && 400 git commit -m "Modify foo, add symlink bar" && 401 402 git checkout B && 403 test_write_lines original 1 2 3 4 5 6 >foo && 404 git add foo && 405 git mv foo bar && 406 git commit -m "rename foo to bar" 407 ) && 408 # Testing 409 ( 410 cd rename-add-symlink && 411 412 test_expect_code 1 \ 413 git merge-tree -z A^0 B^0 >out && 414 echo >>out && 415 416 # 417 # First, check that the bar that appears at stage 3 does not 418 # correspond to an individual blob anywhere in history 419 # 420 hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") && 421 git rev-list --objects --all >all_blobs && 422 ! grep $hash all_blobs && 423 424 # 425 # Second, check anonymized hash output against expectation 426 # 427 anonymize_hash out >actual && 428 q_to_tab <<-\EOF | lf_to_nul >expect && 429 HASH 430 120000 HASH 2Qbar 431 100644 HASH 3Qbar~B^0 432 EOF 433 434 q_to_nul <<-EOF >>expect && 435 Q2QbarQbar~B^0QCONFLICT (distinct modes)QCONFLICT (distinct types): bar had different types on each side; renamed one of them so each can be recorded somewhere. 436 Q1QfooQAuto-mergingQAuto-merging foo 437 Q 438 EOF 439 test_cmp expect actual 440 ) 441' 442 443# rename/rename(1to2) + content conflict handling 444# Commit O: foo 445# Commit A: modify foo & rename to bar 446# Commit B: modify foo & rename to baz 447# Expected: CONFLICT(rename/rename) 448 449test_expect_success 'rename/rename + content conflict' ' 450 # Setup 451 git init rr-plus-content && 452 ( 453 cd rr-plus-content && 454 test_write_lines 1 2 3 4 5 >foo && 455 git add foo && 456 git commit -m "original" && 457 458 git branch O && 459 git branch A && 460 git branch B && 461 462 git checkout A && 463 test_write_lines 1 2 3 4 5 six >foo && 464 git add foo && 465 git mv foo bar && 466 git commit -m "Modify foo + rename to bar" && 467 468 git checkout B && 469 test_write_lines 1 2 3 4 5 6 >foo && 470 git add foo && 471 git mv foo baz && 472 git commit -m "Modify foo + rename to baz" 473 ) && 474 # Testing 475 ( 476 cd rr-plus-content && 477 478 test_expect_code 1 \ 479 git merge-tree -z A^0 B^0 >out && 480 echo >>out && 481 anonymize_hash out >actual && 482 q_to_tab <<-\EOF | lf_to_nul >expect && 483 HASH 484 100644 HASH 2Qbar 485 100644 HASH 3Qbaz 486 100644 HASH 1Qfoo 487 EOF 488 489 q_to_nul <<-EOF >>expect && 490 Q1QfooQAuto-mergingQAuto-merging foo 491 Q3QfooQbarQbazQCONFLICT (rename/rename)QCONFLICT (rename/rename): foo renamed to bar in A^0 and to baz in B^0. 492 Q 493 EOF 494 test_cmp expect actual 495 ) 496' 497 498# rename/add/delete 499# Commit O: foo 500# Commit A: rm foo, add different bar 501# Commit B: rename foo->bar 502# Expected: CONFLICT (rename/delete), CONFLICT(add/add) [via rename collide] 503# for bar 504 505test_expect_success 'rename/add/delete conflict' ' 506 # Setup 507 git init rad && 508 ( 509 cd rad && 510 echo "original file" >foo && 511 git add foo && 512 git commit -m "original" && 513 514 git branch O && 515 git branch A && 516 git branch B && 517 518 git checkout A && 519 git rm foo && 520 echo "different file" >bar && 521 git add bar && 522 git commit -m "Remove foo, add bar" && 523 524 git checkout B && 525 git mv foo bar && 526 git commit -m "rename foo to bar" 527 ) && 528 # Testing 529 ( 530 cd rad && 531 532 test_expect_code 1 \ 533 git merge-tree -z B^0 A^0 >out && 534 echo >>out && 535 anonymize_hash out >actual && 536 537 q_to_tab <<-\EOF | lf_to_nul >expect && 538 HASH 539 100644 HASH 2Qbar 540 100644 HASH 3Qbar 541 542 EOF 543 544 q_to_nul <<-EOF >>expect && 545 2QbarQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to bar in B^0, but deleted in A^0. 546 Q1QbarQAuto-mergingQAuto-merging bar 547 Q1QbarQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in bar 548 Q 549 EOF 550 test_cmp expect actual 551 ) 552' 553 554# rename/rename(2to1)/delete/delete 555# Commit O: foo, bar 556# Commit A: rename foo->baz, rm bar 557# Commit B: rename bar->baz, rm foo 558# Expected: 2x CONFLICT (rename/delete), CONFLICT (add/add) via colliding 559# renames for baz 560 561test_expect_success 'rename/rename(2to1)/delete/delete conflict' ' 562 # Setup 563 git init rrdd && 564 ( 565 cd rrdd && 566 echo foo >foo && 567 echo bar >bar && 568 git add foo bar && 569 git commit -m O && 570 571 git branch O && 572 git branch A && 573 git branch B && 574 575 git checkout A && 576 git mv foo baz && 577 git rm bar && 578 git commit -m "Rename foo, remove bar" && 579 580 git checkout B && 581 git mv bar baz && 582 git rm foo && 583 git commit -m "Rename bar, remove foo" 584 ) && 585 # Testing 586 ( 587 cd rrdd && 588 589 test_expect_code 1 \ 590 git merge-tree -z A^0 B^0 >out && 591 echo >>out && 592 anonymize_hash out >actual && 593 594 q_to_tab <<-\EOF | lf_to_nul >expect && 595 HASH 596 100644 HASH 2Qbaz 597 100644 HASH 3Qbaz 598 599 EOF 600 601 q_to_nul <<-EOF >>expect && 602 2QbazQbarQCONFLICT (rename/delete)QCONFLICT (rename/delete): bar renamed to baz in B^0, but deleted in A^0. 603 Q2QbazQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to baz in A^0, but deleted in B^0. 604 Q1QbazQAuto-mergingQAuto-merging baz 605 Q1QbazQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in baz 606 Q 607 EOF 608 test_cmp expect actual 609 ) 610' 611 612# mod6: chains of rename/rename(1to2) + add/add via colliding renames 613# Commit O: one, three, five 614# Commit A: one->two, three->four, five->six 615# Commit B: one->six, three->two, five->four 616# Expected: three CONFLICT(rename/rename) messages + three CONFLICT(add/add) 617# messages; each path in two of the multi-way merged contents 618# found in two, four, six 619 620test_expect_success 'mod6: chains of rename/rename(1to2) and add/add via colliding renames' ' 621 # Setup 622 git init mod6 && 623 ( 624 cd mod6 && 625 test_seq 11 19 >one && 626 test_seq 31 39 >three && 627 test_seq 51 59 >five && 628 git add . && 629 test_tick && 630 git commit -m "O" && 631 632 git branch O && 633 git branch A && 634 git branch B && 635 636 git checkout A && 637 test_seq 10 19 >one && 638 echo 40 >>three && 639 git add one three && 640 git mv one two && 641 git mv three four && 642 git mv five six && 643 test_tick && 644 git commit -m "A" && 645 646 git checkout B && 647 echo 20 >>one && 648 echo forty >>three && 649 echo 60 >>five && 650 git add one three five && 651 git mv one six && 652 git mv three two && 653 git mv five four && 654 test_tick && 655 git commit -m "B" 656 ) && 657 # Testing 658 ( 659 cd mod6 && 660 661 test_expect_code 1 \ 662 git merge-tree -z A^0 B^0 >out && 663 echo >>out && 664 665 # 666 # First, check that some of the hashes that appear as stage 667 # conflict entries do not appear as individual blobs anywhere 668 # in history. 669 # 670 hash1=$(tr "\0" "\n" <out | head | grep 2.four | cut -f 2 -d " ") && 671 hash2=$(tr "\0" "\n" <out | head | grep 3.two | cut -f 2 -d " ") && 672 git rev-list --objects --all >all_blobs && 673 ! grep $hash1 all_blobs && 674 ! grep $hash2 all_blobs && 675 676 # 677 # Now compare anonymized hash output with expectation 678 # 679 anonymize_hash out >actual && 680 q_to_tab <<-\EOF | lf_to_nul >expect && 681 HASH 682 100644 HASH 1Qfive 683 100644 HASH 2Qfour 684 100644 HASH 3Qfour 685 100644 HASH 1Qone 686 100644 HASH 2Qsix 687 100644 HASH 3Qsix 688 100644 HASH 1Qthree 689 100644 HASH 2Qtwo 690 100644 HASH 3Qtwo 691 692 EOF 693 694 q_to_nul <<-EOF >>expect && 695 3QfiveQsixQfourQCONFLICT (rename/rename)QCONFLICT (rename/rename): five renamed to six in A^0 and to four in B^0. 696 Q1QfourQAuto-mergingQAuto-merging four 697 Q1QfourQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in four 698 Q1QoneQAuto-mergingQAuto-merging one 699 Q3QoneQtwoQsixQCONFLICT (rename/rename)QCONFLICT (rename/rename): one renamed to two in A^0 and to six in B^0. 700 Q1QsixQAuto-mergingQAuto-merging six 701 Q1QsixQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in six 702 Q1QthreeQAuto-mergingQAuto-merging three 703 Q3QthreeQfourQtwoQCONFLICT (rename/rename)QCONFLICT (rename/rename): three renamed to four in A^0 and to two in B^0. 704 Q1QtwoQAuto-mergingQAuto-merging two 705 Q1QtwoQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in two 706 Q 707 EOF 708 test_cmp expect actual 709 ) 710' 711 712# directory rename + rename/delete + modify/delete + directory/file conflict 713# Commit O: foo, olddir/{a,b,c} 714# Commit A: delete foo, rename olddir/ -> newdir/, add newdir/bar/file 715# Commit B: modify foo & rename foo -> olddir/bar 716# Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo) 717 718test_expect_success 'directory rename + rename/delete + modify/delete + directory/file conflict' ' 719 # Setup 720 git init 4-stacked-conflict && 721 ( 722 cd 4-stacked-conflict && 723 test_write_lines 1 2 3 4 5 >foo && 724 mkdir olddir && 725 for i in a b c; do echo $i >olddir/$i || exit 1; done && 726 git add foo olddir && 727 git commit -m "original" && 728 729 git branch O && 730 git branch A && 731 git branch B && 732 733 git checkout A && 734 git rm foo && 735 git mv olddir newdir && 736 mkdir newdir/bar && 737 >newdir/bar/file && 738 git add newdir/bar/file && 739 git commit -m "rm foo, olddir/ -> newdir/, + newdir/bar/file" && 740 741 git checkout B && 742 test_write_lines 1 2 3 4 5 6 >foo && 743 git add foo && 744 git mv foo olddir/bar && 745 git commit -m "Modify foo & rename foo -> olddir/bar" 746 ) && 747 # Testing 748 ( 749 cd 4-stacked-conflict && 750 751 test_expect_code 1 \ 752 git merge-tree -z A^0 B^0 >out && 753 echo >>out && 754 anonymize_hash out >actual && 755 756 q_to_tab <<-\EOF | lf_to_nul >expect && 757 HASH 758 100644 HASH 1Qnewdir/bar~B^0 759 100644 HASH 3Qnewdir/bar~B^0 760 EOF 761 762 q_to_nul <<-EOF >>expect && 763 Q2Qnewdir/barQolddir/barQCONFLICT (directory rename suggested)QCONFLICT (file location): foo renamed to olddir/bar in B^0, inside a directory that was renamed in A^0, suggesting it should perhaps be moved to newdir/bar. 764 Q2Qnewdir/barQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to newdir/bar in B^0, but deleted in A^0. 765 Q2Qnewdir/bar~B^0Qnewdir/barQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of newdir/bar from B^0; moving it to newdir/bar~B^0 instead. 766 Q1Qnewdir/bar~B^0QCONFLICT (modify/delete)QCONFLICT (modify/delete): newdir/bar~B^0 deleted in A^0 and modified in B^0. Version B^0 of newdir/bar~B^0 left in tree. 767 Q 768 EOF 769 test_cmp expect actual 770 ) 771' 772 773for opt in $(git merge-tree --git-completion-helper-all) 774do 775 if test $opt = "--trivial-merge" || test $opt = "--write-tree" 776 then 777 continue 778 fi 779 780 test_expect_success "usage: --trivial-merge is incompatible with $opt" ' 781 test_expect_code 128 git merge-tree --trivial-merge $opt side1 side2 side3 782 ' 783done 784 785test_expect_success 'Just the conflicted files without the messages' ' 786 test_expect_code 1 git merge-tree --write-tree --no-messages --name-only side1 side2 >out && 787 anonymize_hash out >actual && 788 789 test_write_lines HASH greeting whatever~side1 >expect && 790 791 test_cmp expect actual 792' 793 794test_expect_success 'Check conflicted oids and modes without messages' ' 795 test_expect_code 1 git merge-tree --write-tree --no-messages side1 side2 >out && 796 anonymize_hash out >actual && 797 798 # Compare the basic output format 799 q_to_tab >expect <<-\EOF && 800 HASH 801 100644 HASH 1Qgreeting 802 100644 HASH 2Qgreeting 803 100644 HASH 3Qgreeting 804 100644 HASH 1Qwhatever~side1 805 100644 HASH 2Qwhatever~side1 806 EOF 807 808 test_cmp expect actual && 809 810 # Check the actual hashes against the `ls-files -u` output too 811 tail -n +2 out | sed -e s/side1/HEAD/ >actual && 812 test_cmp conflicted-file-info actual 813' 814 815test_expect_success 'NUL terminated conflicted file "lines"' ' 816 git checkout -b tweak1 side1 && 817 test_write_lines zero 1 2 3 4 5 6 >numbers && 818 git add numbers && 819 git mv numbers "Αυτά μου φαίνονται κινέζικα" && 820 git commit -m "Renamed numbers" && 821 822 test_expect_code 1 git merge-tree --write-tree -z tweak1 side2 >out && 823 echo >>out && 824 anonymize_hash out >actual && 825 826 # Expected results: 827 # "greeting" should merge with conflicts 828 # "whatever" has *both* a modify/delete and a file/directory conflict 829 # "Αυτά μου φαίνονται κινέζικα" should have a conflict 830 echo HASH | lf_to_nul >expect && 831 832 q_to_tab <<-EOF | lf_to_nul >>expect && 833 100644 HASH 1Qgreeting 834 100644 HASH 2Qgreeting 835 100644 HASH 3Qgreeting 836 100644 HASH 1Qwhatever~tweak1 837 100644 HASH 2Qwhatever~tweak1 838 100644 HASH 1QΑυτά μου φαίνονται κινέζικα 839 100644 HASH 2QΑυτά μου φαίνονται κινέζικα 840 100644 HASH 3QΑυτά μου φαίνονται κινέζικα 841 842 EOF 843 844 q_to_nul <<-EOF >>expect && 845 1QgreetingQAuto-mergingQAuto-merging greeting 846 Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting 847 Q2Qwhatever~tweak1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from tweak1; moving it to whatever~tweak1 instead. 848 Q1Qwhatever~tweak1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~tweak1 deleted in side2 and modified in tweak1. Version tweak1 of whatever~tweak1 left in tree. 849 Q1QΑυτά μου φαίνονται κινέζικαQAuto-mergingQAuto-merging Αυτά μου φαίνονται κινέζικα 850 Q1QΑυτά μου φαίνονται κινέζικαQCONFLICT (contents)QCONFLICT (content): Merge conflict in Αυτά μου φαίνονται κινέζικα 851 Q 852 EOF 853 854 test_cmp expect actual 855' 856 857test_expect_success 'error out by default for unrelated histories' ' 858 test_expect_code 128 git merge-tree --write-tree side1 unrelated 2>error && 859 860 grep "refusing to merge unrelated histories" error 861' 862 863test_expect_success 'can override merge of unrelated histories' ' 864 git merge-tree --write-tree --allow-unrelated-histories side1 unrelated >tree && 865 TREE=$(cat tree) && 866 867 git rev-parse side1:numbers side1:greeting side1:whatever unrelated:something-else >expect && 868 git rev-parse $TREE:numbers $TREE:greeting $TREE:whatever $TREE:something-else >actual && 869 870 test_cmp expect actual 871' 872 873test_expect_success SANITY 'merge-ort fails gracefully in a read-only repository' ' 874 git init --bare read-only && 875 git push read-only side1 side2 side3 && 876 test_when_finished "chmod -R u+w read-only" && 877 chmod -R a-w read-only && 878 test_must_fail git -C read-only merge-tree side1 side3 && 879 test_must_fail git -C read-only merge-tree side1 side2 880' 881 882test_expect_success '--stdin with both a successful and a conflicted merge' ' 883 printf "side1 side3\nside1 side2" | git merge-tree --stdin >actual && 884 885 git checkout side1^0 && 886 git merge side3 && 887 888 printf "1\0" >expect && 889 git rev-parse HEAD^{tree} | lf_to_nul >>expect && 890 printf "\0" >>expect && 891 892 git checkout side1^0 && 893 test_must_fail git merge side2 && 894 sed s/HEAD/side1/ greeting >tmp && 895 mv tmp greeting && 896 git add -u && 897 git mv whatever~HEAD whatever~side1 && 898 899 printf "0\0" >>expect && 900 git write-tree | lf_to_nul >>expect && 901 902 cat <<-EOF | q_to_tab | lf_to_nul >>expect && 903 100644 $(git rev-parse side1~1:greeting) 1Qgreeting 904 100644 $(git rev-parse side1:greeting) 2Qgreeting 905 100644 $(git rev-parse side2:greeting) 3Qgreeting 906 100644 $(git rev-parse side1~1:whatever) 1Qwhatever~side1 907 100644 $(git rev-parse side1:whatever) 2Qwhatever~side1 908 EOF 909 910 q_to_nul <<-EOF >>expect && 911 Q1QgreetingQAuto-mergingQAuto-merging greeting 912 Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting 913 Q1QnumbersQAuto-mergingQAuto-merging numbers 914 Q2Qwhatever~side1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead. 915 Q1Qwhatever~side1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1. Version side1 of whatever~side1 left in tree. 916 EOF 917 918 printf "\0\0" >>expect && 919 920 test_cmp expect actual 921' 922 923 924test_expect_success '--merge-base is incompatible with --stdin' ' 925 test_must_fail git merge-tree --merge-base=side1 --stdin 2>expect && 926 927 grep "^fatal: .*merge-base.*stdin.* cannot be used together" expect 928' 929 930# specify merge-base as parent of branch2 931# git merge-tree --write-tree --merge-base=c2 c1 c3 932# Commit c1: add file1 933# Commit c2: add file2 after c1 934# Commit c3: add file3 after c2 935# Expected: add file3, and file2 does NOT appear 936 937test_expect_success 'specify merge-base as parent of branch2' ' 938 # Setup 939 test_when_finished "rm -rf base-b2-p" && 940 git init base-b2-p && 941 test_commit -C base-b2-p c1 file1 && 942 test_commit -C base-b2-p c2 file2 && 943 test_commit -C base-b2-p c3 file3 && 944 945 # Testing 946 TREE_OID=$(git -C base-b2-p merge-tree --write-tree --merge-base=c2 c1 c3) && 947 948 q_to_tab <<-EOF >expect && 949 100644 blob $(git -C base-b2-p rev-parse c1:file1)Qfile1 950 100644 blob $(git -C base-b2-p rev-parse c3:file3)Qfile3 951 EOF 952 953 git -C base-b2-p ls-tree $TREE_OID >actual && 954 test_cmp expect actual 955' 956 957# Since the earlier tests have verified that individual merge-tree calls 958# are doing the right thing, this test case is only used to verify that 959# we can also trigger merges via --stdin, and that when we do we get 960# the same answer as running a bunch of separate merges. 961 962test_expect_success 'check the input format when --stdin is passed' ' 963 test_when_finished "rm -rf repo" && 964 git init repo && 965 test_commit -C repo c1 && 966 test_commit -C repo c2 && 967 test_commit -C repo c3 && 968 printf "c1 c3\nc2 -- c1 c3\nc2 c3" | git -C repo merge-tree --stdin >actual && 969 970 printf "1\0" >expect && 971 git -C repo merge-tree --write-tree -z c1 c3 >>expect && 972 printf "\0" >>expect && 973 974 printf "1\0" >>expect && 975 git -C repo merge-tree --write-tree -z --merge-base=c2 c1 c3 >>expect && 976 printf "\0" >>expect && 977 978 printf "1\0" >>expect && 979 git -C repo merge-tree --write-tree -z c2 c3 >>expect && 980 printf "\0" >>expect && 981 982 test_cmp expect actual 983' 984 985test_expect_success '--merge-base with tree OIDs' ' 986 git merge-tree --merge-base=side1^ side1 side3 >with-commits && 987 git merge-tree --merge-base=side1^^{tree} side1^{tree} side3^{tree} >with-trees && 988 test_cmp with-commits with-trees 989' 990 991test_expect_success 'error out on missing tree objects' ' 992 git init --bare missing-tree.git && 993 git rev-list side3 >list && 994 git rev-parse side3^: >>list && 995 git pack-objects missing-tree.git/objects/pack/side3-tree-is-missing <list && 996 side3=$(git rev-parse side3) && 997 test_must_fail git --git-dir=missing-tree.git merge-tree $side3^ $side3 >actual 2>err && 998 test_grep "Could not read $(git rev-parse $side3:)" err && 999 test_must_be_empty actual 1000' 1001 1002test_expect_success 'error out on missing blob objects' ' 1003 echo 1 | git hash-object -w --stdin >blob1 && 1004 echo 2 | git hash-object -w --stdin >blob2 && 1005 echo 3 | git hash-object -w --stdin >blob3 && 1006 printf "100644 blob $(cat blob1)\tblob\n" | git mktree >tree1 && 1007 printf "100644 blob $(cat blob2)\tblob\n" | git mktree >tree2 && 1008 printf "100644 blob $(cat blob3)\tblob\n" | git mktree >tree3 && 1009 git init --bare missing-blob.git && 1010 cat blob1 blob3 tree1 tree2 tree3 | 1011 git pack-objects missing-blob.git/objects/pack/side1-whatever-is-missing && 1012 test_must_fail git --git-dir=missing-blob.git >actual 2>err \ 1013 merge-tree --merge-base=$(cat tree1) $(cat tree2) $(cat tree3) && 1014 test_grep "unable to read blob object $(cat blob2)" err && 1015 test_must_be_empty actual 1016' 1017 1018test_expect_success 'error out on missing commits as well' ' 1019 git init --bare missing-commit.git && 1020 git rev-list --objects side1 side3 >list-including-initial && 1021 grep -v ^$(git rev-parse side1^) <list-including-initial >list && 1022 git pack-objects missing-commit.git/objects/pack/missing-initial <list && 1023 side1=$(git rev-parse side1) && 1024 side3=$(git rev-parse side3) && 1025 test_must_fail git --git-dir=missing-commit.git \ 1026 merge-tree --allow-unrelated-histories $side1 $side3 >actual && 1027 test_must_be_empty actual 1028' 1029 1030test_done