t / t3510-cherry-pick-sequence.shon commit revert: allow cherry-pick --continue to commit before resuming (093a309)
   1#!/bin/sh
   2
   3test_description='Test cherry-pick continuation features
   4
   5 +  conflicting: rewrites unrelated to conflicting
   6  + yetanotherpick: rewrites foo to e
   7  + anotherpick: rewrites foo to d
   8  + picked: rewrites foo to c
   9  + unrelatedpick: rewrites unrelated to reallyunrelated
  10  + base: rewrites foo to b
  11  + initial: writes foo as a, unrelated as unrelated
  12
  13'
  14
  15. ./test-lib.sh
  16
  17pristine_detach () {
  18        git cherry-pick --quit &&
  19        git checkout -f "$1^0" &&
  20        git read-tree -u --reset HEAD &&
  21        git clean -d -f -f -q -x
  22}
  23
  24test_cmp_rev () {
  25        git rev-parse --verify "$1" >expect.rev &&
  26        git rev-parse --verify "$2" >actual.rev &&
  27        test_cmp expect.rev actual.rev
  28}
  29
  30test_expect_success setup '
  31        git config advice.detachedhead false
  32        echo unrelated >unrelated &&
  33        git add unrelated &&
  34        test_commit initial foo a &&
  35        test_commit base foo b &&
  36        test_commit unrelatedpick unrelated reallyunrelated &&
  37        test_commit picked foo c &&
  38        test_commit anotherpick foo d &&
  39        test_commit yetanotherpick foo e &&
  40        pristine_detach initial &&
  41        test_commit conflicting unrelated
  42'
  43
  44test_expect_success 'cherry-pick persists data on failure' '
  45        pristine_detach initial &&
  46        test_must_fail git cherry-pick -s base..anotherpick &&
  47        test_path_is_dir .git/sequencer &&
  48        test_path_is_file .git/sequencer/head &&
  49        test_path_is_file .git/sequencer/todo &&
  50        test_path_is_file .git/sequencer/opts
  51'
  52
  53test_expect_success 'cherry-pick persists opts correctly' '
  54        pristine_detach initial &&
  55        test_must_fail git cherry-pick -s -m 1 --strategy=recursive -X patience -X ours base..anotherpick &&
  56        test_path_is_dir .git/sequencer &&
  57        test_path_is_file .git/sequencer/head &&
  58        test_path_is_file .git/sequencer/todo &&
  59        test_path_is_file .git/sequencer/opts &&
  60        echo "true" >expect &&
  61        git config --file=.git/sequencer/opts --get-all options.signoff >actual &&
  62        test_cmp expect actual &&
  63        echo "1" >expect &&
  64        git config --file=.git/sequencer/opts --get-all options.mainline >actual &&
  65        test_cmp expect actual &&
  66        echo "recursive" >expect &&
  67        git config --file=.git/sequencer/opts --get-all options.strategy >actual &&
  68        test_cmp expect actual &&
  69        cat >expect <<-\EOF &&
  70        patience
  71        ours
  72        EOF
  73        git config --file=.git/sequencer/opts --get-all options.strategy-option >actual &&
  74        test_cmp expect actual
  75'
  76
  77test_expect_success 'cherry-pick cleans up sequencer state upon success' '
  78        pristine_detach initial &&
  79        git cherry-pick initial..picked &&
  80        test_path_is_missing .git/sequencer
  81'
  82
  83test_expect_success '--quit does not complain when no cherry-pick is in progress' '
  84        pristine_detach initial &&
  85        git cherry-pick --quit
  86'
  87
  88test_expect_success '--abort requires cherry-pick in progress' '
  89        pristine_detach initial &&
  90        test_must_fail git cherry-pick --abort
  91'
  92
  93test_expect_success '--quit cleans up sequencer state' '
  94        pristine_detach initial &&
  95        test_must_fail git cherry-pick base..picked &&
  96        git cherry-pick --quit &&
  97        test_path_is_missing .git/sequencer
  98'
  99
 100test_expect_success '--quit keeps HEAD and conflicted index intact' '
 101        pristine_detach initial &&
 102        cat >expect <<-\EOF &&
 103        OBJID
 104        :100644 100644 OBJID OBJID M    unrelated
 105        OBJID
 106        :000000 100644 OBJID OBJID A    foo
 107        :000000 100644 OBJID OBJID A    unrelated
 108        EOF
 109        test_must_fail git cherry-pick base..picked &&
 110        git cherry-pick --quit &&
 111        test_path_is_missing .git/sequencer &&
 112        test_must_fail git update-index --refresh &&
 113        {
 114                git rev-list HEAD |
 115                git diff-tree --root --stdin |
 116                sed "s/$_x40/OBJID/g"
 117        } >actual &&
 118        test_cmp expect actual
 119'
 120
 121test_expect_success '--abort to cancel multiple cherry-pick' '
 122        pristine_detach initial &&
 123        test_must_fail git cherry-pick base..anotherpick &&
 124        git cherry-pick --abort &&
 125        test_path_is_missing .git/sequencer &&
 126        test_cmp_rev initial HEAD &&
 127        git update-index --refresh &&
 128        git diff-index --exit-code HEAD
 129'
 130
 131test_expect_success '--abort to cancel single cherry-pick' '
 132        pristine_detach initial &&
 133        test_must_fail git cherry-pick picked &&
 134        git cherry-pick --abort &&
 135        test_path_is_missing .git/sequencer &&
 136        test_cmp_rev initial HEAD &&
 137        git update-index --refresh &&
 138        git diff-index --exit-code HEAD
 139'
 140
 141test_expect_success 'cherry-pick --abort to cancel multiple revert' '
 142        pristine_detach anotherpick &&
 143        test_must_fail git revert base..picked &&
 144        git cherry-pick --abort &&
 145        test_path_is_missing .git/sequencer &&
 146        test_cmp_rev anotherpick HEAD &&
 147        git update-index --refresh &&
 148        git diff-index --exit-code HEAD
 149'
 150
 151test_expect_success 'revert --abort works, too' '
 152        pristine_detach anotherpick &&
 153        test_must_fail git revert base..picked &&
 154        git revert --abort &&
 155        test_path_is_missing .git/sequencer &&
 156        test_cmp_rev anotherpick HEAD
 157'
 158
 159test_expect_success '--abort to cancel single revert' '
 160        pristine_detach anotherpick &&
 161        test_must_fail git revert picked &&
 162        git revert --abort &&
 163        test_path_is_missing .git/sequencer &&
 164        test_cmp_rev anotherpick HEAD &&
 165        git update-index --refresh &&
 166        git diff-index --exit-code HEAD
 167'
 168
 169test_expect_success '--abort keeps unrelated change, easy case' '
 170        pristine_detach unrelatedpick &&
 171        echo changed >expect &&
 172        test_must_fail git cherry-pick picked..yetanotherpick &&
 173        echo changed >unrelated &&
 174        git cherry-pick --abort &&
 175        test_cmp expect unrelated
 176'
 177
 178test_expect_success '--abort refuses to clobber unrelated change, harder case' '
 179        pristine_detach initial &&
 180        echo changed >expect &&
 181        test_must_fail git cherry-pick base..anotherpick &&
 182        echo changed >unrelated &&
 183        test_must_fail git cherry-pick --abort &&
 184        test_cmp expect unrelated &&
 185        git rev-list HEAD >log &&
 186        test_line_count = 2 log &&
 187        test_must_fail git update-index --refresh &&
 188
 189        git checkout unrelated &&
 190        git cherry-pick --abort &&
 191        test_cmp_rev initial HEAD
 192'
 193
 194test_expect_success 'cherry-pick cleans up sequencer state when one commit is left' '
 195        pristine_detach initial &&
 196        test_must_fail git cherry-pick base..picked &&
 197        test_path_is_missing .git/sequencer &&
 198        echo "resolved" >foo &&
 199        git add foo &&
 200        git commit &&
 201        {
 202                git rev-list HEAD |
 203                git diff-tree --root --stdin |
 204                sed "s/$_x40/OBJID/g"
 205        } >actual &&
 206        cat >expect <<-\EOF &&
 207        OBJID
 208        :100644 100644 OBJID OBJID M    foo
 209        OBJID
 210        :100644 100644 OBJID OBJID M    unrelated
 211        OBJID
 212        :000000 100644 OBJID OBJID A    foo
 213        :000000 100644 OBJID OBJID A    unrelated
 214        EOF
 215        test_cmp expect actual
 216'
 217
 218test_expect_failure '--abort after last commit in sequence' '
 219        pristine_detach initial &&
 220        test_must_fail git cherry-pick base..picked &&
 221        git cherry-pick --abort &&
 222        test_path_is_missing .git/sequencer &&
 223        test_cmp_rev initial HEAD &&
 224        git update-index --refresh &&
 225        git diff-index --exit-code HEAD
 226'
 227
 228test_expect_success 'cherry-pick does not implicitly stomp an existing operation' '
 229        pristine_detach initial &&
 230        test_must_fail git cherry-pick base..anotherpick &&
 231        test-chmtime -v +0 .git/sequencer >expect &&
 232        test_must_fail git cherry-pick unrelatedpick &&
 233        test-chmtime -v +0 .git/sequencer >actual &&
 234        test_cmp expect actual
 235'
 236
 237test_expect_success '--continue complains when no cherry-pick is in progress' '
 238        pristine_detach initial &&
 239        test_must_fail git cherry-pick --continue
 240'
 241
 242test_expect_success '--continue complains when there are unresolved conflicts' '
 243        pristine_detach initial &&
 244        test_must_fail git cherry-pick base..anotherpick &&
 245        test_must_fail git cherry-pick --continue
 246'
 247
 248test_expect_success '--continue of single cherry-pick' '
 249        pristine_detach initial &&
 250        echo c >expect &&
 251        test_must_fail git cherry-pick picked &&
 252        echo c >foo &&
 253        git add foo &&
 254        git cherry-pick --continue &&
 255
 256        test_cmp expect foo &&
 257        test_cmp_rev initial HEAD^ &&
 258        git diff --exit-code HEAD &&
 259        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 260'
 261
 262test_expect_success '--continue of single revert' '
 263        pristine_detach initial &&
 264        echo resolved >expect &&
 265        echo "Revert \"picked\"" >expect.msg &&
 266        test_must_fail git revert picked &&
 267        echo resolved >foo &&
 268        git add foo &&
 269        git cherry-pick --continue &&
 270
 271        git diff --exit-code HEAD &&
 272        test_cmp expect foo &&
 273        test_cmp_rev initial HEAD^ &&
 274        git diff-tree -s --pretty=tformat:%s HEAD >msg &&
 275        test_cmp expect.msg msg &&
 276        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 277        test_must_fail git rev-parse --verify REVERT_HEAD
 278'
 279
 280test_expect_success '--continue after resolving conflicts' '
 281        pristine_detach initial &&
 282        echo d >expect &&
 283        cat >expect.log <<-\EOF &&
 284        OBJID
 285        :100644 100644 OBJID OBJID M    foo
 286        OBJID
 287        :100644 100644 OBJID OBJID M    foo
 288        OBJID
 289        :100644 100644 OBJID OBJID M    unrelated
 290        OBJID
 291        :000000 100644 OBJID OBJID A    foo
 292        :000000 100644 OBJID OBJID A    unrelated
 293        EOF
 294        test_must_fail git cherry-pick base..anotherpick &&
 295        echo c >foo &&
 296        git add foo &&
 297        git cherry-pick --continue &&
 298        {
 299                git rev-list HEAD |
 300                git diff-tree --root --stdin |
 301                sed "s/$_x40/OBJID/g"
 302        } >actual.log &&
 303        test_cmp expect foo &&
 304        test_cmp expect.log actual.log
 305'
 306
 307test_expect_success '--continue after resolving conflicts and committing' '
 308        pristine_detach initial &&
 309        test_must_fail git cherry-pick base..anotherpick &&
 310        echo "c" >foo &&
 311        git add foo &&
 312        git commit &&
 313        git cherry-pick --continue &&
 314        test_path_is_missing .git/sequencer &&
 315        {
 316                git rev-list HEAD |
 317                git diff-tree --root --stdin |
 318                sed "s/$_x40/OBJID/g"
 319        } >actual &&
 320        cat >expect <<-\EOF &&
 321        OBJID
 322        :100644 100644 OBJID OBJID M    foo
 323        OBJID
 324        :100644 100644 OBJID OBJID M    foo
 325        OBJID
 326        :100644 100644 OBJID OBJID M    unrelated
 327        OBJID
 328        :000000 100644 OBJID OBJID A    foo
 329        :000000 100644 OBJID OBJID A    unrelated
 330        EOF
 331        test_cmp expect actual
 332'
 333
 334test_expect_success '--continue asks for help after resolving patch to nil' '
 335        pristine_detach conflicting &&
 336        test_must_fail git cherry-pick initial..picked &&
 337
 338        test_cmp_rev unrelatedpick CHERRY_PICK_HEAD &&
 339        git checkout HEAD -- unrelated &&
 340        test_must_fail git cherry-pick --continue 2>msg &&
 341        test_i18ngrep "The previous cherry-pick is now empty" msg
 342'
 343
 344test_expect_failure 'follow advice and skip nil patch' '
 345        pristine_detach conflicting &&
 346        test_must_fail git cherry-pick initial..picked &&
 347
 348        git checkout HEAD -- unrelated &&
 349        test_must_fail git cherry-pick --continue &&
 350        git reset &&
 351        git cherry-pick --continue &&
 352
 353        git rev-list initial..HEAD >commits &&
 354        test_line_count = 3 commits
 355'
 356
 357test_expect_success '--continue respects opts' '
 358        pristine_detach initial &&
 359        test_must_fail git cherry-pick -x base..anotherpick &&
 360        echo "c" >foo &&
 361        git add foo &&
 362        git commit &&
 363        git cherry-pick --continue &&
 364        test_path_is_missing .git/sequencer &&
 365        git cat-file commit HEAD >anotherpick_msg &&
 366        git cat-file commit HEAD~1 >picked_msg &&
 367        git cat-file commit HEAD~2 >unrelatedpick_msg &&
 368        git cat-file commit HEAD~3 >initial_msg &&
 369        test_must_fail grep "cherry picked from" initial_msg &&
 370        grep "cherry picked from" unrelatedpick_msg &&
 371        grep "cherry picked from" picked_msg &&
 372        grep "cherry picked from" anotherpick_msg
 373'
 374
 375test_expect_success '--continue of single-pick respects -x' '
 376        pristine_detach initial &&
 377        test_must_fail git cherry-pick -x picked &&
 378        echo c >foo &&
 379        git add foo &&
 380        git cherry-pick --continue &&
 381        test_path_is_missing .git/sequencer &&
 382        git cat-file commit HEAD >msg &&
 383        grep "cherry picked from" msg
 384'
 385
 386test_expect_success '--continue respects -x in first commit in multi-pick' '
 387        pristine_detach initial &&
 388        test_must_fail git cherry-pick -x picked anotherpick &&
 389        echo c >foo &&
 390        git add foo &&
 391        git cherry-pick --continue &&
 392        test_path_is_missing .git/sequencer &&
 393        git cat-file commit HEAD^ >msg &&
 394        picked=$(git rev-parse --verify picked) &&
 395        grep "cherry picked from.*$picked" msg
 396'
 397
 398test_expect_success '--signoff is not automatically propagated to resolved conflict' '
 399        pristine_detach initial &&
 400        test_must_fail git cherry-pick --signoff base..anotherpick &&
 401        echo "c" >foo &&
 402        git add foo &&
 403        git commit &&
 404        git cherry-pick --continue &&
 405        test_path_is_missing .git/sequencer &&
 406        git cat-file commit HEAD >anotherpick_msg &&
 407        git cat-file commit HEAD~1 >picked_msg &&
 408        git cat-file commit HEAD~2 >unrelatedpick_msg &&
 409        git cat-file commit HEAD~3 >initial_msg &&
 410        test_must_fail grep "Signed-off-by:" initial_msg &&
 411        grep "Signed-off-by:" unrelatedpick_msg &&
 412        test_must_fail grep "Signed-off-by:" picked_msg &&
 413        grep "Signed-off-by:" anotherpick_msg
 414'
 415
 416test_expect_success '--signoff dropped for implicit commit of resolution, multi-pick case' '
 417        pristine_detach initial &&
 418        test_must_fail git cherry-pick -s picked anotherpick &&
 419        echo c >foo &&
 420        git add foo &&
 421        git cherry-pick --continue &&
 422
 423        git diff --exit-code HEAD &&
 424        test_cmp_rev initial HEAD^^ &&
 425        git cat-file commit HEAD^ >msg &&
 426        ! grep Signed-off-by: msg
 427'
 428
 429test_expect_success 'sign-off needs to be reaffirmed after conflict resolution, single-pick case' '
 430        pristine_detach initial &&
 431        test_must_fail git cherry-pick -s picked &&
 432        echo c >foo &&
 433        git add foo &&
 434        git cherry-pick --continue &&
 435
 436        git diff --exit-code HEAD &&
 437        test_cmp_rev initial HEAD^ &&
 438        git cat-file commit HEAD >msg &&
 439        ! grep Signed-off-by: msg
 440'
 441
 442test_expect_success 'malformed instruction sheet 1' '
 443        pristine_detach initial &&
 444        test_must_fail git cherry-pick base..anotherpick &&
 445        echo "resolved" >foo &&
 446        git add foo &&
 447        git commit &&
 448        sed "s/pick /pick/" .git/sequencer/todo >new_sheet &&
 449        cp new_sheet .git/sequencer/todo &&
 450        test_must_fail git cherry-pick --continue
 451'
 452
 453test_expect_success 'malformed instruction sheet 2' '
 454        pristine_detach initial &&
 455        test_must_fail git cherry-pick base..anotherpick &&
 456        echo "resolved" >foo &&
 457        git add foo &&
 458        git commit &&
 459        sed "s/pick/revert/" .git/sequencer/todo >new_sheet &&
 460        cp new_sheet .git/sequencer/todo &&
 461        test_must_fail git cherry-pick --continue
 462'
 463
 464test_done