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