bec0192c3b71085805ee5c9aa5f92ffd3ee8fbff
   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 -f 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                test $(git rev-parse B:a) = $(git rev-parse b) &&
  84                test $(git rev-parse C:a) = $(git rev-parse a)
  85        )
  86'
  87
  88test_expect_success 'setup resolvable conflict missed if rename missed' '
  89        test_create_repo break-detection-1 &&
  90        (
  91                cd break-detection-1 &&
  92
  93                printf "1\n2\n3\n4\n5\n" >a &&
  94                echo foo >b &&
  95                git add a b &&
  96                git commit -m A &&
  97                git tag A &&
  98
  99                git checkout -b B A &&
 100                git mv a c &&
 101                echo "Completely different content" >a &&
 102                git add a &&
 103                git commit -m B &&
 104
 105                git checkout -b C A &&
 106                echo 6 >>a &&
 107                git add a &&
 108                git commit -m C
 109        )
 110'
 111
 112test_expect_failure 'conflict caused if rename not detected' '
 113        (
 114                cd break-detection-1 &&
 115
 116                git checkout -q C^0 &&
 117                git merge -s recursive B^0 &&
 118
 119                test 3 -eq $(git ls-files -s | wc -l) &&
 120                test 0 -eq $(git ls-files -u | wc -l) &&
 121                test 0 -eq $(git ls-files -o | wc -l) &&
 122
 123                test_line_count = 6 c &&
 124                test $(git rev-parse HEAD:a) = $(git rev-parse B:a) &&
 125                test $(git rev-parse HEAD:b) = $(git rev-parse A:b)
 126        )
 127'
 128
 129test_expect_success 'setup conflict resolved wrong if rename missed' '
 130        test_create_repo break-detection-2 &&
 131        (
 132                cd break-detection-2 &&
 133
 134                printf "1\n2\n3\n4\n5\n" >a &&
 135                echo foo >b &&
 136                git add a b &&
 137                git commit -m A &&
 138                git tag A &&
 139
 140                git checkout -b D A &&
 141                echo 7 >>a &&
 142                git add a &&
 143                git mv a c &&
 144                echo "Completely different content" >a &&
 145                git add a &&
 146                git commit -m D &&
 147
 148                git checkout -b E A &&
 149                git rm a &&
 150                echo "Completely different content" >>a &&
 151                git add a &&
 152                git commit -m E
 153        )
 154'
 155
 156test_expect_failure 'missed conflict if rename not detected' '
 157        (
 158                cd break-detection-2 &&
 159
 160                git checkout -q E^0 &&
 161                test_must_fail git merge -s recursive D^0
 162        )
 163'
 164
 165# Tests for undetected rename/add-source causing a file to erroneously be
 166# deleted (and for mishandled rename/rename(1to1) causing the same issue).
 167#
 168# This test uses a rename/rename(1to1)+add-source conflict (1to1 means the
 169# same file is renamed on both sides to the same thing; it should trigger
 170# the 1to2 logic, which it would do if the add-source didn't cause issues
 171# for git's rename detection):
 172#   Commit A: new file: a
 173#   Commit B: rename a->b
 174#   Commit C: rename a->b, add unrelated a
 175
 176test_expect_success 'setup undetected rename/add-source causes data loss' '
 177        test_create_repo break-detection-3 &&
 178        (
 179                cd break-detection-3 &&
 180
 181                printf "1\n2\n3\n4\n5\n" >a &&
 182                git add a &&
 183                git commit -m A &&
 184                git tag A &&
 185
 186                git checkout -b B A &&
 187                git mv a b &&
 188                git commit -m B &&
 189
 190                git checkout -b C A &&
 191                git mv a b &&
 192                echo foobar >a &&
 193                git add a &&
 194                git commit -m C
 195        )
 196'
 197
 198test_expect_failure 'detect rename/add-source and preserve all data' '
 199        (
 200                cd break-detection-3 &&
 201
 202                git checkout B^0 &&
 203
 204                git merge -s recursive C^0 &&
 205
 206                test 2 -eq $(git ls-files -s | wc -l) &&
 207                test 2 -eq $(git ls-files -u | wc -l) &&
 208                test 0 -eq $(git ls-files -o | wc -l) &&
 209
 210                test -f a &&
 211                test -f b &&
 212
 213                test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
 214                test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
 215        )
 216'
 217
 218test_expect_failure 'detect rename/add-source and preserve all data, merge other way' '
 219        (
 220                cd break-detection-3 &&
 221
 222                git checkout C^0 &&
 223
 224                git merge -s recursive B^0 &&
 225
 226                test 2 -eq $(git ls-files -s | wc -l) &&
 227                test 2 -eq $(git ls-files -u | wc -l) &&
 228                test 0 -eq $(git ls-files -o | wc -l) &&
 229
 230                test -f a &&
 231                test -f b &&
 232
 233                test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
 234                test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
 235        )
 236'
 237
 238test_expect_success 'setup content merge + rename/directory conflict' '
 239        test_create_repo rename-directory-1 &&
 240        (
 241                cd rename-directory-1 &&
 242
 243                printf "1\n2\n3\n4\n5\n6\n" >file &&
 244                git add file &&
 245                test_tick &&
 246                git commit -m base &&
 247                git tag base &&
 248
 249                git checkout -b right &&
 250                echo 7 >>file &&
 251                mkdir newfile &&
 252                echo junk >newfile/realfile &&
 253                git add file newfile/realfile &&
 254                test_tick &&
 255                git commit -m right &&
 256
 257                git checkout -b left-conflict base &&
 258                echo 8 >>file &&
 259                git add file &&
 260                git mv file newfile &&
 261                test_tick &&
 262                git commit -m left &&
 263
 264                git checkout -b left-clean base &&
 265                echo 0 >newfile &&
 266                cat file >>newfile &&
 267                git add newfile &&
 268                git rm file &&
 269                test_tick &&
 270                git commit -m left
 271        )
 272'
 273
 274test_expect_success 'rename/directory conflict + clean content merge' '
 275        (
 276                cd rename-directory-1 &&
 277
 278                git checkout left-clean^0 &&
 279
 280                test_must_fail git merge -s recursive right^0 &&
 281
 282                test 2 -eq $(git ls-files -s | wc -l) &&
 283                test 1 -eq $(git ls-files -u | wc -l) &&
 284                test 1 -eq $(git ls-files -o | wc -l) &&
 285
 286                echo 0 >expect &&
 287                git cat-file -p base:file >>expect &&
 288                echo 7 >>expect &&
 289                test_cmp expect newfile~HEAD &&
 290
 291                test $(git rev-parse :2:newfile) = $(git hash-object expect) &&
 292
 293                test -f newfile/realfile &&
 294                test -f newfile~HEAD
 295        )
 296'
 297
 298test_expect_success 'rename/directory conflict + content merge conflict' '
 299        (
 300                cd rename-directory-1 &&
 301
 302                git reset --hard &&
 303                git reset --hard &&
 304                git clean -fdqx &&
 305
 306                git checkout left-conflict^0 &&
 307
 308                test_must_fail git merge -s recursive right^0 &&
 309
 310                test 4 -eq $(git ls-files -s | wc -l) &&
 311                test 3 -eq $(git ls-files -u | wc -l) &&
 312                test 1 -eq $(git ls-files -o | wc -l) &&
 313
 314                git cat-file -p left-conflict:newfile >left &&
 315                git cat-file -p base:file    >base &&
 316                git cat-file -p right:file   >right &&
 317                test_must_fail git merge-file \
 318                        -L "HEAD:newfile" \
 319                        -L "" \
 320                        -L "right^0:file" \
 321                        left base right &&
 322                test_cmp left newfile~HEAD &&
 323
 324                test $(git rev-parse :1:newfile) = $(git rev-parse base:file) &&
 325                test $(git rev-parse :2:newfile) = $(git rev-parse left-conflict:newfile) &&
 326                test $(git rev-parse :3:newfile) = $(git rev-parse right:file) &&
 327
 328                test -f newfile/realfile &&
 329                test -f newfile~HEAD
 330        )
 331'
 332
 333test_expect_success 'setup content merge + rename/directory conflict w/ disappearing dir' '
 334        test_create_repo rename-directory-2 &&
 335        (
 336                cd rename-directory-2 &&
 337
 338                mkdir sub &&
 339                printf "1\n2\n3\n4\n5\n6\n" >sub/file &&
 340                git add sub/file &&
 341                test_tick &&
 342                git commit -m base &&
 343                git tag base &&
 344
 345                git checkout -b right &&
 346                echo 7 >>sub/file &&
 347                git add sub/file &&
 348                test_tick &&
 349                git commit -m right &&
 350
 351                git checkout -b left base &&
 352                echo 0 >newfile &&
 353                cat sub/file >>newfile &&
 354                git rm sub/file &&
 355                mv newfile sub &&
 356                git add sub &&
 357                test_tick &&
 358                git commit -m left
 359        )
 360'
 361
 362test_expect_success 'disappearing dir in rename/directory conflict handled' '
 363        (
 364                cd rename-directory-2 &&
 365
 366                git checkout left^0 &&
 367
 368                git merge -s recursive right^0 &&
 369
 370                test 1 -eq $(git ls-files -s | wc -l) &&
 371                test 0 -eq $(git ls-files -u | wc -l) &&
 372                test 0 -eq $(git ls-files -o | wc -l) &&
 373
 374                echo 0 >expect &&
 375                git cat-file -p base:sub/file >>expect &&
 376                echo 7 >>expect &&
 377                test_cmp expect sub &&
 378
 379                test -f sub
 380        )
 381'
 382
 383# Test for all kinds of things that can go wrong with rename/rename (2to1):
 384#   Commit A: new files: a & b
 385#   Commit B: rename a->c, modify b
 386#   Commit C: rename b->c, modify a
 387#
 388# Merging of B & C should NOT be clean.  Questions:
 389#   * Both a & b should be removed by the merge; are they?
 390#   * The two c's should contain modifications to a & b; do they?
 391#   * The index should contain two files, both for c; does it?
 392#   * The working copy should have two files, both of form c~<unique>; does it?
 393#   * Nothing else should be present.  Is anything?
 394
 395test_expect_success 'setup rename/rename (2to1) + modify/modify' '
 396        test_create_repo rename-rename-2to1 &&
 397        (
 398                cd rename-rename-2to1 &&
 399
 400                printf "1\n2\n3\n4\n5\n" >a &&
 401                printf "5\n4\n3\n2\n1\n" >b &&
 402                git add a b &&
 403                git commit -m A &&
 404                git tag A &&
 405
 406                git checkout -b B A &&
 407                git mv a c &&
 408                echo 0 >>b &&
 409                git add b &&
 410                git commit -m B &&
 411
 412                git checkout -b C A &&
 413                git mv b c &&
 414                echo 6 >>a &&
 415                git add a &&
 416                git commit -m C
 417        )
 418'
 419
 420test_expect_success 'handle rename/rename (2to1) conflict correctly' '
 421        (
 422                cd rename-rename-2to1 &&
 423
 424                git checkout B^0 &&
 425
 426                test_must_fail git merge -s recursive C^0 >out &&
 427                test_i18ngrep "CONFLICT (rename/rename)" out &&
 428
 429                test 2 -eq $(git ls-files -s | wc -l) &&
 430                test 2 -eq $(git ls-files -u | wc -l) &&
 431                test 2 -eq $(git ls-files -u c | wc -l) &&
 432                test 3 -eq $(git ls-files -o | wc -l) &&
 433
 434                test ! -f a &&
 435                test ! -f b &&
 436                test -f c~HEAD &&
 437                test -f c~C^0 &&
 438
 439                test $(git hash-object c~HEAD) = $(git rev-parse C:a) &&
 440                test $(git hash-object c~C^0) = $(git rev-parse B:b)
 441        )
 442'
 443
 444# Testcase setup for simple rename/rename (1to2) conflict:
 445#   Commit A: new file: a
 446#   Commit B: rename a->b
 447#   Commit C: rename a->c
 448test_expect_success 'setup simple rename/rename (1to2) conflict' '
 449        test_create_repo rename-rename-1to2 &&
 450        (
 451                cd rename-rename-1to2 &&
 452
 453                echo stuff >a &&
 454                git add a &&
 455                test_tick &&
 456                git commit -m A &&
 457                git tag A &&
 458
 459                git checkout -b B A &&
 460                git mv a b &&
 461                test_tick &&
 462                git commit -m B &&
 463
 464                git checkout -b C A &&
 465                git mv a c &&
 466                test_tick &&
 467                git commit -m C
 468        )
 469'
 470
 471test_expect_success 'merge has correct working tree contents' '
 472        (
 473                cd rename-rename-1to2 &&
 474
 475                git checkout C^0 &&
 476
 477                test_must_fail git merge -s recursive B^0 &&
 478
 479                test 3 -eq $(git ls-files -s | wc -l) &&
 480                test 3 -eq $(git ls-files -u | wc -l) &&
 481                test 0 -eq $(git ls-files -o | wc -l) &&
 482
 483                test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
 484                test $(git rev-parse :3:b) = $(git rev-parse A:a) &&
 485                test $(git rev-parse :2:c) = $(git rev-parse A:a) &&
 486
 487                test ! -f a &&
 488                test $(git hash-object b) = $(git rev-parse A:a) &&
 489                test $(git hash-object c) = $(git rev-parse A:a)
 490        )
 491'
 492
 493# Testcase setup for rename/rename(1to2)/add-source conflict:
 494#   Commit A: new file: a
 495#   Commit B: rename a->b
 496#   Commit C: rename a->c, add completely different a
 497#
 498# Merging of B & C should NOT be clean; there's a rename/rename conflict
 499
 500test_expect_success 'setup rename/rename(1to2)/add-source conflict' '
 501        test_create_repo rename-rename-1to2-add-source-1 &&
 502        (
 503                cd rename-rename-1to2-add-source-1 &&
 504
 505                printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
 506                git add a &&
 507                git commit -m A &&
 508                git tag A &&
 509
 510                git checkout -b B A &&
 511                git mv a b &&
 512                git commit -m B &&
 513
 514                git checkout -b C A &&
 515                git mv a c &&
 516                echo something completely different >a &&
 517                git add a &&
 518                git commit -m C
 519        )
 520'
 521
 522test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge' '
 523        (
 524                cd rename-rename-1to2-add-source-1 &&
 525
 526                git checkout B^0 &&
 527
 528                test_must_fail git merge -s recursive C^0 &&
 529
 530                test 4 -eq $(git ls-files -s | wc -l) &&
 531                test 0 -eq $(git ls-files -o | wc -l) &&
 532
 533                test $(git rev-parse 3:a) = $(git rev-parse C:a) &&
 534                test $(git rev-parse 1:a) = $(git rev-parse A:a) &&
 535                test $(git rev-parse 2:b) = $(git rev-parse B:b) &&
 536                test $(git rev-parse 3:c) = $(git rev-parse C:c) &&
 537
 538                test -f a &&
 539                test -f b &&
 540                test -f c
 541        )
 542'
 543
 544test_expect_success 'setup rename/rename(1to2)/add-source resolvable conflict' '
 545        test_create_repo rename-rename-1to2-add-source-2 &&
 546        (
 547                cd rename-rename-1to2-add-source-2 &&
 548
 549                >a &&
 550                git add a &&
 551                test_tick &&
 552                git commit -m base &&
 553                git tag A &&
 554
 555                git checkout -b B A &&
 556                git mv a b &&
 557                test_tick &&
 558                git commit -m one &&
 559
 560                git checkout -b C A &&
 561                git mv a b &&
 562                echo important-info >a &&
 563                git add a &&
 564                test_tick &&
 565                git commit -m two
 566        )
 567'
 568
 569test_expect_failure 'rename/rename/add-source still tracks new a file' '
 570        (
 571                cd rename-rename-1to2-add-source-2 &&
 572
 573                git checkout C^0 &&
 574                git merge -s recursive B^0 &&
 575
 576                test 2 -eq $(git ls-files -s | wc -l) &&
 577                test 0 -eq $(git ls-files -o | wc -l) &&
 578
 579                test $(git rev-parse HEAD:a) = $(git rev-parse C:a) &&
 580                test $(git rev-parse HEAD:b) = $(git rev-parse A:a)
 581        )
 582'
 583
 584test_expect_success 'setup rename/rename(1to2)/add-dest conflict' '
 585        test_create_repo rename-rename-1to2-add-dest &&
 586        (
 587                cd rename-rename-1to2-add-dest &&
 588
 589                echo stuff >a &&
 590                git add a &&
 591                test_tick &&
 592                git commit -m base &&
 593                git tag A &&
 594
 595                git checkout -b B A &&
 596                git mv a b &&
 597                echo precious-data >c &&
 598                git add c &&
 599                test_tick &&
 600                git commit -m one &&
 601
 602                git checkout -b C A &&
 603                git mv a c &&
 604                echo important-info >b &&
 605                git add b &&
 606                test_tick &&
 607                git commit -m two
 608        )
 609'
 610
 611test_expect_success 'rename/rename/add-dest merge still knows about conflicting file versions' '
 612        (
 613                cd rename-rename-1to2-add-dest &&
 614
 615                git checkout C^0 &&
 616                test_must_fail git merge -s recursive B^0 &&
 617
 618                test 5 -eq $(git ls-files -s | wc -l) &&
 619                test 2 -eq $(git ls-files -u b | wc -l) &&
 620                test 2 -eq $(git ls-files -u c | wc -l) &&
 621                test 4 -eq $(git ls-files -o | wc -l) &&
 622
 623                test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
 624                test $(git rev-parse :2:b) = $(git rev-parse C:b) &&
 625                test $(git rev-parse :3:b) = $(git rev-parse B:b) &&
 626                test $(git rev-parse :2:c) = $(git rev-parse C:c) &&
 627                test $(git rev-parse :3:c) = $(git rev-parse B:c) &&
 628
 629                test $(git hash-object c~HEAD) = $(git rev-parse C:c) &&
 630                test $(git hash-object c~B\^0) = $(git rev-parse B:c) &&
 631                test $(git hash-object b~HEAD) = $(git rev-parse C:b) &&
 632                test $(git hash-object b~B\^0) = $(git rev-parse B:b) &&
 633
 634                test ! -f b &&
 635                test ! -f c
 636        )
 637'
 638
 639test_done