t / t4200-rerere.shon commit Merge branch 'master' of https://github.com/vnwildman/git (26a567e)
   1#!/bin/sh
   2#
   3# Copyright (c) 2006 Johannes E. Schindelin
   4#
   5
   6test_description='git rerere
   7
   8! [fifth] version1
   9 ! [first] first
  10  ! [fourth] version1
  11   ! [master] initial
  12    ! [second] prefer first over second
  13     ! [third] version2
  14------
  15     + [third] version2
  16+      [fifth] version1
  17  +    [fourth] version1
  18+ +  + [third^] third
  19    -  [second] prefer first over second
  20 +  +  [first] first
  21    +  [second^] second
  22++++++ [master] initial
  23'
  24
  25. ./test-lib.sh
  26
  27test_expect_success 'setup' '
  28        cat >a1 <<-\EOF &&
  29        Some title
  30        ==========
  31        Whether '\''tis nobler in the mind to suffer
  32        The slings and arrows of outrageous fortune,
  33        Or to take arms against a sea of troubles,
  34        And by opposing end them? To die: to sleep;
  35        No more; and by a sleep to say we end
  36        The heart-ache and the thousand natural shocks
  37        That flesh is heir to, '\''tis a consummation
  38        Devoutly to be wish'\''d.
  39        EOF
  40
  41        git add a1 &&
  42        test_tick &&
  43        git commit -q -a -m initial &&
  44
  45        cat >>a1 <<-\EOF &&
  46        Some title
  47        ==========
  48        To die, to sleep;
  49        To sleep: perchance to dream: ay, there'\''s the rub;
  50        For in that sleep of death what dreams may come
  51        When we have shuffled off this mortal coil,
  52        Must give us pause: there'\''s the respect
  53        That makes calamity of so long life;
  54        EOF
  55
  56        git checkout -b first &&
  57        test_tick &&
  58        git commit -q -a -m first &&
  59
  60        git checkout -b second master &&
  61        git show first:a1 |
  62        sed -e "s/To die, t/To die! T/" -e "s/Some title/Some Title/" >a1 &&
  63        echo "* END *" >>a1 &&
  64        test_tick &&
  65        git commit -q -a -m second
  66'
  67
  68test_expect_success 'nothing recorded without rerere' '
  69        rm -rf .git/rr-cache &&
  70        git config rerere.enabled false &&
  71        test_must_fail git merge first &&
  72        ! test -d .git/rr-cache
  73'
  74
  75test_expect_success 'activate rerere, old style (conflicting merge)' '
  76        git reset --hard &&
  77        mkdir .git/rr-cache &&
  78        test_might_fail git config --unset rerere.enabled &&
  79        test_must_fail git merge first &&
  80
  81        sha1=$(perl -pe "s/     .*//" .git/MERGE_RR) &&
  82        rr=.git/rr-cache/$sha1 &&
  83        grep "^=======\$" $rr/preimage &&
  84        ! test -f $rr/postimage &&
  85        ! test -f $rr/thisimage
  86'
  87
  88test_expect_success 'rerere.enabled works, too' '
  89        rm -rf .git/rr-cache &&
  90        git config rerere.enabled true &&
  91        git reset --hard &&
  92        test_must_fail git merge first &&
  93
  94        sha1=$(perl -pe "s/     .*//" .git/MERGE_RR) &&
  95        rr=.git/rr-cache/$sha1 &&
  96        grep ^=======$ $rr/preimage
  97'
  98
  99test_expect_success 'set up rr-cache' '
 100        rm -rf .git/rr-cache &&
 101        git config rerere.enabled true &&
 102        git reset --hard &&
 103        test_must_fail git merge first &&
 104        sha1=$(perl -pe "s/     .*//" .git/MERGE_RR) &&
 105        rr=.git/rr-cache/$sha1
 106'
 107
 108test_expect_success 'rr-cache looks sane' '
 109        # no postimage or thisimage yet
 110        ! test -f $rr/postimage &&
 111        ! test -f $rr/thisimage &&
 112
 113        # preimage has right number of lines
 114        cnt=$(sed -ne "/^<<<<<<</,/^>>>>>>>/p" $rr/preimage | wc -l) &&
 115        echo $cnt &&
 116        test $cnt = 13
 117'
 118
 119test_expect_success 'rerere diff' '
 120        git show first:a1 >a1 &&
 121        cat >expect <<-\EOF &&
 122        --- a/a1
 123        +++ b/a1
 124        @@ -1,4 +1,4 @@
 125        -Some Title
 126        +Some title
 127         ==========
 128         Whether '\''tis nobler in the mind to suffer
 129         The slings and arrows of outrageous fortune,
 130        @@ -8,21 +8,11 @@
 131         The heart-ache and the thousand natural shocks
 132         That flesh is heir to, '\''tis a consummation
 133         Devoutly to be wish'\''d.
 134        -<<<<<<<
 135        -Some Title
 136        -==========
 137        -To die! To sleep;
 138        -=======
 139         Some title
 140         ==========
 141         To die, to sleep;
 142        ->>>>>>>
 143         To sleep: perchance to dream: ay, there'\''s the rub;
 144         For in that sleep of death what dreams may come
 145         When we have shuffled off this mortal coil,
 146         Must give us pause: there'\''s the respect
 147         That makes calamity of so long life;
 148        -<<<<<<<
 149        -=======
 150        -* END *
 151        ->>>>>>>
 152        EOF
 153        git rerere diff >out &&
 154        test_cmp expect out
 155'
 156
 157test_expect_success 'rerere status' '
 158        echo a1 >expect &&
 159        git rerere status >out &&
 160        test_cmp expect out
 161'
 162
 163test_expect_success 'first postimage wins' '
 164        git show first:a1 | sed "s/To die: t/To die! T/" >expect &&
 165
 166        git commit -q -a -m "prefer first over second" &&
 167        test -f $rr/postimage &&
 168
 169        oldmtimepost=$(test-tool chmtime --get -60 $rr/postimage) &&
 170
 171        git checkout -b third master &&
 172        git show second^:a1 | sed "s/To die: t/To die! T/" >a1 &&
 173        git commit -q -a -m third &&
 174
 175        test_must_fail git merge first &&
 176        # rerere kicked in
 177        ! grep "^=======\$" a1 &&
 178        test_cmp expect a1
 179'
 180
 181test_expect_success 'rerere updates postimage timestamp' '
 182        newmtimepost=$(test-tool chmtime --get $rr/postimage) &&
 183        test $oldmtimepost -lt $newmtimepost
 184'
 185
 186test_expect_success 'rerere clear' '
 187        mv $rr/postimage .git/post-saved &&
 188        echo "$sha1     a1" | perl -pe "y/\012/\000/" >.git/MERGE_RR &&
 189        git rerere clear &&
 190        ! test -d $rr
 191'
 192
 193test_expect_success 'leftover directory' '
 194        git reset --hard &&
 195        mkdir -p $rr &&
 196        test_must_fail git merge first &&
 197        test -f $rr/preimage
 198'
 199
 200test_expect_success 'missing preimage' '
 201        git reset --hard &&
 202        mkdir -p $rr &&
 203        cp .git/post-saved $rr/postimage &&
 204        test_must_fail git merge first &&
 205        test -f $rr/preimage
 206'
 207
 208test_expect_success 'set up for garbage collection tests' '
 209        mkdir -p $rr &&
 210        echo Hello >$rr/preimage &&
 211        echo World >$rr/postimage &&
 212
 213        sha2=4000000000000000000000000000000000000000 &&
 214        rr2=.git/rr-cache/$sha2 &&
 215        mkdir $rr2 &&
 216        echo Hello >$rr2/preimage &&
 217
 218        almost_15_days_ago=$((60-15*86400)) &&
 219        just_over_15_days_ago=$((-1-15*86400)) &&
 220        almost_60_days_ago=$((60-60*86400)) &&
 221        just_over_60_days_ago=$((-1-60*86400)) &&
 222
 223        test-tool chmtime =$just_over_60_days_ago $rr/preimage &&
 224        test-tool chmtime =$almost_60_days_ago $rr/postimage &&
 225        test-tool chmtime =$almost_15_days_ago $rr2/preimage
 226'
 227
 228test_expect_success 'gc preserves young or recently used records' '
 229        git rerere gc &&
 230        test -f $rr/preimage &&
 231        test -f $rr2/preimage
 232'
 233
 234test_expect_success 'old records rest in peace' '
 235        test-tool chmtime =$just_over_60_days_ago $rr/postimage &&
 236        test-tool chmtime =$just_over_15_days_ago $rr2/preimage &&
 237        git rerere gc &&
 238        ! test -f $rr/preimage &&
 239        ! test -f $rr2/preimage
 240'
 241
 242rerere_gc_custom_expiry_test () {
 243        five_days="$1" right_now="$2"
 244        test_expect_success "rerere gc with custom expiry ($five_days, $right_now)" '
 245                rm -fr .git/rr-cache &&
 246                rr=.git/rr-cache/$ZERO_OID &&
 247                mkdir -p "$rr" &&
 248                >"$rr/preimage" &&
 249                >"$rr/postimage" &&
 250
 251                two_days_ago=$((-2*86400)) &&
 252                test-tool chmtime =$two_days_ago "$rr/preimage" &&
 253                test-tool chmtime =$two_days_ago "$rr/postimage" &&
 254
 255                find .git/rr-cache -type f | sort >original &&
 256
 257                git -c "gc.rerereresolved=$five_days" \
 258                    -c "gc.rerereunresolved=$five_days" rerere gc &&
 259                find .git/rr-cache -type f | sort >actual &&
 260                test_cmp original actual &&
 261
 262                git -c "gc.rerereresolved=$five_days" \
 263                    -c "gc.rerereunresolved=$right_now" rerere gc &&
 264                find .git/rr-cache -type f | sort >actual &&
 265                test_cmp original actual &&
 266
 267                git -c "gc.rerereresolved=$right_now" \
 268                    -c "gc.rerereunresolved=$right_now" rerere gc &&
 269                find .git/rr-cache -type f | sort >actual &&
 270                test_must_be_empty actual
 271        '
 272}
 273
 274rerere_gc_custom_expiry_test 5 0
 275
 276rerere_gc_custom_expiry_test 5.days.ago now
 277
 278test_expect_success 'setup: file2 added differently in two branches' '
 279        git reset --hard &&
 280
 281        git checkout -b fourth &&
 282        echo Hallo >file2 &&
 283        git add file2 &&
 284        test_tick &&
 285        git commit -m version1 &&
 286
 287        git checkout third &&
 288        echo Bello >file2 &&
 289        git add file2 &&
 290        test_tick &&
 291        git commit -m version2 &&
 292
 293        test_must_fail git merge fourth &&
 294        echo Cello >file2 &&
 295        git add file2 &&
 296        git commit -m resolution
 297'
 298
 299test_expect_success 'resolution was recorded properly' '
 300        echo Cello >expected &&
 301
 302        git reset --hard HEAD~2 &&
 303        git checkout -b fifth &&
 304
 305        echo Hallo >file3 &&
 306        git add file3 &&
 307        test_tick &&
 308        git commit -m version1 &&
 309
 310        git checkout third &&
 311        echo Bello >file3 &&
 312        git add file3 &&
 313        test_tick &&
 314        git commit -m version2 &&
 315        git tag version2 &&
 316
 317        test_must_fail git merge fifth &&
 318        test_cmp expected file3 &&
 319        test_must_fail git update-index --refresh
 320'
 321
 322test_expect_success 'rerere.autoupdate' '
 323        git config rerere.autoupdate true &&
 324        git reset --hard &&
 325        git checkout version2 &&
 326        test_must_fail git merge fifth &&
 327        git update-index --refresh
 328'
 329
 330test_expect_success 'merge --rerere-autoupdate' '
 331        test_might_fail git config --unset rerere.autoupdate &&
 332        git reset --hard &&
 333        git checkout version2 &&
 334        test_must_fail git merge --rerere-autoupdate fifth &&
 335        git update-index --refresh
 336'
 337
 338test_expect_success 'merge --no-rerere-autoupdate' '
 339        headblob=$(git rev-parse version2:file3) &&
 340        mergeblob=$(git rev-parse fifth:file3) &&
 341        cat >expected <<-EOF &&
 342        100644 $headblob 2      file3
 343        100644 $mergeblob 3     file3
 344        EOF
 345
 346        git config rerere.autoupdate true &&
 347        git reset --hard &&
 348        git checkout version2 &&
 349        test_must_fail git merge --no-rerere-autoupdate fifth &&
 350        git ls-files -u >actual &&
 351        test_cmp expected actual
 352'
 353
 354test_expect_success 'set up an unresolved merge' '
 355        headblob=$(git rev-parse version2:file3) &&
 356        mergeblob=$(git rev-parse fifth:file3) &&
 357        cat >expected.unresolved <<-EOF &&
 358        100644 $headblob 2      file3
 359        100644 $mergeblob 3     file3
 360        EOF
 361
 362        test_might_fail git config --unset rerere.autoupdate &&
 363        git reset --hard &&
 364        git checkout version2 &&
 365        fifth=$(git rev-parse fifth) &&
 366        echo "$fifth            branch 'fifth' of ." |
 367        git fmt-merge-msg >msg &&
 368        ancestor=$(git merge-base version2 fifth) &&
 369        test_must_fail git merge-recursive "$ancestor" -- HEAD fifth &&
 370
 371        git ls-files --stage >failedmerge &&
 372        cp file3 file3.conflict &&
 373
 374        git ls-files -u >actual &&
 375        test_cmp expected.unresolved actual
 376'
 377
 378test_expect_success 'explicit rerere' '
 379        test_might_fail git config --unset rerere.autoupdate &&
 380        git rm -fr --cached . &&
 381        git update-index --index-info <failedmerge &&
 382        cp file3.conflict file3 &&
 383        test_must_fail git update-index --refresh -q &&
 384
 385        git rerere &&
 386        git ls-files -u >actual &&
 387        test_cmp expected.unresolved actual
 388'
 389
 390test_expect_success 'explicit rerere with autoupdate' '
 391        git config rerere.autoupdate true &&
 392        git rm -fr --cached . &&
 393        git update-index --index-info <failedmerge &&
 394        cp file3.conflict file3 &&
 395        test_must_fail git update-index --refresh -q &&
 396
 397        git rerere &&
 398        git update-index --refresh
 399'
 400
 401test_expect_success 'explicit rerere --rerere-autoupdate overrides' '
 402        git config rerere.autoupdate false &&
 403        git rm -fr --cached . &&
 404        git update-index --index-info <failedmerge &&
 405        cp file3.conflict file3 &&
 406        git rerere &&
 407        git ls-files -u >actual1 &&
 408
 409        git rm -fr --cached . &&
 410        git update-index --index-info <failedmerge &&
 411        cp file3.conflict file3 &&
 412        git rerere --rerere-autoupdate &&
 413        git update-index --refresh &&
 414
 415        git rm -fr --cached . &&
 416        git update-index --index-info <failedmerge &&
 417        cp file3.conflict file3 &&
 418        git rerere --rerere-autoupdate --no-rerere-autoupdate &&
 419        git ls-files -u >actual2 &&
 420
 421        git rm -fr --cached . &&
 422        git update-index --index-info <failedmerge &&
 423        cp file3.conflict file3 &&
 424        git rerere --rerere-autoupdate --no-rerere-autoupdate --rerere-autoupdate &&
 425        git update-index --refresh &&
 426
 427        test_cmp expected.unresolved actual1 &&
 428        test_cmp expected.unresolved actual2
 429'
 430
 431test_expect_success 'rerere --no-no-rerere-autoupdate' '
 432        git rm -fr --cached . &&
 433        git update-index --index-info <failedmerge &&
 434        cp file3.conflict file3 &&
 435        test_must_fail git rerere --no-no-rerere-autoupdate 2>err &&
 436        test_i18ngrep [Uu]sage err &&
 437        test_must_fail git update-index --refresh
 438'
 439
 440test_expect_success 'rerere -h' '
 441        test_must_fail git rerere -h >help &&
 442        test_i18ngrep [Uu]sage help
 443'
 444
 445concat_insert () {
 446        last=$1
 447        shift
 448        cat early && printf "%s\n" "$@" && cat late "$last"
 449}
 450
 451count_pre_post () {
 452        find .git/rr-cache/ -type f -name "preimage*" >actual &&
 453        test_line_count = "$1" actual &&
 454        find .git/rr-cache/ -type f -name "postimage*" >actual &&
 455        test_line_count = "$2" actual
 456}
 457
 458merge_conflict_resolve () {
 459        git reset --hard &&
 460        test_must_fail git merge six.1 &&
 461        # Resolution is to replace 7 with 6.1 and 6.2 (i.e. take both)
 462        concat_insert short 6.1 6.2 >file1 &&
 463        concat_insert long 6.1 6.2 >file2
 464}
 465
 466test_expect_success 'multiple identical conflicts' '
 467        rm -fr .git/rr-cache &&
 468        mkdir .git/rr-cache &&
 469        git reset --hard &&
 470
 471        test_seq 1 6 >early &&
 472        >late &&
 473        test_seq 11 15 >short &&
 474        test_seq 111 120 >long &&
 475        concat_insert short >file1 &&
 476        concat_insert long >file2 &&
 477        git add file1 file2 &&
 478        git commit -m base &&
 479        git tag base &&
 480        git checkout -b six.1 &&
 481        concat_insert short 6.1 >file1 &&
 482        concat_insert long 6.1 >file2 &&
 483        git add file1 file2 &&
 484        git commit -m 6.1 &&
 485        git checkout -b six.2 HEAD^ &&
 486        concat_insert short 6.2 >file1 &&
 487        concat_insert long 6.2 >file2 &&
 488        git add file1 file2 &&
 489        git commit -m 6.2 &&
 490
 491        # At this point, six.1 and six.2
 492        # - derive from common ancestor that has two files
 493        #   1...6 7 11..15 (file1) and 1...6 7 111..120 (file2)
 494        # - six.1 replaces these 7s with 6.1
 495        # - six.2 replaces these 7s with 6.2
 496
 497        merge_conflict_resolve &&
 498
 499        # Check that rerere knows that file1 and file2 have conflicts
 500
 501        printf "%s\n" file1 file2 >expect &&
 502        git ls-files -u | sed -e "s/^.* //" | sort -u >actual &&
 503        test_cmp expect actual &&
 504
 505        git rerere status | sort >actual &&
 506        test_cmp expect actual &&
 507
 508        git rerere remaining >actual &&
 509        test_cmp expect actual &&
 510
 511        count_pre_post 2 0 &&
 512
 513        # Pretend that the conflicts were made quite some time ago
 514        test-tool chmtime -172800 $(find .git/rr-cache/ -type f) &&
 515
 516        # Unresolved entries have not expired yet
 517        git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
 518        count_pre_post 2 0 &&
 519
 520        # Unresolved entries have expired
 521        git -c gc.rerereresolved=5 -c gc.rerereunresolved=1 rerere gc &&
 522        count_pre_post 0 0 &&
 523
 524        # Recreate the conflicted state
 525        merge_conflict_resolve &&
 526        count_pre_post 2 0 &&
 527
 528        # Clear it
 529        git rerere clear &&
 530        count_pre_post 0 0 &&
 531
 532        # Recreate the conflicted state
 533        merge_conflict_resolve &&
 534        count_pre_post 2 0 &&
 535
 536        # We resolved file1 and file2
 537        git rerere &&
 538        git rerere remaining >actual &&
 539        test_must_be_empty actual &&
 540
 541        # We must have recorded both of them
 542        count_pre_post 2 2 &&
 543
 544        # Now we should be able to resolve them both
 545        git reset --hard &&
 546        test_must_fail git merge six.1 &&
 547        git rerere &&
 548
 549        git rerere remaining >actual &&
 550        test_must_be_empty actual &&
 551
 552        concat_insert short 6.1 6.2 >file1.expect &&
 553        concat_insert long 6.1 6.2 >file2.expect &&
 554        test_cmp file1.expect file1 &&
 555        test_cmp file2.expect file2 &&
 556
 557        # Forget resolution for file2
 558        git rerere forget file2 &&
 559        echo file2 >expect &&
 560        git rerere status >actual &&
 561        test_cmp expect actual &&
 562        count_pre_post 2 1 &&
 563
 564        # file2 already has correct resolution, so record it again
 565        git rerere &&
 566
 567        # Pretend that the resolutions are old again
 568        test-tool chmtime -172800 $(find .git/rr-cache/ -type f) &&
 569
 570        # Resolved entries have not expired yet
 571        git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
 572
 573        count_pre_post 2 2 &&
 574
 575        # Resolved entries have expired
 576        git -c gc.rerereresolved=1 -c gc.rerereunresolved=5 rerere gc &&
 577        count_pre_post 0 0
 578'
 579
 580test_expect_success 'rerere with unexpected conflict markers does not crash' '
 581        git reset --hard &&
 582
 583        git checkout -b branch-1 master &&
 584        echo "bar" >test &&
 585        git add test &&
 586        git commit -q -m two &&
 587
 588        git reset --hard &&
 589        git checkout -b branch-2 master &&
 590        echo "foo" >test &&
 591        git add test &&
 592        git commit -q -a -m one &&
 593
 594        test_must_fail git merge branch-1 &&
 595        echo "<<<<<<< a" >test &&
 596        git rerere &&
 597
 598        git rerere clear
 599'
 600
 601test_expect_success 'rerere with inner conflict markers' '
 602        git reset --hard &&
 603
 604        git checkout -b A master &&
 605        echo "bar" >test &&
 606        git add test &&
 607        git commit -q -m two &&
 608        echo "baz" >test &&
 609        git add test &&
 610        git commit -q -m three &&
 611
 612        git reset --hard &&
 613        git checkout -b B master &&
 614        echo "foo" >test &&
 615        git add test &&
 616        git commit -q -a -m one &&
 617
 618        test_must_fail git merge A~ &&
 619        git add test &&
 620        git commit -q -m "will solve conflicts later" &&
 621        test_must_fail git merge A &&
 622
 623        echo "resolved" >test &&
 624        git add test &&
 625        git commit -q -m "solved conflict" &&
 626
 627        echo "resolved" >expect &&
 628
 629        git reset --hard HEAD~~ &&
 630        test_must_fail git merge A~ &&
 631        git add test &&
 632        git commit -q -m "will solve conflicts later" &&
 633        test_must_fail git merge A &&
 634        cat test >actual &&
 635        test_cmp expect actual &&
 636
 637        git add test &&
 638        git commit -m "rerere solved conflict" &&
 639        git reset --hard HEAD~ &&
 640        test_must_fail git merge A &&
 641        cat test >actual &&
 642        test_cmp expect actual
 643'
 644
 645test_expect_success 'setup simple stage 1 handling' '
 646        test_create_repo stage_1_handling &&
 647        (
 648                cd stage_1_handling &&
 649
 650                test_seq 1 10 >original &&
 651                git add original &&
 652                git commit -m original &&
 653
 654                git checkout -b A master &&
 655                git mv original A &&
 656                git commit -m "rename to A" &&
 657
 658                git checkout -b B master &&
 659                git mv original B &&
 660                git commit -m "rename to B"
 661        )
 662'
 663
 664test_expect_success 'test simple stage 1 handling' '
 665        (
 666                cd stage_1_handling &&
 667
 668                git config rerere.enabled true &&
 669                git checkout A^0 &&
 670                test_must_fail git merge B^0
 671        )
 672'
 673
 674test_done