t / t4200-rerere.shon commit send-email: support separate Reply-To address (d11c943)
   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-chmtime -v -60 $rr/postimage | cut -f 1) &&
 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-chmtime -v +0 $rr/postimage | cut -f 1) &&
 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-chmtime =$just_over_60_days_ago $rr/preimage &&
 224        test-chmtime =$almost_60_days_ago $rr/postimage &&
 225        test-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-chmtime =$just_over_60_days_ago $rr/postimage &&
 236        test-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/$_z40 &&
 247                mkdir -p "$rr" &&
 248                >"$rr/preimage" &&
 249                >"$rr/postimage" &&
 250
 251                two_days_ago=$((-2*86400)) &&
 252                test-chmtime =$two_days_ago "$rr/preimage" &&
 253                test-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                >expect &&
 271                test_cmp expect actual
 272        '
 273}
 274
 275rerere_gc_custom_expiry_test 5 0
 276
 277rerere_gc_custom_expiry_test 5.days.ago now
 278
 279test_expect_success 'setup: file2 added differently in two branches' '
 280        git reset --hard &&
 281
 282        git checkout -b fourth &&
 283        echo Hallo >file2 &&
 284        git add file2 &&
 285        test_tick &&
 286        git commit -m version1 &&
 287
 288        git checkout third &&
 289        echo Bello >file2 &&
 290        git add file2 &&
 291        test_tick &&
 292        git commit -m version2 &&
 293
 294        test_must_fail git merge fourth &&
 295        echo Cello >file2 &&
 296        git add file2 &&
 297        git commit -m resolution
 298'
 299
 300test_expect_success 'resolution was recorded properly' '
 301        echo Cello >expected &&
 302
 303        git reset --hard HEAD~2 &&
 304        git checkout -b fifth &&
 305
 306        echo Hallo >file3 &&
 307        git add file3 &&
 308        test_tick &&
 309        git commit -m version1 &&
 310
 311        git checkout third &&
 312        echo Bello >file3 &&
 313        git add file3 &&
 314        test_tick &&
 315        git commit -m version2 &&
 316        git tag version2 &&
 317
 318        test_must_fail git merge fifth &&
 319        test_cmp expected file3 &&
 320        test_must_fail git update-index --refresh
 321'
 322
 323test_expect_success 'rerere.autoupdate' '
 324        git config rerere.autoupdate true &&
 325        git reset --hard &&
 326        git checkout version2 &&
 327        test_must_fail git merge fifth &&
 328        git update-index --refresh
 329'
 330
 331test_expect_success 'merge --rerere-autoupdate' '
 332        test_might_fail git config --unset rerere.autoupdate &&
 333        git reset --hard &&
 334        git checkout version2 &&
 335        test_must_fail git merge --rerere-autoupdate fifth &&
 336        git update-index --refresh
 337'
 338
 339test_expect_success 'merge --no-rerere-autoupdate' '
 340        headblob=$(git rev-parse version2:file3) &&
 341        mergeblob=$(git rev-parse fifth:file3) &&
 342        cat >expected <<-EOF &&
 343        100644 $headblob 2      file3
 344        100644 $mergeblob 3     file3
 345        EOF
 346
 347        git config rerere.autoupdate true &&
 348        git reset --hard &&
 349        git checkout version2 &&
 350        test_must_fail git merge --no-rerere-autoupdate fifth &&
 351        git ls-files -u >actual &&
 352        test_cmp expected actual
 353'
 354
 355test_expect_success 'set up an unresolved merge' '
 356        headblob=$(git rev-parse version2:file3) &&
 357        mergeblob=$(git rev-parse fifth:file3) &&
 358        cat >expected.unresolved <<-EOF &&
 359        100644 $headblob 2      file3
 360        100644 $mergeblob 3     file3
 361        EOF
 362
 363        test_might_fail git config --unset rerere.autoupdate &&
 364        git reset --hard &&
 365        git checkout version2 &&
 366        fifth=$(git rev-parse fifth) &&
 367        echo "$fifth            branch 'fifth' of ." |
 368        git fmt-merge-msg >msg &&
 369        ancestor=$(git merge-base version2 fifth) &&
 370        test_must_fail git merge-recursive "$ancestor" -- HEAD fifth &&
 371
 372        git ls-files --stage >failedmerge &&
 373        cp file3 file3.conflict &&
 374
 375        git ls-files -u >actual &&
 376        test_cmp expected.unresolved actual
 377'
 378
 379test_expect_success 'explicit rerere' '
 380        test_might_fail git config --unset rerere.autoupdate &&
 381        git rm -fr --cached . &&
 382        git update-index --index-info <failedmerge &&
 383        cp file3.conflict file3 &&
 384        test_must_fail git update-index --refresh -q &&
 385
 386        git rerere &&
 387        git ls-files -u >actual &&
 388        test_cmp expected.unresolved actual
 389'
 390
 391test_expect_success 'explicit rerere with autoupdate' '
 392        git config rerere.autoupdate true &&
 393        git rm -fr --cached . &&
 394        git update-index --index-info <failedmerge &&
 395        cp file3.conflict file3 &&
 396        test_must_fail git update-index --refresh -q &&
 397
 398        git rerere &&
 399        git update-index --refresh
 400'
 401
 402test_expect_success 'explicit rerere --rerere-autoupdate overrides' '
 403        git config rerere.autoupdate false &&
 404        git rm -fr --cached . &&
 405        git update-index --index-info <failedmerge &&
 406        cp file3.conflict file3 &&
 407        git rerere &&
 408        git ls-files -u >actual1 &&
 409
 410        git rm -fr --cached . &&
 411        git update-index --index-info <failedmerge &&
 412        cp file3.conflict file3 &&
 413        git rerere --rerere-autoupdate &&
 414        git update-index --refresh &&
 415
 416        git rm -fr --cached . &&
 417        git update-index --index-info <failedmerge &&
 418        cp file3.conflict file3 &&
 419        git rerere --rerere-autoupdate --no-rerere-autoupdate &&
 420        git ls-files -u >actual2 &&
 421
 422        git rm -fr --cached . &&
 423        git update-index --index-info <failedmerge &&
 424        cp file3.conflict file3 &&
 425        git rerere --rerere-autoupdate --no-rerere-autoupdate --rerere-autoupdate &&
 426        git update-index --refresh &&
 427
 428        test_cmp expected.unresolved actual1 &&
 429        test_cmp expected.unresolved actual2
 430'
 431
 432test_expect_success 'rerere --no-no-rerere-autoupdate' '
 433        git rm -fr --cached . &&
 434        git update-index --index-info <failedmerge &&
 435        cp file3.conflict file3 &&
 436        test_must_fail git rerere --no-no-rerere-autoupdate 2>err &&
 437        test_i18ngrep [Uu]sage err &&
 438        test_must_fail git update-index --refresh
 439'
 440
 441test_expect_success 'rerere -h' '
 442        test_must_fail git rerere -h >help &&
 443        test_i18ngrep [Uu]sage help
 444'
 445
 446concat_insert () {
 447        last=$1
 448        shift
 449        cat early && printf "%s\n" "$@" && cat late "$last"
 450}
 451
 452count_pre_post () {
 453        find .git/rr-cache/ -type f -name "preimage*" >actual &&
 454        test_line_count = "$1" actual &&
 455        find .git/rr-cache/ -type f -name "postimage*" >actual &&
 456        test_line_count = "$2" actual
 457}
 458
 459merge_conflict_resolve () {
 460        git reset --hard &&
 461        test_must_fail git merge six.1 &&
 462        # Resolution is to replace 7 with 6.1 and 6.2 (i.e. take both)
 463        concat_insert short 6.1 6.2 >file1 &&
 464        concat_insert long 6.1 6.2 >file2
 465}
 466
 467test_expect_success 'multiple identical conflicts' '
 468        rm -fr .git/rr-cache &&
 469        mkdir .git/rr-cache &&
 470        git reset --hard &&
 471
 472        test_seq 1 6 >early &&
 473        >late &&
 474        test_seq 11 15 >short &&
 475        test_seq 111 120 >long &&
 476        concat_insert short >file1 &&
 477        concat_insert long >file2 &&
 478        git add file1 file2 &&
 479        git commit -m base &&
 480        git tag base &&
 481        git checkout -b six.1 &&
 482        concat_insert short 6.1 >file1 &&
 483        concat_insert long 6.1 >file2 &&
 484        git add file1 file2 &&
 485        git commit -m 6.1 &&
 486        git checkout -b six.2 HEAD^ &&
 487        concat_insert short 6.2 >file1 &&
 488        concat_insert long 6.2 >file2 &&
 489        git add file1 file2 &&
 490        git commit -m 6.2 &&
 491
 492        # At this point, six.1 and six.2
 493        # - derive from common ancestor that has two files
 494        #   1...6 7 11..15 (file1) and 1...6 7 111..120 (file2)
 495        # - six.1 replaces these 7s with 6.1
 496        # - six.2 replaces these 7s with 6.2
 497
 498        merge_conflict_resolve &&
 499
 500        # Check that rerere knows that file1 and file2 have conflicts
 501
 502        printf "%s\n" file1 file2 >expect &&
 503        git ls-files -u | sed -e "s/^.* //" | sort -u >actual &&
 504        test_cmp expect actual &&
 505
 506        git rerere status | sort >actual &&
 507        test_cmp expect actual &&
 508
 509        git rerere remaining >actual &&
 510        test_cmp expect actual &&
 511
 512        count_pre_post 2 0 &&
 513
 514        # Pretend that the conflicts were made quite some time ago
 515        find .git/rr-cache/ -type f | xargs test-chmtime -172800 &&
 516
 517        # Unresolved entries have not expired yet
 518        git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
 519        count_pre_post 2 0 &&
 520
 521        # Unresolved entries have expired
 522        git -c gc.rerereresolved=5 -c gc.rerereunresolved=1 rerere gc &&
 523        count_pre_post 0 0 &&
 524
 525        # Recreate the conflicted state
 526        merge_conflict_resolve &&
 527        count_pre_post 2 0 &&
 528
 529        # Clear it
 530        git rerere clear &&
 531        count_pre_post 0 0 &&
 532
 533        # Recreate the conflicted state
 534        merge_conflict_resolve &&
 535        count_pre_post 2 0 &&
 536
 537        # We resolved file1 and file2
 538        git rerere &&
 539        >expect &&
 540        git rerere remaining >actual &&
 541        test_cmp expect actual &&
 542
 543        # We must have recorded both of them
 544        count_pre_post 2 2 &&
 545
 546        # Now we should be able to resolve them both
 547        git reset --hard &&
 548        test_must_fail git merge six.1 &&
 549        git rerere &&
 550
 551        >expect &&
 552        git rerere remaining >actual &&
 553        test_cmp expect actual &&
 554
 555        concat_insert short 6.1 6.2 >file1.expect &&
 556        concat_insert long 6.1 6.2 >file2.expect &&
 557        test_cmp file1.expect file1 &&
 558        test_cmp file2.expect file2 &&
 559
 560        # Forget resolution for file2
 561        git rerere forget file2 &&
 562        echo file2 >expect &&
 563        git rerere status >actual &&
 564        test_cmp expect actual &&
 565        count_pre_post 2 1 &&
 566
 567        # file2 already has correct resolution, so record it again
 568        git rerere &&
 569
 570        # Pretend that the resolutions are old again
 571        find .git/rr-cache/ -type f | xargs test-chmtime -172800 &&
 572
 573        # Resolved entries have not expired yet
 574        git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
 575
 576        count_pre_post 2 2 &&
 577
 578        # Resolved entries have expired
 579        git -c gc.rerereresolved=1 -c gc.rerereunresolved=5 rerere gc &&
 580        count_pre_post 0 0
 581'
 582
 583test_done