1#!/bin/sh
   2test_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. ./test-lib.sh
   7test_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        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        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'
  28test_expect_success "Does git preserve Gollum's precious artifact?" '
  30        test_must_fail git merge -s recursive rename-the-ring &&
  31        # Make sure git did not delete an untracked file
  33        test -f ring
  34'
  35# 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
  42test_expect_success 'setup rename/modify/add-source conflict' '
  44        git rm -rf . &&
  45        git clean -fdqx &&
  46        rm -rf .git &&
  47        git init &&
  48        printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
  50        git add a &&
  51        git commit -m A &&
  52        git tag A &&
  53        git checkout -b B A &&
  55        echo 8 >>a &&
  56        git add a &&
  57        git commit -m B &&
  58        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'
  65test_expect_failure 'rename/modify/add-source conflict resolvable' '
  67        git checkout B^0 &&
  68        git merge -s recursive C^0 &&
  70        test $(git rev-parse B:a) = $(git rev-parse b) &&
  72        test $(git rev-parse C:a) = $(git rev-parse a)
  73'
  74test_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        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        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        git checkout -b C A &&
  94        echo 6 >>a &&
  95        git add a &&
  96        git commit -m C
  97'
  98test_expect_failure 'conflict caused if rename not detected' '
 100        git checkout -q C^0 &&
 101        git merge -s recursive B^0 &&
 102        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        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'
 111test_expect_success 'setup conflict resolved wrong if rename missed' '
 113        git reset --hard &&
 114        git clean -f &&
 115        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        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'
 130test_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# 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
 146test_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        printf "1\n2\n3\n4\n5\n" >a &&
 154        git add a &&
 155        git commit -m A &&
 156        git tag A &&
 157        git checkout -b B A &&
 159        git mv a b &&
 160        git commit -m B &&
 161        git checkout -b C A &&
 163        git mv a b &&
 164        echo foobar >a &&
 165        git add a &&
 166        git commit -m C
 167'
 168test_expect_failure 'detect rename/add-source and preserve all data' '
 170        git checkout B^0 &&
 171        git merge -s recursive C^0 &&
 173        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        test -f a &&
 179        test -f b &&
 180        test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
 182        test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
 183'
 184test_expect_failure 'detect rename/add-source and preserve all data, merge other way' '
 186        git checkout C^0 &&
 187        git merge -s recursive B^0 &&
 189        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        test -f a &&
 195        test -f b &&
 196        test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
 198        test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
 199'
 200test_expect_success 'setup content merge + rename/directory conflict' '
 202        git rm -rf . &&
 203        git clean -fdqx &&
 204        rm -rf .git &&
 205        git init &&
 206        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        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        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        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'
 236test_expect_success 'rename/directory conflict + clean content merge' '
 238        git reset --hard &&
 239        git reset --hard &&
 240        git clean -fdqx &&
 241        git checkout left-clean^0 &&
 243        test_must_fail git merge -s recursive right^0 &&
 245        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        echo 0 >expect &&
 251        git cat-file -p base:file >>expect &&
 252        echo 7 >>expect &&
 253        test_cmp expect newfile~HEAD &&
 254        test $(git rev-parse :2:newfile) = $(git hash-object expect) &&
 256        test -f newfile/realfile &&
 258        test -f newfile~HEAD
 259'
 260test_expect_success 'rename/directory conflict + content merge conflict' '
 262        git reset --hard &&
 263        git reset --hard &&
 264        git clean -fdqx &&
 265        git checkout left-conflict^0 &&
 267        test_must_fail git merge -s recursive right^0 &&
 269        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        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        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        test -f newfile/realfile &&
 289        test -f newfile~HEAD
 290'
 291test_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        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        git checkout -b right &&
 307        echo 7 >>sub/file &&
 308        git add sub/file &&
 309        test_tick &&
 310        git commit -m right &&
 311        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'
 321test_expect_success 'disappearing dir in rename/directory conflict handled' '
 323        git reset --hard &&
 324        git clean -fdqx &&
 325        git checkout left^0 &&
 327        git merge -s recursive right^0 &&
 329        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        echo 0 >expect &&
 335        git cat-file -p base:sub/file >>expect &&
 336        echo 7 >>expect &&
 337        test_cmp expect sub &&
 338        test -f sub
 340'
 341# 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?
 353test_expect_success 'setup rename/rename (2to1) + modify/modify' '
 355        git rm -rf . &&
 356        git clean -fdqx &&
 357        rm -rf .git &&
 358        git init &&
 359        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        git checkout -b B A &&
 367        git mv a c &&
 368        echo 0 >>b &&
 369        git add b &&
 370        git commit -m B &&
 371        git checkout -b C A &&
 373        git mv b c &&
 374        echo 6 >>a &&
 375        git add a &&
 376        git commit -m C
 377'
 378test_expect_success 'handle rename/rename (2to1) conflict correctly' '
 380        git checkout B^0 &&
 381        test_must_fail git merge -s recursive C^0 >out &&
 383        test_i18ngrep "CONFLICT (rename/rename)" out &&
 384        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        test ! -f a &&
 391        test ! -f b &&
 392        test -f c~HEAD &&
 393        test -f c~C^0 &&
 394        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# 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        echo stuff >a &&
 410        git add a &&
 411        test_tick &&
 412        git commit -m A &&
 413        git tag A &&
 414        git checkout -b B A &&
 416        git mv a b &&
 417        test_tick &&
 418        git commit -m B &&
 419        git checkout -b C A &&
 421        git mv a c &&
 422        test_tick &&
 423        git commit -m C
 424'
 425test_expect_success 'merge has correct working tree contents' '
 427        git checkout C^0 &&
 428        test_must_fail git merge -s recursive B^0 &&
 430        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        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        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# 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
 450test_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        printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
 458        git add a &&
 459        git commit -m A &&
 460        git tag A &&
 461        git checkout -b B A &&
 463        git mv a b &&
 464        git commit -m B &&
 465        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'
 472test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge' '
 474        git checkout B^0 &&
 475        test_must_fail git merge -s recursive C^0 &&
 477        test 4 -eq $(git ls-files -s | wc -l) &&
 479        test 0 -eq $(git ls-files -o | wc -l) &&
 480        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        test -f a &&
 487        test -f b &&
 488        test -f c
 489'
 490test_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        >a &&
 498        git add a &&
 499        test_tick &&
 500        git commit -m base &&
 501        git tag A &&
 502        git checkout -b B A &&
 504        git mv a b &&
 505        test_tick &&
 506        git commit -m one &&
 507        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'
 515test_expect_failure 'rename/rename/add-source still tracks new a file' '
 517        git checkout C^0 &&
 518        git merge -s recursive B^0 &&
 519        test 2 -eq $(git ls-files -s | wc -l) &&
 521        test 0 -eq $(git ls-files -o | wc -l) &&
 522        test $(git rev-parse HEAD:a) = $(git rev-parse C:a) &&
 524        test $(git rev-parse HEAD:b) = $(git rev-parse A:a)
 525'
 526test_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        echo stuff >a &&
 534        git add a &&
 535        test_tick &&
 536        git commit -m base &&
 537        git tag A &&
 538        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        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'
 553test_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        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        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        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        test ! -f b &&
 575        test ! -f c
 576'
 577test_done