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