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