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