t / t3507-cherry-pick-conflict.shon commit t3506: validate '-m 1 -ff' is now accepted for non-merge commits (1c32013)
   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 'failed cherry-pick describes conflict in work tree' '
 193        pristine_detach initial &&
 194        cat <<-EOF > expected &&
 195        <<<<<<< HEAD
 196        a
 197        =======
 198        c
 199        >>>>>>> objid picked
 200        EOF
 201
 202        test_must_fail git cherry-pick picked &&
 203
 204        sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
 205        test_cmp expected actual
 206'
 207
 208test_expect_success 'diff3 -m style' '
 209        pristine_detach initial &&
 210        git config merge.conflictstyle diff3 &&
 211        cat <<-EOF > expected &&
 212        <<<<<<< HEAD
 213        a
 214        ||||||| parent of objid picked
 215        b
 216        =======
 217        c
 218        >>>>>>> objid picked
 219        EOF
 220
 221        test_must_fail git cherry-pick picked &&
 222
 223        sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
 224        test_cmp expected actual
 225'
 226
 227test_expect_success 'revert also handles conflicts sanely' '
 228        git config --unset merge.conflictstyle &&
 229        pristine_detach initial &&
 230        cat <<-EOF > expected &&
 231        <<<<<<< HEAD
 232        a
 233        =======
 234        b
 235        >>>>>>> parent of objid picked
 236        EOF
 237        {
 238                git checkout picked -- foo &&
 239                git ls-files --stage foo &&
 240                git checkout initial -- foo &&
 241                git ls-files --stage foo &&
 242                git checkout base -- foo &&
 243                git ls-files --stage foo
 244        } > stages &&
 245        sed "
 246                1 s/ 0  / 1     /
 247                2 s/ 0  / 2     /
 248                3 s/ 0  / 3     /
 249        " < stages > expected-stages &&
 250        git read-tree -u --reset HEAD &&
 251
 252        head=$(git rev-parse HEAD) &&
 253        test_must_fail git revert picked &&
 254        newhead=$(git rev-parse HEAD) &&
 255        git ls-files --stage --unmerged > actual-stages &&
 256
 257        test "$head" = "$newhead" &&
 258        test_must_fail git update-index --refresh -q &&
 259        test_must_fail git diff-index --exit-code HEAD &&
 260        test_cmp expected-stages actual-stages &&
 261        sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
 262        test_cmp expected actual
 263'
 264
 265test_expect_success 'failed revert sets REVERT_HEAD' '
 266        pristine_detach initial &&
 267        test_must_fail git revert picked &&
 268        test_cmp_rev picked REVERT_HEAD
 269'
 270
 271test_expect_success 'successful revert does not set REVERT_HEAD' '
 272        pristine_detach base &&
 273        git revert base &&
 274        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 275        test_must_fail git rev-parse --verify REVERT_HEAD
 276'
 277
 278test_expect_success 'revert --no-commit sets REVERT_HEAD' '
 279        pristine_detach base &&
 280        git revert --no-commit base &&
 281        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 282        test_cmp_rev base REVERT_HEAD
 283'
 284
 285test_expect_success 'revert w/dirty tree does not set REVERT_HEAD' '
 286        pristine_detach base &&
 287        echo foo > foo &&
 288        test_must_fail git revert base &&
 289        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 290        test_must_fail git rev-parse --verify REVERT_HEAD
 291'
 292
 293test_expect_success 'GIT_CHERRY_PICK_HELP does not suppress REVERT_HEAD' '
 294        pristine_detach initial &&
 295        (
 296                GIT_CHERRY_PICK_HELP="and then do something else" &&
 297                GIT_REVERT_HELP="and then do something else, again" &&
 298                export GIT_CHERRY_PICK_HELP GIT_REVERT_HELP &&
 299                test_must_fail git revert picked
 300        ) &&
 301        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 302        test_cmp_rev picked REVERT_HEAD
 303'
 304
 305test_expect_success 'git reset clears REVERT_HEAD' '
 306        pristine_detach initial &&
 307        test_must_fail git revert picked &&
 308        git reset &&
 309        test_must_fail git rev-parse --verify REVERT_HEAD
 310'
 311
 312test_expect_success 'failed commit does not clear REVERT_HEAD' '
 313        pristine_detach initial &&
 314        test_must_fail git revert picked &&
 315        test_must_fail git commit &&
 316        test_cmp_rev picked REVERT_HEAD
 317'
 318
 319test_expect_success 'revert conflict, diff3 -m style' '
 320        pristine_detach initial &&
 321        git config merge.conflictstyle diff3 &&
 322        cat <<-EOF > expected &&
 323        <<<<<<< HEAD
 324        a
 325        ||||||| objid picked
 326        c
 327        =======
 328        b
 329        >>>>>>> parent of objid picked
 330        EOF
 331
 332        test_must_fail git revert picked &&
 333
 334        sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
 335        test_cmp expected actual
 336'
 337
 338test_expect_success 'failed cherry-pick does not forget -s' '
 339        pristine_detach initial &&
 340        test_must_fail git cherry-pick -s picked &&
 341        test_i18ngrep -e "Signed-off-by" .git/MERGE_MSG
 342'
 343
 344test_expect_success 'commit after failed cherry-pick does not add duplicated -s' '
 345        pristine_detach initial &&
 346        test_must_fail git cherry-pick -s picked-signed &&
 347        git commit -a -s &&
 348        test $(git show -s |grep -c "Signed-off-by") = 1
 349'
 350
 351test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
 352        pristine_detach initial &&
 353        test_must_fail git cherry-pick picked &&
 354
 355        git commit -a -s &&
 356
 357        # Do S-o-b and Conflicts appear in the right order?
 358        cat <<-\EOF >expect &&
 359        Signed-off-by: C O Mitter <committer@example.com>
 360        # Conflicts:
 361        EOF
 362        grep -e "^# Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
 363        test_cmp expect actual &&
 364
 365        cat <<-\EOF >expected &&
 366        picked
 367
 368        Signed-off-by: C O Mitter <committer@example.com>
 369        EOF
 370
 371        git show -s --pretty=format:%B >actual &&
 372        test_cmp expected actual
 373'
 374
 375test_expect_success 'commit --amend -s places the sign-off at the right place' '
 376        pristine_detach initial &&
 377        test_must_fail git cherry-pick picked &&
 378
 379        # emulate old-style conflicts block
 380        mv .git/MERGE_MSG .git/MERGE_MSG+ &&
 381        sed -e "/^# Conflicts:/,\$s/^# *//" <.git/MERGE_MSG+ >.git/MERGE_MSG &&
 382
 383        git commit -a &&
 384        git commit --amend -s &&
 385
 386        # Do S-o-b and Conflicts appear in the right order?
 387        cat <<-\EOF >expect &&
 388        Signed-off-by: C O Mitter <committer@example.com>
 389        Conflicts:
 390        EOF
 391        grep -e "^Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
 392        test_cmp expect actual
 393'
 394
 395test_expect_success 'cherry-pick preserves sparse-checkout' '
 396        pristine_detach initial &&
 397        test_config core.sparseCheckout true &&
 398        test_when_finished "
 399                echo \"/*\" >.git/info/sparse-checkout
 400                git read-tree --reset -u HEAD
 401                rm .git/info/sparse-checkout" &&
 402        echo /unrelated >.git/info/sparse-checkout &&
 403        git read-tree --reset -u HEAD &&
 404        test_must_fail git cherry-pick -Xours picked>actual &&
 405        test_i18ngrep ! "Changes not staged for commit:" actual
 406'
 407
 408test_done