t / t3507-cherry-pick-conflict.shon commit general improvements (43abf13)
   1#!/bin/sh
   2
   3test_description='test cherry-pick and revert with conflicts
   4
   5  -
   6  + picked: rewrites foo to c
   7  + base: rewrites foo to b
   8  + initial: writes foo as a, unrelated as unrelated
   9
  10'
  11
  12. ./test-lib.sh
  13
  14pristine_detach () {
  15        git checkout -f "$1^0" &&
  16        git read-tree -u --reset HEAD &&
  17        git clean -d -f -f -q -x
  18}
  19
  20test_expect_success setup '
  21
  22        echo unrelated >unrelated &&
  23        git add unrelated &&
  24        test_commit initial foo a &&
  25        test_commit base foo b &&
  26        test_commit picked foo c &&
  27        test_commit --signoff picked-signed foo d &&
  28        git checkout -b topic initial &&
  29        test_commit redundant-pick foo c redundant &&
  30        git commit --allow-empty --allow-empty-message &&
  31        git tag empty &&
  32        git checkout master &&
  33        git config advice.detachedhead false
  34
  35'
  36
  37test_expect_success 'failed cherry-pick does not advance HEAD' '
  38        pristine_detach initial &&
  39
  40        head=$(git rev-parse HEAD) &&
  41        test_must_fail git cherry-pick picked &&
  42        newhead=$(git rev-parse HEAD) &&
  43
  44        test "$head" = "$newhead"
  45'
  46
  47test_expect_success 'advice from failed cherry-pick' "
  48        pristine_detach initial &&
  49
  50        picked=\$(git rev-parse --short picked) &&
  51        cat <<-EOF >expected &&
  52        error: could not apply \$picked... picked
  53        hint: after resolving the conflicts, mark the corrected paths
  54        hint: with 'git add <paths>' or 'git rm <paths>'
  55        hint: and commit the result with 'git commit'
  56        EOF
  57        test_must_fail git cherry-pick picked 2>actual &&
  58
  59        test_i18ncmp expected actual
  60"
  61
  62test_expect_success 'advice from failed cherry-pick --no-commit' "
  63        pristine_detach initial &&
  64
  65        picked=\$(git rev-parse --short picked) &&
  66        cat <<-EOF >expected &&
  67        error: could not apply \$picked... picked
  68        hint: after resolving the conflicts, mark the corrected paths
  69        hint: with 'git add <paths>' or 'git rm <paths>'
  70        EOF
  71        test_must_fail git cherry-pick --no-commit picked 2>actual &&
  72
  73        test_i18ncmp expected actual
  74"
  75
  76test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' '
  77        pristine_detach initial &&
  78        test_must_fail git cherry-pick picked &&
  79        test_cmp_rev picked CHERRY_PICK_HEAD
  80'
  81
  82test_expect_success 'successful cherry-pick does not set CHERRY_PICK_HEAD' '
  83        pristine_detach initial &&
  84        git cherry-pick base &&
  85        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
  86'
  87
  88test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' '
  89        pristine_detach initial &&
  90        git cherry-pick --no-commit base &&
  91        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
  92'
  93
  94test_expect_success 'cherry-pick w/dirty tree does not set CHERRY_PICK_HEAD' '
  95        pristine_detach initial &&
  96        echo foo >foo &&
  97        test_must_fail git cherry-pick base &&
  98        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
  99'
 100
 101test_expect_success \
 102        'cherry-pick --strategy=resolve w/dirty tree does not set CHERRY_PICK_HEAD' '
 103        pristine_detach initial &&
 104        echo foo >foo &&
 105        test_must_fail git cherry-pick --strategy=resolve base &&
 106        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 107'
 108
 109test_expect_success 'GIT_CHERRY_PICK_HELP suppresses CHERRY_PICK_HEAD' '
 110        pristine_detach initial &&
 111        (
 112                GIT_CHERRY_PICK_HELP="and then do something else" &&
 113                export GIT_CHERRY_PICK_HELP &&
 114                test_must_fail git cherry-pick picked
 115        ) &&
 116        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 117'
 118
 119test_expect_success 'git reset clears CHERRY_PICK_HEAD' '
 120        pristine_detach initial &&
 121
 122        test_must_fail git cherry-pick picked &&
 123        git reset &&
 124
 125        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 126'
 127
 128test_expect_success 'failed commit does not clear CHERRY_PICK_HEAD' '
 129        pristine_detach initial &&
 130
 131        test_must_fail git cherry-pick picked &&
 132        test_must_fail git commit &&
 133
 134        test_cmp_rev picked CHERRY_PICK_HEAD
 135'
 136
 137test_expect_success 'cancelled commit does not clear CHERRY_PICK_HEAD' '
 138        pristine_detach initial &&
 139
 140        test_must_fail git cherry-pick picked &&
 141        echo resolved >foo &&
 142        git add foo &&
 143        git update-index --refresh -q &&
 144        test_must_fail git diff-index --exit-code HEAD &&
 145        (
 146                GIT_EDITOR=false &&
 147                export GIT_EDITOR &&
 148                test_must_fail git commit
 149        ) &&
 150
 151        test_cmp_rev picked CHERRY_PICK_HEAD
 152'
 153
 154test_expect_success 'successful commit clears CHERRY_PICK_HEAD' '
 155        pristine_detach initial &&
 156
 157        test_must_fail git cherry-pick picked &&
 158        echo resolved >foo &&
 159        git add foo &&
 160        git commit &&
 161
 162        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 163'
 164test_expect_success 'successful final commit clears cherry-pick state' '
 165        pristine_detach initial &&
 166
 167        test_must_fail git cherry-pick base picked-signed &&
 168        echo resolved >foo &&
 169        test_path_is_file .git/sequencer/todo &&
 170        git commit -a &&
 171        test_must_fail test_path_exists .git/sequencer
 172'
 173
 174test_expect_success 'reset after final pick clears cherry-pick state' '
 175        pristine_detach initial &&
 176
 177        test_must_fail git cherry-pick base picked-signed &&
 178        echo resolved >foo &&
 179        test_path_is_file .git/sequencer/todo &&
 180        git reset &&
 181        test_must_fail test_path_exists .git/sequencer
 182'
 183
 184test_expect_success 'failed cherry-pick produces dirty index' '
 185        pristine_detach initial &&
 186
 187        test_must_fail git cherry-pick picked &&
 188
 189        test_must_fail git update-index --refresh -q &&
 190        test_must_fail git diff-index --exit-code HEAD
 191'
 192
 193test_expect_success 'failed cherry-pick registers participants in index' '
 194        pristine_detach initial &&
 195        {
 196                git checkout base -- foo &&
 197                git ls-files --stage foo &&
 198                git checkout initial -- foo &&
 199                git ls-files --stage foo &&
 200                git checkout picked -- foo &&
 201                git ls-files --stage foo
 202        } >stages &&
 203        sed "
 204                1 s/ 0  / 1     /
 205                2 s/ 0  / 2     /
 206                3 s/ 0  / 3     /
 207        " stages >expected &&
 208        git read-tree -u --reset HEAD &&
 209
 210        test_must_fail git cherry-pick picked &&
 211        git ls-files --stage --unmerged >actual &&
 212
 213        test_cmp expected actual
 214'
 215
 216test_expect_success \
 217        'cherry-pick conflict, ensure commit.cleanup = scissors places scissors line properly' '
 218        pristine_detach initial &&
 219        git config commit.cleanup scissors &&
 220        cat <<-EOF >expected &&
 221                picked
 222
 223                # ------------------------ >8 ------------------------
 224                # Do not modify or remove the line above.
 225                # Everything below it will be ignored.
 226                #
 227                # Conflicts:
 228                #       foo
 229                EOF
 230
 231        test_must_fail git cherry-pick picked &&
 232
 233        test_i18ncmp expected .git/MERGE_MSG
 234'
 235
 236test_expect_success \
 237        'cherry-pick conflict, ensure cleanup=scissors places scissors line properly' '
 238        pristine_detach initial &&
 239        git config --unset commit.cleanup &&
 240        cat <<-EOF >expected &&
 241                picked
 242
 243                # ------------------------ >8 ------------------------
 244                # Do not modify or remove the line above.
 245                # Everything below it will be ignored.
 246                #
 247                # Conflicts:
 248                #       foo
 249                EOF
 250
 251        test_must_fail git cherry-pick --cleanup=scissors picked &&
 252
 253        test_i18ncmp expected .git/MERGE_MSG
 254'
 255
 256test_expect_success 'failed cherry-pick describes conflict in work tree' '
 257        pristine_detach initial &&
 258        cat <<-EOF >expected &&
 259        <<<<<<< HEAD
 260        a
 261        =======
 262        c
 263        >>>>>>> objid picked
 264        EOF
 265
 266        test_must_fail git cherry-pick picked &&
 267
 268        sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 269        test_cmp expected actual
 270'
 271
 272test_expect_success 'diff3 -m style' '
 273        pristine_detach initial &&
 274        git config merge.conflictstyle diff3 &&
 275        cat <<-EOF >expected &&
 276        <<<<<<< HEAD
 277        a
 278        ||||||| parent of objid picked
 279        b
 280        =======
 281        c
 282        >>>>>>> objid picked
 283        EOF
 284
 285        test_must_fail git cherry-pick picked &&
 286
 287        sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 288        test_cmp expected actual
 289'
 290
 291test_expect_success 'revert also handles conflicts sanely' '
 292        git config --unset merge.conflictstyle &&
 293        pristine_detach initial &&
 294        cat <<-EOF >expected &&
 295        <<<<<<< HEAD
 296        a
 297        =======
 298        b
 299        >>>>>>> parent of objid picked
 300        EOF
 301        {
 302                git checkout picked -- foo &&
 303                git ls-files --stage foo &&
 304                git checkout initial -- foo &&
 305                git ls-files --stage foo &&
 306                git checkout base -- foo &&
 307                git ls-files --stage foo
 308        } >stages &&
 309        sed "
 310                1 s/ 0  / 1     /
 311                2 s/ 0  / 2     /
 312                3 s/ 0  / 3     /
 313        " stages >expected-stages &&
 314        git read-tree -u --reset HEAD &&
 315
 316        head=$(git rev-parse HEAD) &&
 317        test_must_fail git revert picked &&
 318        newhead=$(git rev-parse HEAD) &&
 319        git ls-files --stage --unmerged >actual-stages &&
 320
 321        test "$head" = "$newhead" &&
 322        test_must_fail git update-index --refresh -q &&
 323        test_must_fail git diff-index --exit-code HEAD &&
 324        test_cmp expected-stages actual-stages &&
 325        sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 326        test_cmp expected actual
 327'
 328
 329test_expect_success 'failed revert sets REVERT_HEAD' '
 330        pristine_detach initial &&
 331        test_must_fail git revert picked &&
 332        test_cmp_rev picked REVERT_HEAD
 333'
 334
 335test_expect_success 'successful revert does not set REVERT_HEAD' '
 336        pristine_detach base &&
 337        git revert base &&
 338        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 339        test_must_fail git rev-parse --verify REVERT_HEAD
 340'
 341
 342test_expect_success 'revert --no-commit sets REVERT_HEAD' '
 343        pristine_detach base &&
 344        git revert --no-commit base &&
 345        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 346        test_cmp_rev base REVERT_HEAD
 347'
 348
 349test_expect_success 'revert w/dirty tree does not set REVERT_HEAD' '
 350        pristine_detach base &&
 351        echo foo >foo &&
 352        test_must_fail git revert base &&
 353        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 354        test_must_fail git rev-parse --verify REVERT_HEAD
 355'
 356
 357test_expect_success 'GIT_CHERRY_PICK_HELP does not suppress REVERT_HEAD' '
 358        pristine_detach initial &&
 359        (
 360                GIT_CHERRY_PICK_HELP="and then do something else" &&
 361                GIT_REVERT_HELP="and then do something else, again" &&
 362                export GIT_CHERRY_PICK_HELP GIT_REVERT_HELP &&
 363                test_must_fail git revert picked
 364        ) &&
 365        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 366        test_cmp_rev picked REVERT_HEAD
 367'
 368
 369test_expect_success 'git reset clears REVERT_HEAD' '
 370        pristine_detach initial &&
 371        test_must_fail git revert picked &&
 372        git reset &&
 373        test_must_fail git rev-parse --verify REVERT_HEAD
 374'
 375
 376test_expect_success 'failed commit does not clear REVERT_HEAD' '
 377        pristine_detach initial &&
 378        test_must_fail git revert picked &&
 379        test_must_fail git commit &&
 380        test_cmp_rev picked REVERT_HEAD
 381'
 382
 383test_expect_success 'successful final commit clears revert state' '
 384       pristine_detach picked-signed &&
 385
 386       test_must_fail git revert picked-signed base &&
 387       echo resolved >foo &&
 388       test_path_is_file .git/sequencer/todo &&
 389       git commit -a &&
 390       test_must_fail test_path_exists .git/sequencer
 391'
 392
 393test_expect_success 'reset after final pick clears revert state' '
 394       pristine_detach picked-signed &&
 395
 396       test_must_fail git revert picked-signed base &&
 397       echo resolved >foo &&
 398       test_path_is_file .git/sequencer/todo &&
 399       git reset &&
 400       test_must_fail test_path_exists .git/sequencer
 401'
 402
 403test_expect_success 'revert conflict, diff3 -m style' '
 404        pristine_detach initial &&
 405        git config merge.conflictstyle diff3 &&
 406        cat <<-EOF >expected &&
 407        <<<<<<< HEAD
 408        a
 409        ||||||| objid picked
 410        c
 411        =======
 412        b
 413        >>>>>>> parent of objid picked
 414        EOF
 415
 416        test_must_fail git revert picked &&
 417
 418        sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
 419        test_cmp expected actual
 420'
 421
 422test_expect_success \
 423        'revert conflict, ensure commit.cleanup = scissors places scissors line properly' '
 424        pristine_detach initial &&
 425        git config commit.cleanup scissors &&
 426        cat >expected <<-EOF &&
 427                Revert "picked"
 428
 429                This reverts commit OBJID.
 430
 431                # ------------------------ >8 ------------------------
 432                # Do not modify or remove the line above.
 433                # Everything below it will be ignored.
 434                #
 435                # Conflicts:
 436                #       foo
 437                EOF
 438
 439        test_must_fail git revert picked &&
 440
 441        sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
 442        test_i18ncmp expected actual
 443'
 444
 445test_expect_success \
 446        'revert conflict, ensure cleanup=scissors places scissors line properly' '
 447        pristine_detach initial &&
 448        git config --unset commit.cleanup &&
 449        cat >expected <<-EOF &&
 450                Revert "picked"
 451
 452                This reverts commit OBJID.
 453
 454                # ------------------------ >8 ------------------------
 455                # Do not modify or remove the line above.
 456                # Everything below it will be ignored.
 457                #
 458                # Conflicts:
 459                #       foo
 460                EOF
 461
 462        test_must_fail git revert --cleanup=scissors picked &&
 463
 464        sed "s/$OID_REGEX/OBJID/" .git/MERGE_MSG >actual &&
 465        test_i18ncmp expected actual
 466'
 467
 468test_expect_success 'failed cherry-pick does not forget -s' '
 469        pristine_detach initial &&
 470        test_must_fail git cherry-pick -s picked &&
 471        test_i18ngrep -e "Signed-off-by" .git/MERGE_MSG
 472'
 473
 474test_expect_success 'commit after failed cherry-pick does not add duplicated -s' '
 475        pristine_detach initial &&
 476        test_must_fail git cherry-pick -s picked-signed &&
 477        git commit -a -s &&
 478        test $(git show -s >tmp && grep -c "Signed-off-by" tmp && rm tmp) = 1
 479'
 480
 481test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
 482        pristine_detach initial &&
 483        test_must_fail git cherry-pick picked &&
 484
 485        git commit -a -s &&
 486
 487        # Do S-o-b and Conflicts appear in the right order?
 488        cat <<-\EOF >expect &&
 489        Signed-off-by: C O Mitter <committer@example.com>
 490        # Conflicts:
 491        EOF
 492        grep -e "^# Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
 493        test_cmp expect actual &&
 494
 495        cat <<-\EOF >expected &&
 496        picked
 497
 498        Signed-off-by: C O Mitter <committer@example.com>
 499        EOF
 500
 501        git show -s --pretty=format:%B >actual &&
 502        test_cmp expected actual
 503'
 504
 505test_expect_success 'commit --amend -s places the sign-off at the right place' '
 506        pristine_detach initial &&
 507        test_must_fail git cherry-pick picked &&
 508
 509        # emulate old-style conflicts block
 510        mv .git/MERGE_MSG .git/MERGE_MSG+ &&
 511        sed -e "/^# Conflicts:/,\$s/^# *//" .git/MERGE_MSG+ >.git/MERGE_MSG &&
 512
 513        git commit -a &&
 514        git commit --amend -s &&
 515
 516        # Do S-o-b and Conflicts appear in the right order?
 517        cat <<-\EOF >expect &&
 518        Signed-off-by: C O Mitter <committer@example.com>
 519        Conflicts:
 520        EOF
 521        grep -e "^Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
 522        test_cmp expect actual
 523'
 524
 525test_expect_success 'cherry-pick preserves sparse-checkout' '
 526        pristine_detach initial &&
 527        test_config core.sparseCheckout true &&
 528        test_when_finished "
 529                echo \"/*\" >.git/info/sparse-checkout
 530                git read-tree --reset -u HEAD
 531                rm .git/info/sparse-checkout" &&
 532        echo /unrelated >.git/info/sparse-checkout &&
 533        git read-tree --reset -u HEAD &&
 534        test_must_fail git cherry-pick -Xours picked>actual &&
 535        test_i18ngrep ! "Changes not staged for commit:" actual
 536'
 537
 538test_expect_success 'cherry-pick --continue remembers --keep-redundant-commits' '
 539        test_when_finished "git cherry-pick --abort || :" &&
 540        pristine_detach initial &&
 541        test_must_fail git cherry-pick --keep-redundant-commits picked redundant &&
 542        echo c >foo &&
 543        git add foo &&
 544        git cherry-pick --continue
 545'
 546
 547test_expect_success 'cherry-pick --continue remembers --allow-empty and --allow-empty-message' '
 548        test_when_finished "git cherry-pick --abort || :" &&
 549        pristine_detach initial &&
 550        test_must_fail git cherry-pick --allow-empty --allow-empty-message \
 551                                       picked empty &&
 552        echo c >foo &&
 553        git add foo &&
 554        git cherry-pick --continue
 555'
 556
 557test_done