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