t / t6022-merge-rename.shon commit Merge branch 'maint-1.7.3' into maint-1.7.4 (ed36a48)
   1#!/bin/sh
   2
   3test_description='Merge-recursive merging renames'
   4. ./test-lib.sh
   5
   6modify () {
   7        sed -e "$1" <"$2" >"$2.x" &&
   8        mv "$2.x" "$2"
   9}
  10
  11test_expect_success setup \
  12'
  13cat >A <<\EOF &&
  14a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  15b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
  16c cccccccccccccccccccccccccccccccccccccccccccccccc
  17d dddddddddddddddddddddddddddddddddddddddddddddddd
  18e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
  19f ffffffffffffffffffffffffffffffffffffffffffffffff
  20g gggggggggggggggggggggggggggggggggggggggggggggggg
  21h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
  22i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
  23j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
  24k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
  25l llllllllllllllllllllllllllllllllllllllllllllllll
  26m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
  27n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
  28o oooooooooooooooooooooooooooooooooooooooooooooooo
  29EOF
  30
  31cat >M <<\EOF &&
  32A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  33B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
  34C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
  35D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
  36E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  37F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  38G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
  39H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
  40I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
  41J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
  42K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
  43L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
  44M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  45N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
  46O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
  47EOF
  48
  49git add A M &&
  50git commit -m "initial has A and M" &&
  51git branch white &&
  52git branch red &&
  53git branch blue &&
  54git branch yellow &&
  55git branch change &&
  56git branch change+rename &&
  57
  58sed -e "/^g /s/.*/g : master changes a line/" <A >A+ &&
  59mv A+ A &&
  60git commit -a -m "master updates A" &&
  61
  62git checkout yellow &&
  63rm -f M &&
  64git commit -a -m "yellow removes M" &&
  65
  66git checkout white &&
  67sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
  68sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
  69rm -f A M &&
  70git update-index --add --remove A B M N &&
  71git commit -m "white renames A->B, M->N" &&
  72
  73git checkout red &&
  74sed -e "/^g /s/.*/g : red changes a line/" <A >B &&
  75sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
  76rm -f A M &&
  77git update-index --add --remove A B M N &&
  78git commit -m "red renames A->B, M->N" &&
  79
  80git checkout blue &&
  81sed -e "/^g /s/.*/g : blue changes a line/" <A >C &&
  82sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
  83rm -f A M &&
  84git update-index --add --remove A C M N &&
  85git commit -m "blue renames A->C, M->N" &&
  86
  87git checkout change &&
  88sed -e "/^g /s/.*/g : changed line/" <A >A+ &&
  89mv A+ A &&
  90git commit -q -a -m "changed" &&
  91
  92git checkout change+rename &&
  93sed -e "/^g /s/.*/g : changed line/" <A >B &&
  94rm A &&
  95git update-index --add B &&
  96git commit -q -a -m "changed and renamed" &&
  97
  98git checkout master'
  99
 100test_expect_success 'pull renaming branch into unrenaming one' \
 101'
 102        git show-branch &&
 103        test_expect_code 1 git pull . white &&
 104        git ls-files -s &&
 105        git ls-files -u B >b.stages &&
 106        test_line_count = 3 b.stages &&
 107        git ls-files -s N >n.stages &&
 108        test_line_count = 1 n.stages &&
 109        sed -ne "/^g/{
 110        p
 111        q
 112        }" B | grep master &&
 113        git diff --exit-code white N
 114'
 115
 116test_expect_success 'pull renaming branch into another renaming one' \
 117'
 118        rm -f B &&
 119        git reset --hard &&
 120        git checkout red &&
 121        test_expect_code 1 git pull . white &&
 122        git ls-files -u B >b.stages &&
 123        test_line_count = 3 b.stages &&
 124        git ls-files -s N >n.stages &&
 125        test_line_count = 1 n.stages &&
 126        sed -ne "/^g/{
 127        p
 128        q
 129        }" B | grep red &&
 130        git diff --exit-code white N
 131'
 132
 133test_expect_success 'pull unrenaming branch into renaming one' \
 134'
 135        git reset --hard &&
 136        git show-branch &&
 137        test_expect_code 1 git pull . master &&
 138        git ls-files -u B >b.stages &&
 139        test_line_count = 3 b.stages &&
 140        git ls-files -s N >n.stages &&
 141        test_line_count = 1 n.stages &&
 142        sed -ne "/^g/{
 143        p
 144        q
 145        }" B | grep red &&
 146        git diff --exit-code white N
 147'
 148
 149test_expect_success 'pull conflicting renames' \
 150'
 151        git reset --hard &&
 152        git show-branch &&
 153        test_expect_code 1 git pull . blue &&
 154        git ls-files -u A >a.stages &&
 155        test_line_count = 1 a.stages &&
 156        git ls-files -u B >b.stages &&
 157        test_line_count = 1 b.stages &&
 158        git ls-files -u C >c.stages &&
 159        test_line_count = 1 c.stages &&
 160        git ls-files -s N >n.stages &&
 161        test_line_count = 1 n.stages &&
 162        sed -ne "/^g/{
 163        p
 164        q
 165        }" B | grep red &&
 166        git diff --exit-code white N
 167'
 168
 169test_expect_success 'interference with untracked working tree file' '
 170        git reset --hard &&
 171        git show-branch &&
 172        echo >A this file should not matter &&
 173        test_expect_code 1 git pull . white &&
 174        test_path_is_file A
 175'
 176
 177test_expect_success 'interference with untracked working tree file' '
 178        git reset --hard &&
 179        git checkout white &&
 180        git show-branch &&
 181        rm -f A &&
 182        echo >A this file should not matter &&
 183        test_expect_code 1 git pull . red &&
 184        test_path_is_file A
 185'
 186
 187test_expect_success 'interference with untracked working tree file' '
 188        git reset --hard &&
 189        rm -f A M &&
 190        git checkout -f master &&
 191        git tag -f anchor &&
 192        git show-branch &&
 193        git pull . yellow &&
 194        test_path_is_missing M &&
 195        git reset --hard anchor
 196'
 197
 198test_expect_success 'updated working tree file should prevent the merge' '
 199        git reset --hard &&
 200        rm -f A M &&
 201        git checkout -f master &&
 202        git tag -f anchor &&
 203        git show-branch &&
 204        echo >>M one line addition &&
 205        cat M >M.saved &&
 206        test_expect_code 128 git pull . yellow &&
 207        test_cmp M M.saved &&
 208        rm -f M.saved
 209'
 210
 211test_expect_success 'updated working tree file should prevent the merge' '
 212        git reset --hard &&
 213        rm -f A M &&
 214        git checkout -f master &&
 215        git tag -f anchor &&
 216        git show-branch &&
 217        echo >>M one line addition &&
 218        cat M >M.saved &&
 219        git update-index M &&
 220        test_expect_code 128 git pull . yellow &&
 221        test_cmp M M.saved &&
 222        rm -f M.saved
 223'
 224
 225test_expect_success 'interference with untracked working tree file' '
 226        git reset --hard &&
 227        rm -f A M &&
 228        git checkout -f yellow &&
 229        git tag -f anchor &&
 230        git show-branch &&
 231        echo >M this file should not matter &&
 232        git pull . master &&
 233        test_path_is_file M &&
 234        ! {
 235                git ls-files -s |
 236                grep M
 237        } &&
 238        git reset --hard anchor
 239'
 240
 241test_expect_success 'merge of identical changes in a renamed file' '
 242        rm -f A M N &&
 243        git reset --hard &&
 244        git checkout change+rename &&
 245        GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" &&
 246        git reset --hard HEAD^ &&
 247        git checkout change &&
 248        GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B"
 249'
 250
 251test_expect_success 'setup for rename + d/f conflicts' '
 252        git reset --hard &&
 253        git checkout --orphan dir-in-way &&
 254        git rm -rf . &&
 255
 256        mkdir sub &&
 257        mkdir dir &&
 258        printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
 259        echo foo >dir/file-in-the-way &&
 260        git add -A &&
 261        git commit -m "Common commmit" &&
 262
 263        echo 11 >>sub/file &&
 264        echo more >>dir/file-in-the-way &&
 265        git add -u &&
 266        git commit -m "Commit to merge, with dir in the way" &&
 267
 268        git checkout -b dir-not-in-way &&
 269        git reset --soft HEAD^ &&
 270        git rm -rf dir &&
 271        git commit -m "Commit to merge, with dir removed" -- dir sub/file &&
 272
 273        git checkout -b renamed-file-has-no-conflicts dir-in-way~1 &&
 274        git rm -rf dir &&
 275        git rm sub/file &&
 276        printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n" >dir &&
 277        git add dir &&
 278        git commit -m "Independent change" &&
 279
 280        git checkout -b renamed-file-has-conflicts dir-in-way~1 &&
 281        git rm -rf dir &&
 282        git mv sub/file dir &&
 283        echo 12 >>dir &&
 284        git add dir &&
 285        git commit -m "Conflicting change"
 286'
 287
 288printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n11\n" >expected
 289
 290test_expect_success 'Rename+D/F conflict; renamed file merges + dir not in way' '
 291        git reset --hard &&
 292        git checkout -q renamed-file-has-no-conflicts^0 &&
 293        git merge --strategy=recursive dir-not-in-way &&
 294        git diff --quiet &&
 295        test -f dir &&
 296        test_cmp expected dir
 297'
 298
 299test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
 300        git reset --hard &&
 301        rm -rf dir~* &&
 302        git checkout -q renamed-file-has-no-conflicts^0 &&
 303        test_must_fail git merge --strategy=recursive dir-in-way >output &&
 304
 305        grep "CONFLICT (delete/modify): dir/file-in-the-way" output &&
 306        grep "Auto-merging dir" output &&
 307        grep "Adding as dir~HEAD instead" output &&
 308
 309        test 2 -eq "$(git ls-files -u | wc -l)" &&
 310        test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
 311
 312        test_must_fail git diff --quiet &&
 313        test_must_fail git diff --cached --quiet &&
 314
 315        test -f dir/file-in-the-way &&
 316        test -f dir~HEAD &&
 317        test_cmp expected dir~HEAD
 318'
 319
 320test_expect_success 'Same as previous, but merged other way' '
 321        git reset --hard &&
 322        rm -rf dir~* &&
 323        git checkout -q dir-in-way^0 &&
 324        test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
 325
 326        ! grep "error: refusing to lose untracked file at" errors &&
 327        grep "CONFLICT (delete/modify): dir/file-in-the-way" output &&
 328        grep "Auto-merging dir" output &&
 329        grep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
 330
 331        test 2 -eq "$(git ls-files -u | wc -l)" &&
 332        test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
 333
 334        test_must_fail git diff --quiet &&
 335        test_must_fail git diff --cached --quiet &&
 336
 337        test -f dir/file-in-the-way &&
 338        test -f dir~renamed-file-has-no-conflicts &&
 339        test_cmp expected dir~renamed-file-has-no-conflicts
 340'
 341
 342cat >expected <<\EOF &&
 3431
 3442
 3453
 3464
 3475
 3486
 3497
 3508
 3519
 35210
 353<<<<<<< HEAD
 35412
 355=======
 35611
 357>>>>>>> dir-not-in-way
 358EOF
 359
 360test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
 361        git reset --hard &&
 362        rm -rf dir~* &&
 363        git checkout -q renamed-file-has-conflicts^0 &&
 364        test_must_fail git merge --strategy=recursive dir-not-in-way &&
 365
 366        test 3 -eq "$(git ls-files -u | wc -l)" &&
 367        test 3 -eq "$(git ls-files -u dir | wc -l)" &&
 368
 369        test_must_fail git diff --quiet &&
 370        test_must_fail git diff --cached --quiet &&
 371
 372        test -f dir &&
 373        test_cmp expected dir
 374'
 375
 376test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in the way' '
 377        modify s/dir-not-in-way/dir-in-way/ expected &&
 378
 379        git reset --hard &&
 380        rm -rf dir~* &&
 381        git checkout -q renamed-file-has-conflicts^0 &&
 382        test_must_fail git merge --strategy=recursive dir-in-way &&
 383
 384        test 5 -eq "$(git ls-files -u | wc -l)" &&
 385        test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
 386        test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
 387
 388        test_must_fail git diff --quiet &&
 389        test_must_fail git diff --cached --quiet &&
 390
 391        test -f dir/file-in-the-way &&
 392        test -f dir~HEAD &&
 393        test_cmp expected dir~HEAD
 394'
 395
 396cat >expected <<\EOF &&
 3971
 3982
 3993
 4004
 4015
 4026
 4037
 4048
 4059
 40610
 407<<<<<<< HEAD
 40811
 409=======
 41012
 411>>>>>>> renamed-file-has-conflicts
 412EOF
 413
 414test_expect_success 'Same as previous, but merged other way' '
 415        git reset --hard &&
 416        rm -rf dir~* &&
 417        git checkout -q dir-in-way^0 &&
 418        test_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&
 419
 420        test 5 -eq "$(git ls-files -u | wc -l)" &&
 421        test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
 422        test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
 423
 424        test_must_fail git diff --quiet &&
 425        test_must_fail git diff --cached --quiet &&
 426
 427        test -f dir/file-in-the-way &&
 428        test -f dir~renamed-file-has-conflicts &&
 429        test_cmp expected dir~renamed-file-has-conflicts
 430'
 431
 432test_expect_success 'setup both rename source and destination involved in D/F conflict' '
 433        git reset --hard &&
 434        git checkout --orphan rename-dest &&
 435        git rm -rf . &&
 436        git clean -fdqx &&
 437
 438        mkdir one &&
 439        echo stuff >one/file &&
 440        git add -A &&
 441        git commit -m "Common commmit" &&
 442
 443        git mv one/file destdir &&
 444        git commit -m "Renamed to destdir" &&
 445
 446        git checkout -b source-conflict HEAD~1 &&
 447        git rm -rf one &&
 448        mkdir destdir &&
 449        touch one destdir/foo &&
 450        git add -A &&
 451        git commit -m "Conflicts in the way"
 452'
 453
 454test_expect_success 'both rename source and destination involved in D/F conflict' '
 455        git reset --hard &&
 456        rm -rf dir~* &&
 457        git checkout -q rename-dest^0 &&
 458        test_must_fail git merge --strategy=recursive source-conflict &&
 459
 460        test 1 -eq "$(git ls-files -u | wc -l)" &&
 461
 462        test_must_fail git diff --quiet &&
 463
 464        test -f destdir/foo &&
 465        test -f one &&
 466        test -f destdir~HEAD &&
 467        test "stuff" = "$(cat destdir~HEAD)"
 468'
 469
 470test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '
 471        git reset --hard &&
 472        git checkout --orphan rename-two &&
 473        git rm -rf . &&
 474        git clean -fdqx &&
 475
 476        mkdir one &&
 477        mkdir two &&
 478        echo stuff >one/file &&
 479        echo other >two/file &&
 480        git add -A &&
 481        git commit -m "Common commmit" &&
 482
 483        git rm -rf one &&
 484        git mv two/file one &&
 485        git commit -m "Rename two/file -> one" &&
 486
 487        git checkout -b rename-one HEAD~1 &&
 488        git rm -rf two &&
 489        git mv one/file two &&
 490        rm -r one &&
 491        git commit -m "Rename one/file -> two"
 492'
 493
 494test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '
 495        git checkout -q rename-one^0 &&
 496        mkdir one &&
 497        test_must_fail git merge --strategy=recursive rename-two &&
 498
 499        test 2 -eq "$(git ls-files -u | wc -l)" &&
 500        test 1 -eq "$(git ls-files -u one | wc -l)" &&
 501        test 1 -eq "$(git ls-files -u two | wc -l)" &&
 502
 503        test_must_fail git diff --quiet &&
 504
 505        test 4 -eq $(find . | grep -v .git | wc -l) &&
 506
 507        test -d one &&
 508        test -f one~rename-two &&
 509        test -f two &&
 510        test "other" = $(cat one~rename-two) &&
 511        test "stuff" = $(cat two)
 512'
 513
 514test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean start' '
 515        git reset --hard &&
 516        git clean -fdqx &&
 517        test_must_fail git merge --strategy=recursive rename-two &&
 518
 519        test 2 -eq "$(git ls-files -u | wc -l)" &&
 520        test 1 -eq "$(git ls-files -u one | wc -l)" &&
 521        test 1 -eq "$(git ls-files -u two | wc -l)" &&
 522
 523        test_must_fail git diff --quiet &&
 524
 525        test 3 -eq $(find . | grep -v .git | wc -l) &&
 526
 527        test -f one &&
 528        test -f two &&
 529        test "other" = $(cat one) &&
 530        test "stuff" = $(cat two)
 531'
 532
 533test_expect_success 'setup rename of one file to two, with directories in the way' '
 534        git reset --hard &&
 535        git checkout --orphan first-rename &&
 536        git rm -rf . &&
 537        git clean -fdqx &&
 538
 539        echo stuff >original &&
 540        git add -A &&
 541        git commit -m "Common commmit" &&
 542
 543        mkdir two &&
 544        >two/file &&
 545        git add two/file &&
 546        git mv original one &&
 547        git commit -m "Put two/file in the way, rename to one" &&
 548
 549        git checkout -b second-rename HEAD~1 &&
 550        mkdir one &&
 551        >one/file &&
 552        git add one/file &&
 553        git mv original two &&
 554        git commit -m "Put one/file in the way, rename to two"
 555'
 556
 557test_expect_success 'check handling of differently renamed file with D/F conflicts' '
 558        git checkout -q first-rename^0 &&
 559        test_must_fail git merge --strategy=recursive second-rename &&
 560
 561        test 5 -eq "$(git ls-files -s | wc -l)" &&
 562        test 3 -eq "$(git ls-files -u | wc -l)" &&
 563        test 1 -eq "$(git ls-files -u one | wc -l)" &&
 564        test 1 -eq "$(git ls-files -u two | wc -l)" &&
 565        test 1 -eq "$(git ls-files -u original | wc -l)" &&
 566        test 2 -eq "$(git ls-files -o | wc -l)" &&
 567
 568        test -f one/file &&
 569        test -f two/file &&
 570        test -f one~HEAD &&
 571        test -f two~second-rename &&
 572        ! test -f original
 573'
 574
 575test_expect_success 'setup rename one file to two; directories moving out of the way' '
 576        git reset --hard &&
 577        git checkout --orphan first-rename-redo &&
 578        git rm -rf . &&
 579        git clean -fdqx &&
 580
 581        echo stuff >original &&
 582        mkdir one two &&
 583        touch one/file two/file &&
 584        git add -A &&
 585        git commit -m "Common commmit" &&
 586
 587        git rm -rf one &&
 588        git mv original one &&
 589        git commit -m "Rename to one" &&
 590
 591        git checkout -b second-rename-redo HEAD~1 &&
 592        git rm -rf two &&
 593        git mv original two &&
 594        git commit -m "Rename to two"
 595'
 596
 597test_expect_success 'check handling of differently renamed file with D/F conflicts' '
 598        git checkout -q first-rename-redo^0 &&
 599        test_must_fail git merge --strategy=recursive second-rename-redo &&
 600
 601        test 3 -eq "$(git ls-files -u | wc -l)" &&
 602        test 1 -eq "$(git ls-files -u one | wc -l)" &&
 603        test 1 -eq "$(git ls-files -u two | wc -l)" &&
 604        test 1 -eq "$(git ls-files -u original | wc -l)" &&
 605        test 0 -eq "$(git ls-files -o | wc -l)" &&
 606
 607        test -f one &&
 608        test -f two &&
 609        ! test -f original
 610'
 611
 612test_done