t / t6042-merge-rename-corner-cases.shon commit untracked-cache: be defensive about missing NULs in index (c6909f9)
   1#!/bin/sh
   2
   3test_description="recursive merge corner cases w/ renames but not criss-crosses"
   4# t6036 has corner cases that involve both criss-cross merges and renames
   5
   6. ./test-lib.sh
   7
   8test_expect_success 'setup rename/delete + untracked file' '
   9        test_create_repo rename-delete-untracked &&
  10        (
  11                cd rename-delete-untracked &&
  12
  13                echo "A pretty inscription" >ring &&
  14                git add ring &&
  15                test_tick &&
  16                git commit -m beginning &&
  17
  18                git branch people &&
  19                git checkout -b rename-the-ring &&
  20                git mv ring one-ring-to-rule-them-all &&
  21                test_tick &&
  22                git commit -m fullname &&
  23
  24                git checkout people &&
  25                git rm ring &&
  26                echo gollum >owner &&
  27                git add owner &&
  28                test_tick &&
  29                git commit -m track-people-instead-of-objects &&
  30                echo "Myyy PRECIOUSSS" >ring
  31        )
  32'
  33
  34test_expect_success "Does git preserve Gollum's precious artifact?" '
  35        (
  36                cd rename-delete-untracked &&
  37
  38                test_must_fail git merge -s recursive rename-the-ring &&
  39
  40                # Make sure git did not delete an untracked file
  41                test_path_is_file ring
  42        )
  43'
  44
  45# Testcase setup for rename/modify/add-source:
  46#   Commit A: new file: a
  47#   Commit B: modify a slightly
  48#   Commit C: rename a->b, add completely different a
  49#
  50# We should be able to merge B & C cleanly
  51
  52test_expect_success 'setup rename/modify/add-source conflict' '
  53        test_create_repo rename-modify-add-source &&
  54        (
  55                cd rename-modify-add-source &&
  56
  57                printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
  58                git add a &&
  59                git commit -m A &&
  60                git tag A &&
  61
  62                git checkout -b B A &&
  63                echo 8 >>a &&
  64                git add a &&
  65                git commit -m B &&
  66
  67                git checkout -b C A &&
  68                git mv a b &&
  69                echo something completely different >a &&
  70                git add a &&
  71                git commit -m C
  72        )
  73'
  74
  75test_expect_failure 'rename/modify/add-source conflict resolvable' '
  76        (
  77                cd rename-modify-add-source &&
  78
  79                git checkout B^0 &&
  80
  81                git merge -s recursive C^0 &&
  82
  83                git rev-parse >expect \
  84                        B:a   C:a     &&
  85                git rev-parse >actual \
  86                        b     c       &&
  87                test_cmp expect actual
  88        )
  89'
  90
  91test_expect_success 'setup resolvable conflict missed if rename missed' '
  92        test_create_repo break-detection-1 &&
  93        (
  94                cd break-detection-1 &&
  95
  96                printf "1\n2\n3\n4\n5\n" >a &&
  97                echo foo >b &&
  98                git add a b &&
  99                git commit -m A &&
 100                git tag A &&
 101
 102                git checkout -b B A &&
 103                git mv a c &&
 104                echo "Completely different content" >a &&
 105                git add a &&
 106                git commit -m B &&
 107
 108                git checkout -b C A &&
 109                echo 6 >>a &&
 110                git add a &&
 111                git commit -m C
 112        )
 113'
 114
 115test_expect_failure 'conflict caused if rename not detected' '
 116        (
 117                cd break-detection-1 &&
 118
 119                git checkout -q C^0 &&
 120                git merge -s recursive B^0 &&
 121
 122                git ls-files -s >out &&
 123                test_line_count = 3 out &&
 124                git ls-files -u >out &&
 125                test_line_count = 0 out &&
 126                git ls-files -o >out &&
 127                test_line_count = 1 out &&
 128
 129                test_line_count = 6 c &&
 130                git rev-parse >expect \
 131                        B:a   A:b     &&
 132                git rev-parse >actual \
 133                        :0:a  :0:b    &&
 134                test_cmp expect actual
 135        )
 136'
 137
 138test_expect_success 'setup conflict resolved wrong if rename missed' '
 139        test_create_repo break-detection-2 &&
 140        (
 141                cd break-detection-2 &&
 142
 143                printf "1\n2\n3\n4\n5\n" >a &&
 144                echo foo >b &&
 145                git add a b &&
 146                git commit -m A &&
 147                git tag A &&
 148
 149                git checkout -b D A &&
 150                echo 7 >>a &&
 151                git add a &&
 152                git mv a c &&
 153                echo "Completely different content" >a &&
 154                git add a &&
 155                git commit -m D &&
 156
 157                git checkout -b E A &&
 158                git rm a &&
 159                echo "Completely different content" >>a &&
 160                git add a &&
 161                git commit -m E
 162        )
 163'
 164
 165test_expect_failure 'missed conflict if rename not detected' '
 166        (
 167                cd break-detection-2 &&
 168
 169                git checkout -q E^0 &&
 170                test_must_fail git merge -s recursive D^0
 171        )
 172'
 173
 174# Tests for undetected rename/add-source causing a file to erroneously be
 175# deleted (and for mishandled rename/rename(1to1) causing the same issue).
 176#
 177# This test uses a rename/rename(1to1)+add-source conflict (1to1 means the
 178# same file is renamed on both sides to the same thing; it should trigger
 179# the 1to2 logic, which it would do if the add-source didn't cause issues
 180# for git's rename detection):
 181#   Commit A: new file: a
 182#   Commit B: rename a->b
 183#   Commit C: rename a->b, add unrelated a
 184
 185test_expect_success 'setup undetected rename/add-source causes data loss' '
 186        test_create_repo break-detection-3 &&
 187        (
 188                cd break-detection-3 &&
 189
 190                printf "1\n2\n3\n4\n5\n" >a &&
 191                git add a &&
 192                git commit -m A &&
 193                git tag A &&
 194
 195                git checkout -b B A &&
 196                git mv a b &&
 197                git commit -m B &&
 198
 199                git checkout -b C A &&
 200                git mv a b &&
 201                echo foobar >a &&
 202                git add a &&
 203                git commit -m C
 204        )
 205'
 206
 207test_expect_failure 'detect rename/add-source and preserve all data' '
 208        (
 209                cd break-detection-3 &&
 210
 211                git checkout B^0 &&
 212
 213                git merge -s recursive C^0 &&
 214
 215                git ls-files -s >out &&
 216                test_line_count = 2 out &&
 217                git ls-files -u >out &&
 218                test_line_count = 2 out &&
 219                git ls-files -o >out &&
 220                test_line_count = 1 out &&
 221
 222                test_path_is_file a &&
 223                test_path_is_file b &&
 224
 225                git rev-parse >expect \
 226                        A:a   C:a     &&
 227                git rev-parse >actual \
 228                        :0:b  :0:a    &&
 229                test_cmp expect actual
 230        )
 231'
 232
 233test_expect_failure 'detect rename/add-source and preserve all data, merge other way' '
 234        (
 235                cd break-detection-3 &&
 236
 237                git checkout C^0 &&
 238
 239                git merge -s recursive B^0 &&
 240
 241                git ls-files -s >out &&
 242                test_line_count = 2 out &&
 243                git ls-files -u >out &&
 244                test_line_count = 2 out &&
 245                git ls-files -o >out &&
 246                test_line_count = 1 out &&
 247
 248                test_path_is_file a &&
 249                test_path_is_file b &&
 250
 251                git rev-parse >expect \
 252                        A:a   C:a     &&
 253                git rev-parse >actual \
 254                        :0:b  :0:a    &&
 255                test_cmp expect actual
 256        )
 257'
 258
 259test_expect_success 'setup content merge + rename/directory conflict' '
 260        test_create_repo rename-directory-1 &&
 261        (
 262                cd rename-directory-1 &&
 263
 264                printf "1\n2\n3\n4\n5\n6\n" >file &&
 265                git add file &&
 266                test_tick &&
 267                git commit -m base &&
 268                git tag base &&
 269
 270                git checkout -b right &&
 271                echo 7 >>file &&
 272                mkdir newfile &&
 273                echo junk >newfile/realfile &&
 274                git add file newfile/realfile &&
 275                test_tick &&
 276                git commit -m right &&
 277
 278                git checkout -b left-conflict base &&
 279                echo 8 >>file &&
 280                git add file &&
 281                git mv file newfile &&
 282                test_tick &&
 283                git commit -m left &&
 284
 285                git checkout -b left-clean base &&
 286                echo 0 >newfile &&
 287                cat file >>newfile &&
 288                git add newfile &&
 289                git rm file &&
 290                test_tick &&
 291                git commit -m left
 292        )
 293'
 294
 295test_expect_success 'rename/directory conflict + clean content merge' '
 296        (
 297                cd rename-directory-1 &&
 298
 299                git checkout left-clean^0 &&
 300
 301                test_must_fail git merge -s recursive right^0 &&
 302
 303                git ls-files -s >out &&
 304                test_line_count = 2 out &&
 305                git ls-files -u >out &&
 306                test_line_count = 1 out &&
 307                git ls-files -o >out &&
 308                test_line_count = 2 out &&
 309
 310                echo 0 >expect &&
 311                git cat-file -p base:file >>expect &&
 312                echo 7 >>expect &&
 313                test_cmp expect newfile~HEAD &&
 314
 315                test $(git rev-parse :2:newfile) = $(git hash-object expect) &&
 316
 317                test_path_is_file newfile/realfile &&
 318                test_path_is_file newfile~HEAD
 319        )
 320'
 321
 322test_expect_success 'rename/directory conflict + content merge conflict' '
 323        (
 324                cd rename-directory-1 &&
 325
 326                git reset --hard &&
 327                git clean -fdqx &&
 328
 329                git checkout left-conflict^0 &&
 330
 331                test_must_fail git merge -s recursive right^0 &&
 332
 333                git ls-files -s >out &&
 334                test_line_count = 4 out &&
 335                git ls-files -u >out &&
 336                test_line_count = 3 out &&
 337                git ls-files -o >out &&
 338                test_line_count = 2 out &&
 339
 340                git cat-file -p left-conflict:newfile >left &&
 341                git cat-file -p base:file    >base &&
 342                git cat-file -p right:file   >right &&
 343                test_must_fail git merge-file \
 344                        -L "HEAD:newfile" \
 345                        -L "" \
 346                        -L "right^0:file" \
 347                        left base right &&
 348                test_cmp left newfile~HEAD &&
 349
 350                git rev-parse >expect                                 \
 351                        base:file   left-conflict:newfile  right:file &&
 352                git rev-parse >actual                                 \
 353                        :1:newfile  :2:newfile             :3:newfile &&
 354                test_cmp expect actual &&
 355
 356                test_path_is_file newfile/realfile &&
 357                test_path_is_file newfile~HEAD
 358        )
 359'
 360
 361test_expect_success 'setup content merge + rename/directory conflict w/ disappearing dir' '
 362        test_create_repo rename-directory-2 &&
 363        (
 364                cd rename-directory-2 &&
 365
 366                mkdir sub &&
 367                printf "1\n2\n3\n4\n5\n6\n" >sub/file &&
 368                git add sub/file &&
 369                test_tick &&
 370                git commit -m base &&
 371                git tag base &&
 372
 373                git checkout -b right &&
 374                echo 7 >>sub/file &&
 375                git add sub/file &&
 376                test_tick &&
 377                git commit -m right &&
 378
 379                git checkout -b left base &&
 380                echo 0 >newfile &&
 381                cat sub/file >>newfile &&
 382                git rm sub/file &&
 383                mv newfile sub &&
 384                git add sub &&
 385                test_tick &&
 386                git commit -m left
 387        )
 388'
 389
 390test_expect_success 'disappearing dir in rename/directory conflict handled' '
 391        (
 392                cd rename-directory-2 &&
 393
 394                git checkout left^0 &&
 395
 396                git merge -s recursive right^0 &&
 397
 398                git ls-files -s >out &&
 399                test_line_count = 1 out &&
 400                git ls-files -u >out &&
 401                test_line_count = 0 out &&
 402                git ls-files -o >out &&
 403                test_line_count = 1 out &&
 404
 405                echo 0 >expect &&
 406                git cat-file -p base:sub/file >>expect &&
 407                echo 7 >>expect &&
 408                test_cmp expect sub &&
 409
 410                test_path_is_file sub
 411        )
 412'
 413
 414# Test for all kinds of things that can go wrong with rename/rename (2to1):
 415#   Commit A: new files: a & b
 416#   Commit B: rename a->c, modify b
 417#   Commit C: rename b->c, modify a
 418#
 419# Merging of B & C should NOT be clean.  Questions:
 420#   * Both a & b should be removed by the merge; are they?
 421#   * The two c's should contain modifications to a & b; do they?
 422#   * The index should contain two files, both for c; does it?
 423#   * The working copy should have two files, both of form c~<unique>; does it?
 424#   * Nothing else should be present.  Is anything?
 425
 426test_expect_success 'setup rename/rename (2to1) + modify/modify' '
 427        test_create_repo rename-rename-2to1 &&
 428        (
 429                cd rename-rename-2to1 &&
 430
 431                printf "1\n2\n3\n4\n5\n" >a &&
 432                printf "5\n4\n3\n2\n1\n" >b &&
 433                git add a b &&
 434                git commit -m A &&
 435                git tag A &&
 436
 437                git checkout -b B A &&
 438                git mv a c &&
 439                echo 0 >>b &&
 440                git add b &&
 441                git commit -m B &&
 442
 443                git checkout -b C A &&
 444                git mv b c &&
 445                echo 6 >>a &&
 446                git add a &&
 447                git commit -m C
 448        )
 449'
 450
 451test_expect_success 'handle rename/rename (2to1) conflict correctly' '
 452        (
 453                cd rename-rename-2to1 &&
 454
 455                git checkout B^0 &&
 456
 457                test_must_fail git merge -s recursive C^0 >out &&
 458                test_i18ngrep "CONFLICT (rename/rename)" out &&
 459
 460                git ls-files -s >out &&
 461                test_line_count = 2 out &&
 462                git ls-files -u >out &&
 463                test_line_count = 2 out &&
 464                git ls-files -u c >out &&
 465                test_line_count = 2 out &&
 466                git ls-files -o >out &&
 467                test_line_count = 1 out &&
 468
 469                test_path_is_missing a &&
 470                test_path_is_missing b &&
 471
 472                git rev-parse >expect  \
 473                        C:a     B:b    &&
 474                git rev-parse >actual  \
 475                        :2:c    :3:c   &&
 476                test_cmp expect actual &&
 477
 478                # Test that the two-way merge in new_a is as expected
 479                git cat-file -p :2:c >>ours &&
 480                git cat-file -p :3:c >>theirs &&
 481                >empty &&
 482                test_must_fail git merge-file \
 483                        -L "HEAD" \
 484                        -L "" \
 485                        -L "C^0" \
 486                        ours empty theirs &&
 487                git hash-object c >actual &&
 488                git hash-object ours >expect &&
 489                test_cmp expect actual
 490        )
 491'
 492
 493# Testcase setup for simple rename/rename (1to2) conflict:
 494#   Commit A: new file: a
 495#   Commit B: rename a->b
 496#   Commit C: rename a->c
 497test_expect_success 'setup simple rename/rename (1to2) conflict' '
 498        test_create_repo rename-rename-1to2 &&
 499        (
 500                cd rename-rename-1to2 &&
 501
 502                echo stuff >a &&
 503                git add a &&
 504                test_tick &&
 505                git commit -m A &&
 506                git tag A &&
 507
 508                git checkout -b B A &&
 509                git mv a b &&
 510                test_tick &&
 511                git commit -m B &&
 512
 513                git checkout -b C A &&
 514                git mv a c &&
 515                test_tick &&
 516                git commit -m C
 517        )
 518'
 519
 520test_expect_success 'merge has correct working tree contents' '
 521        (
 522                cd rename-rename-1to2 &&
 523
 524                git checkout C^0 &&
 525
 526                test_must_fail git merge -s recursive B^0 &&
 527
 528                git ls-files -s >out &&
 529                test_line_count = 3 out &&
 530                git ls-files -u >out &&
 531                test_line_count = 3 out &&
 532                git ls-files -o >out &&
 533                test_line_count = 1 out &&
 534
 535                test_path_is_missing a &&
 536                git rev-parse >expect   \
 537                        A:a   A:a   A:a \
 538                        A:a   A:a       &&
 539                git rev-parse >actual    \
 540                        :1:a  :3:b  :2:c &&
 541                git hash-object >>actual \
 542                        b     c          &&
 543                test_cmp expect actual
 544        )
 545'
 546
 547# Testcase setup for rename/rename(1to2)/add-source conflict:
 548#   Commit A: new file: a
 549#   Commit B: rename a->b
 550#   Commit C: rename a->c, add completely different a
 551#
 552# Merging of B & C should NOT be clean; there's a rename/rename conflict
 553
 554test_expect_success 'setup rename/rename(1to2)/add-source conflict' '
 555        test_create_repo rename-rename-1to2-add-source-1 &&
 556        (
 557                cd rename-rename-1to2-add-source-1 &&
 558
 559                printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
 560                git add a &&
 561                git commit -m A &&
 562                git tag A &&
 563
 564                git checkout -b B A &&
 565                git mv a b &&
 566                git commit -m B &&
 567
 568                git checkout -b C A &&
 569                git mv a c &&
 570                echo something completely different >a &&
 571                git add a &&
 572                git commit -m C
 573        )
 574'
 575
 576test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge' '
 577        (
 578                cd rename-rename-1to2-add-source-1 &&
 579
 580                git checkout B^0 &&
 581
 582                test_must_fail git merge -s recursive C^0 &&
 583
 584                git ls-files -s >out &&
 585                test_line_count = 4 out &&
 586                git ls-files -o >out &&
 587                test_line_count = 1 out &&
 588
 589                git rev-parse >expect         \
 590                        C:a   A:a   B:b   C:C &&
 591                git rev-parse >actual          \
 592                        :3:a  :1:a  :2:b  :3:c &&
 593                test_cmp expect actual &&
 594
 595                test_path_is_file a &&
 596                test_path_is_file b &&
 597                test_path_is_file c
 598        )
 599'
 600
 601test_expect_success 'setup rename/rename(1to2)/add-source resolvable conflict' '
 602        test_create_repo rename-rename-1to2-add-source-2 &&
 603        (
 604                cd rename-rename-1to2-add-source-2 &&
 605
 606                >a &&
 607                git add a &&
 608                test_tick &&
 609                git commit -m base &&
 610                git tag A &&
 611
 612                git checkout -b B A &&
 613                git mv a b &&
 614                test_tick &&
 615                git commit -m one &&
 616
 617                git checkout -b C A &&
 618                git mv a b &&
 619                echo important-info >a &&
 620                git add a &&
 621                test_tick &&
 622                git commit -m two
 623        )
 624'
 625
 626test_expect_failure 'rename/rename/add-source still tracks new a file' '
 627        (
 628                cd rename-rename-1to2-add-source-2 &&
 629
 630                git checkout C^0 &&
 631                git merge -s recursive B^0 &&
 632
 633                git ls-files -s >out &&
 634                test_line_count = 2 out &&
 635                git ls-files -o >out &&
 636                test_line_count = 1 out &&
 637
 638                git rev-parse >expect \
 639                        C:a   A:a     &&
 640                git rev-parse >actual \
 641                        :0:a  :0:b    &&
 642                test_cmp expect actual
 643        )
 644'
 645
 646test_expect_success 'setup rename/rename(1to2)/add-dest conflict' '
 647        test_create_repo rename-rename-1to2-add-dest &&
 648        (
 649                cd rename-rename-1to2-add-dest &&
 650
 651                echo stuff >a &&
 652                git add a &&
 653                test_tick &&
 654                git commit -m base &&
 655                git tag A &&
 656
 657                git checkout -b B A &&
 658                git mv a b &&
 659                echo precious-data >c &&
 660                git add c &&
 661                test_tick &&
 662                git commit -m one &&
 663
 664                git checkout -b C A &&
 665                git mv a c &&
 666                echo important-info >b &&
 667                git add b &&
 668                test_tick &&
 669                git commit -m two
 670        )
 671'
 672
 673test_expect_success 'rename/rename/add-dest merge still knows about conflicting file versions' '
 674        (
 675                cd rename-rename-1to2-add-dest &&
 676
 677                git checkout C^0 &&
 678                test_must_fail git merge -s recursive B^0 &&
 679
 680                git ls-files -s >out &&
 681                test_line_count = 5 out &&
 682                git ls-files -u b >out &&
 683                test_line_count = 2 out &&
 684                git ls-files -u c >out &&
 685                test_line_count = 2 out &&
 686                git ls-files -o >out &&
 687                test_line_count = 1 out &&
 688
 689                git rev-parse >expect               \
 690                        A:a   C:b   B:b   C:c   B:c &&
 691                git rev-parse >actual                \
 692                        :1:a  :2:b  :3:b  :2:c  :3:c &&
 693                test_cmp expect actual &&
 694
 695                # Record some contents for re-doing merges
 696                git cat-file -p A:a >stuff &&
 697                git cat-file -p C:b >important_info &&
 698                git cat-file -p B:c >precious_data &&
 699                >empty &&
 700
 701                # Test the merge in b
 702                test_must_fail git merge-file \
 703                        -L "HEAD" \
 704                        -L "" \
 705                        -L "B^0" \
 706                        important_info empty stuff &&
 707                test_cmp important_info b &&
 708
 709                # Test the merge in c
 710                test_must_fail git merge-file \
 711                        -L "HEAD" \
 712                        -L "" \
 713                        -L "B^0" \
 714                        stuff empty precious_data &&
 715                test_cmp stuff c
 716        )
 717'
 718
 719# Testcase rad, rename/add/delete
 720#   Commit O: foo
 721#   Commit A: rm foo, add different bar
 722#   Commit B: rename foo->bar
 723#   Expected: CONFLICT (rename/add/delete), two-way merged bar
 724
 725test_expect_success 'rad-setup: rename/add/delete conflict' '
 726        test_create_repo rad &&
 727        (
 728                cd rad &&
 729                echo "original file" >foo &&
 730                git add foo &&
 731                git commit -m "original" &&
 732
 733                git branch O &&
 734                git branch A &&
 735                git branch B &&
 736
 737                git checkout A &&
 738                git rm foo &&
 739                echo "different file" >bar &&
 740                git add bar &&
 741                git commit -m "Remove foo, add bar" &&
 742
 743                git checkout B &&
 744                git mv foo bar &&
 745                git commit -m "rename foo to bar"
 746        )
 747'
 748
 749test_expect_failure 'rad-check: rename/add/delete conflict' '
 750        (
 751                cd rad &&
 752
 753                git checkout B^0 &&
 754                test_must_fail git merge -s recursive A^0 >out 2>err &&
 755
 756                # Not sure whether the output should contain just one
 757                # "CONFLICT (rename/add/delete)" line, or if it should break
 758                # it into a pair of "CONFLICT (rename/delete)" and
 759                # "CONFLICT (rename/add)"; allow for either.
 760                test_i18ngrep "CONFLICT (rename.*add)" out &&
 761                test_i18ngrep "CONFLICT (rename.*delete)" out &&
 762                test_must_be_empty err &&
 763
 764                git ls-files -s >file_count &&
 765                test_line_count = 2 file_count &&
 766                git ls-files -u >file_count &&
 767                test_line_count = 2 file_count &&
 768                git ls-files -o >file_count &&
 769                test_line_count = 2 file_count &&
 770
 771                git rev-parse >actual \
 772                        :2:bar :3:bar &&
 773                git rev-parse >expect \
 774                        B:bar  A:bar  &&
 775
 776                test_cmp file_is_missing foo &&
 777                # bar should have two-way merged contents of the different
 778                # versions of bar; check that content from both sides is
 779                # present.
 780                grep original bar &&
 781                grep different bar
 782        )
 783'
 784
 785# Testcase rrdd, rename/rename(2to1)/delete/delete
 786#   Commit O: foo, bar
 787#   Commit A: rename foo->baz, rm bar
 788#   Commit B: rename bar->baz, rm foo
 789#   Expected: CONFLICT (rename/rename/delete/delete), two-way merged baz
 790
 791test_expect_success 'rrdd-setup: rename/rename(2to1)/delete/delete conflict' '
 792        test_create_repo rrdd &&
 793        (
 794                cd rrdd &&
 795                echo foo >foo &&
 796                echo bar >bar &&
 797                git add foo bar &&
 798                git commit -m O &&
 799
 800                git branch O &&
 801                git branch A &&
 802                git branch B &&
 803
 804                git checkout A &&
 805                git mv foo baz &&
 806                git rm bar &&
 807                git commit -m "Rename foo, remove bar" &&
 808
 809                git checkout B &&
 810                git mv bar baz &&
 811                git rm foo &&
 812                git commit -m "Rename bar, remove foo"
 813        )
 814'
 815
 816test_expect_failure 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '
 817        (
 818                cd rrdd &&
 819
 820                git checkout A^0 &&
 821                test_must_fail git merge -s recursive B^0 >out 2>err &&
 822
 823                # Not sure whether the output should contain just one
 824                # "CONFLICT (rename/rename/delete/delete)" line, or if it
 825                # should break it into three: "CONFLICT (rename/rename)" and
 826                # two "CONFLICT (rename/delete)" lines; allow for either.
 827                test_i18ngrep "CONFLICT (rename/rename)" out &&
 828                test_i18ngrep "CONFLICT (rename.*delete)" out &&
 829                test_must_be_empty err &&
 830
 831                git ls-files -s >file_count &&
 832                test_line_count = 2 file_count &&
 833                git ls-files -u >file_count &&
 834                test_line_count = 2 file_count &&
 835                git ls-files -o >file_count &&
 836                test_line_count = 2 file_count &&
 837
 838                git rev-parse >actual \
 839                        :2:baz :3:baz &&
 840                git rev-parse >expect \
 841                        O:foo  O:bar  &&
 842
 843                test_cmp file_is_missing foo &&
 844                test_cmp file_is_missing bar &&
 845                # baz should have two-way merged contents of the original
 846                # contents of foo and bar; check that content from both sides
 847                # is present.
 848                grep foo baz &&
 849                grep bar baz
 850        )
 851'
 852
 853# Testcase mod6, chains of rename/rename(1to2) and rename/rename(2to1)
 854#   Commit O: one,      three,       five
 855#   Commit A: one->two, three->four, five->six
 856#   Commit B: one->six, three->two,  five->four
 857#   Expected: six CONFLICT(rename/rename) messages, each path in two of the
 858#             multi-way merged contents found in two, four, six
 859
 860test_expect_success 'mod6-setup: chains of rename/rename(1to2) and rename/rename(2to1)' '
 861        test_create_repo mod6 &&
 862        (
 863                cd mod6 &&
 864                test_seq 11 19 >one &&
 865                test_seq 31 39 >three &&
 866                test_seq 51 59 >five &&
 867                git add . &&
 868                test_tick &&
 869                git commit -m "O" &&
 870
 871                git branch O &&
 872                git branch A &&
 873                git branch B &&
 874
 875                git checkout A &&
 876                test_seq 10 19 >one &&
 877                echo 40        >>three &&
 878                git add one three &&
 879                git mv  one   two  &&
 880                git mv  three four &&
 881                git mv  five  six  &&
 882                test_tick &&
 883                git commit -m "A" &&
 884
 885                git checkout B &&
 886                echo 20    >>one       &&
 887                echo forty >>three     &&
 888                echo 60    >>five      &&
 889                git add one three five &&
 890                git mv  one   six  &&
 891                git mv  three two  &&
 892                git mv  five  four &&
 893                test_tick &&
 894                git commit -m "B"
 895        )
 896'
 897
 898test_expect_failure 'mod6-check: chains of rename/rename(1to2) and rename/rename(2to1)' '
 899        (
 900                cd mod6 &&
 901
 902                git checkout A^0 &&
 903
 904                test_must_fail git merge -s recursive B^0 >out 2>err &&
 905
 906                test_i18ngrep "CONFLICT (rename/rename)" out &&
 907                test_must_be_empty err &&
 908
 909                git ls-files -s >file_count &&
 910                test_line_count = 6 file_count &&
 911                git ls-files -u >file_count &&
 912                test_line_count = 6 file_count &&
 913                git ls-files -o >file_count &&
 914                test_line_count = 3 file_count &&
 915
 916                test_seq 10 20 >merged-one &&
 917                test_seq 51 60 >merged-five &&
 918                # Determine what the merge of three would give us.
 919                test_seq 30 40 >three-side-A &&
 920                test_seq 31 39 >three-side-B &&
 921                echo forty >three-side-B &&
 922                >empty &&
 923                test_must_fail git merge-file \
 924                        -L "HEAD" \
 925                        -L "" \
 926                        -L "B^0" \
 927                        three-side-A empty three-side-B &&
 928                sed -e "s/^\([<=>]\)/\1\1\1/" three-side-A >merged-three &&
 929
 930                # Verify the index is as expected
 931                git rev-parse >actual         \
 932                        :2:two       :3:two   \
 933                        :2:four      :3:four  \
 934                        :2:six       :3:six   &&
 935                git hash-object >expect           \
 936                        merged-one   merged-three \
 937                        merged-three merged-five  \
 938                        merged-five  merged-one   &&
 939                test_cmp expect actual &&
 940
 941                git cat-file -p :2:two >expect &&
 942                git cat-file -p :3:two >other &&
 943                test_must_fail git merge-file    \
 944                        -L "HEAD"  -L ""  -L "B^0" \
 945                        expect     empty  other &&
 946                test_cmp expect two &&
 947
 948                git cat-file -p :2:four >expect &&
 949                git cat-file -p :3:four >other &&
 950                test_must_fail git merge-file    \
 951                        -L "HEAD"  -L ""  -L "B^0" \
 952                        expect     empty  other &&
 953                test_cmp expect four &&
 954
 955                git cat-file -p :2:six >expect &&
 956                git cat-file -p :3:six >other &&
 957                test_must_fail git merge-file    \
 958                        -L "HEAD"  -L ""  -L "B^0" \
 959                        expect     empty  other &&
 960                test_cmp expect six
 961        )
 962'
 963
 964test_conflicts_with_adds_and_renames() {
 965        sideL=$1
 966        sideR=$2
 967
 968        # Setup:
 969        #          L
 970        #         / \
 971        #   master   ?
 972        #         \ /
 973        #          R
 974        #
 975        # Where:
 976        #   Both L and R have files named 'three' which collide.  Each of
 977        #   the colliding files could have been involved in a rename, in
 978        #   which case there was a file named 'one' or 'two' that was
 979        #   modified on the opposite side of history and renamed into the
 980        #   collision on this side of history.
 981        #
 982        # Questions:
 983        #   1) The index should contain both a stage 2 and stage 3 entry
 984        #      for the colliding file.  Does it?
 985        #   2) When renames are involved, the content merges are clean, so
 986        #      the index should reflect the content merges, not merely the
 987        #      version of the colliding file from the prior commit.  Does
 988        #      it?
 989        #   3) There should be a file in the worktree named 'three'
 990        #      containing the two-way merged contents of the content-merged
 991        #      versions of 'three' from each of the two colliding
 992        #      files.  Is it present?
 993        #   4) There should not be any three~* files in the working
 994        #      tree
 995        test_expect_success "setup simple $sideL/$sideR conflict" '
 996                test_create_repo simple_${sideL}_${sideR} &&
 997                (
 998                        cd simple_${sideL}_${sideR} &&
 999
1000                        # Create some related files now
1001                        for i in $(test_seq 1 10)
1002                        do
1003                                echo Random base content line $i
1004                        done >file_v1 &&
1005                        cp file_v1 file_v2 &&
1006                        echo modification >>file_v2 &&
1007
1008                        cp file_v1 file_v3 &&
1009                        echo more stuff >>file_v3 &&
1010                        cp file_v3 file_v4 &&
1011                        echo yet more stuff >>file_v4 &&
1012
1013                        # Use a tag to record both these files for simple
1014                        # access, and clean out these untracked files
1015                        git tag file_v1 $(git hash-object -w file_v1) &&
1016                        git tag file_v2 $(git hash-object -w file_v2) &&
1017                        git tag file_v3 $(git hash-object -w file_v3) &&
1018                        git tag file_v4 $(git hash-object -w file_v4) &&
1019                        git clean -f &&
1020
1021                        # Setup original commit (or merge-base), consisting of
1022                        # files named "one" and "two" if renames were involved.
1023                        touch irrelevant_file &&
1024                        git add irrelevant_file &&
1025                        if [ $sideL = "rename" ]
1026                        then
1027                                git show file_v1 >one &&
1028                                git add one
1029                        fi &&
1030                        if [ $sideR = "rename" ]
1031                        then
1032                                git show file_v3 >two &&
1033                                git add two
1034                        fi &&
1035                        test_tick && git commit -m initial &&
1036
1037                        git branch L &&
1038                        git branch R &&
1039
1040                        # Handle the left side
1041                        git checkout L &&
1042                        if [ $sideL = "rename" ]
1043                        then
1044                                git mv one three
1045                        else
1046                                git show file_v2 >three &&
1047                                git add three
1048                        fi &&
1049                        if [ $sideR = "rename" ]
1050                        then
1051                                git show file_v4 >two &&
1052                                git add two
1053                        fi &&
1054                        test_tick && git commit -m L &&
1055
1056                        # Handle the right side
1057                        git checkout R &&
1058                        if [ $sideL = "rename" ]
1059                        then
1060                                git show file_v2 >one &&
1061                                git add one
1062                        fi &&
1063                        if [ $sideR = "rename" ]
1064                        then
1065                                git mv two three
1066                        else
1067                                git show file_v4 >three &&
1068                                git add three
1069                        fi &&
1070                        test_tick && git commit -m R
1071                )
1072        '
1073
1074        test_expect_success "check simple $sideL/$sideR conflict" '
1075                (
1076                        cd simple_${sideL}_${sideR} &&
1077
1078                        git checkout L^0 &&
1079
1080                        # Merge must fail; there is a conflict
1081                        test_must_fail git merge -s recursive R^0 &&
1082
1083                        # Make sure the index has the right number of entries
1084                        git ls-files -s >out &&
1085                        test_line_count = 3 out &&
1086                        git ls-files -u >out &&
1087                        test_line_count = 2 out &&
1088                        # Ensure we have the correct number of untracked files
1089                        git ls-files -o >out &&
1090                        test_line_count = 1 out &&
1091
1092                        # Nothing should have touched irrelevant_file
1093                        git rev-parse >actual      \
1094                                :0:irrelevant_file \
1095                                :2:three           \
1096                                :3:three           &&
1097                        git rev-parse >expected        \
1098                                master:irrelevant_file \
1099                                file_v2                \
1100                                file_v4                &&
1101                        test_cmp expected actual &&
1102
1103                        # Make sure we have the correct merged contents for
1104                        # three
1105                        git show file_v1 >expected &&
1106                        cat <<-\EOF >>expected &&
1107                        <<<<<<< HEAD
1108                        modification
1109                        =======
1110                        more stuff
1111                        yet more stuff
1112                        >>>>>>> R^0
1113                        EOF
1114
1115                        test_cmp expected three
1116                )
1117        '
1118}
1119
1120test_conflicts_with_adds_and_renames rename rename
1121test_conflicts_with_adds_and_renames rename add
1122test_conflicts_with_adds_and_renames add    rename
1123test_conflicts_with_adds_and_renames add    add
1124
1125# Setup:
1126#          L
1127#         / \
1128#   master   ?
1129#         \ /
1130#          R
1131#
1132# Where:
1133#   master has two files, named 'one' and 'two'.
1134#   branches L and R both modify 'one', in conflicting ways.
1135#   branches L and R both modify 'two', in conflicting ways.
1136#   branch L also renames 'one' to 'three'.
1137#   branch R also renames 'two' to 'three'.
1138#
1139#   So, we have four different conflicting files that all end up at path
1140#   'three'.
1141test_expect_success 'setup nested conflicts from rename/rename(2to1)' '
1142        test_create_repo nested_conflicts_from_rename_rename &&
1143        (
1144                cd nested_conflicts_from_rename_rename &&
1145
1146                # Create some related files now
1147                for i in $(test_seq 1 10)
1148                do
1149                        echo Random base content line $i
1150                done >file_v1 &&
1151
1152                cp file_v1 file_v2 &&
1153                cp file_v1 file_v3 &&
1154                cp file_v1 file_v4 &&
1155                cp file_v1 file_v5 &&
1156                cp file_v1 file_v6 &&
1157
1158                echo one  >>file_v1 &&
1159                echo uno  >>file_v2 &&
1160                echo eins >>file_v3 &&
1161
1162                echo two  >>file_v4 &&
1163                echo dos  >>file_v5 &&
1164                echo zwei >>file_v6 &&
1165
1166                # Setup original commit (or merge-base), consisting of
1167                # files named "one" and "two".
1168                mv file_v1 one &&
1169                mv file_v4 two &&
1170                git add one two &&
1171                test_tick && git commit -m english &&
1172
1173                git branch L &&
1174                git branch R &&
1175
1176                # Handle the left side
1177                git checkout L &&
1178                git rm one two &&
1179                mv -f file_v2 three &&
1180                mv -f file_v5 two &&
1181                git add two three &&
1182                test_tick && git commit -m spanish &&
1183
1184                # Handle the right side
1185                git checkout R &&
1186                git rm one two &&
1187                mv -f file_v3 one &&
1188                mv -f file_v6 three &&
1189                git add one three &&
1190                test_tick && git commit -m german
1191        )
1192'
1193
1194test_expect_success 'check nested conflicts from rename/rename(2to1)' '
1195        (
1196                cd nested_conflicts_from_rename_rename &&
1197
1198                git checkout L^0 &&
1199
1200                # Merge must fail; there is a conflict
1201                test_must_fail git merge -s recursive R^0 &&
1202
1203                # Make sure the index has the right number of entries
1204                git ls-files -s >out &&
1205                test_line_count = 2 out &&
1206                git ls-files -u >out &&
1207                test_line_count = 2 out &&
1208                # Ensure we have the correct number of untracked files
1209                git ls-files -o >out &&
1210                test_line_count = 1 out &&
1211
1212                # Compare :2:three to expected values
1213                git cat-file -p master:one >base &&
1214                git cat-file -p L:three >ours &&
1215                git cat-file -p R:one >theirs &&
1216                test_must_fail git merge-file    \
1217                        -L "HEAD:three"  -L ""  -L "R^0:one" \
1218                        ours             base   theirs &&
1219                sed -e "s/^\([<=>]\)/\1\1/" ours >L-three &&
1220                git cat-file -p :2:three >expect &&
1221                test_cmp expect L-three &&
1222
1223                # Compare :2:three to expected values
1224                git cat-file -p master:two >base &&
1225                git cat-file -p L:two >ours &&
1226                git cat-file -p R:three >theirs &&
1227                test_must_fail git merge-file    \
1228                        -L "HEAD:two"  -L ""  -L "R^0:three" \
1229                        ours           base   theirs &&
1230                sed -e "s/^\([<=>]\)/\1\1/" ours >R-three &&
1231                git cat-file -p :3:three >expect &&
1232                test_cmp expect R-three &&
1233
1234                # Compare three to expected contents
1235                >empty &&
1236                test_must_fail git merge-file    \
1237                        -L "HEAD"  -L ""  -L "R^0" \
1238                        L-three    empty  R-three &&
1239                test_cmp three L-three
1240        )
1241'
1242
1243test_done