t / t3510-cherry-pick-sequence.shon commit merge-octopus: abort if index does not match HEAD (3ec62ad)
   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 'cherry-pick --abort to cancel multiple revert' '
 151        pristine_detach anotherpick &&
 152        test_expect_code 1 git revert base..picked &&
 153        git cherry-pick --abort &&
 154        test_path_is_missing .git/sequencer &&
 155        test_cmp_rev anotherpick HEAD &&
 156        git update-index --refresh &&
 157        git diff-index --exit-code HEAD
 158'
 159
 160test_expect_success 'revert --abort works, too' '
 161        pristine_detach anotherpick &&
 162        test_expect_code 1 git revert base..picked &&
 163        git revert --abort &&
 164        test_path_is_missing .git/sequencer &&
 165        test_cmp_rev anotherpick HEAD
 166'
 167
 168test_expect_success '--abort to cancel single revert' '
 169        pristine_detach anotherpick &&
 170        test_expect_code 1 git revert picked &&
 171        git revert --abort &&
 172        test_path_is_missing .git/sequencer &&
 173        test_cmp_rev anotherpick HEAD &&
 174        git update-index --refresh &&
 175        git diff-index --exit-code HEAD
 176'
 177
 178test_expect_success '--abort keeps unrelated change, easy case' '
 179        pristine_detach unrelatedpick &&
 180        echo changed >expect &&
 181        test_expect_code 1 git cherry-pick picked..yetanotherpick &&
 182        echo changed >unrelated &&
 183        git cherry-pick --abort &&
 184        test_cmp expect unrelated
 185'
 186
 187test_expect_success '--abort refuses to clobber unrelated change, harder case' '
 188        pristine_detach initial &&
 189        echo changed >expect &&
 190        test_expect_code 1 git cherry-pick base..anotherpick &&
 191        echo changed >unrelated &&
 192        test_must_fail git cherry-pick --abort &&
 193        test_cmp expect unrelated &&
 194        git rev-list HEAD >log &&
 195        test_line_count = 2 log &&
 196        test_must_fail git update-index --refresh &&
 197
 198        git checkout unrelated &&
 199        git cherry-pick --abort &&
 200        test_cmp_rev initial HEAD
 201'
 202
 203test_expect_success 'cherry-pick still writes sequencer state when one commit is left' '
 204        pristine_detach initial &&
 205        test_expect_code 1 git cherry-pick base..picked &&
 206        test_path_is_dir .git/sequencer &&
 207        echo "resolved" >foo &&
 208        git add foo &&
 209        git commit &&
 210        {
 211                git rev-list HEAD |
 212                git diff-tree --root --stdin |
 213                sed "s/$_x40/OBJID/g"
 214        } >actual &&
 215        cat >expect <<-\EOF &&
 216        OBJID
 217        :100644 100644 OBJID OBJID M    foo
 218        OBJID
 219        :100644 100644 OBJID OBJID M    unrelated
 220        OBJID
 221        :000000 100644 OBJID OBJID A    foo
 222        :000000 100644 OBJID OBJID A    unrelated
 223        EOF
 224        test_cmp expect actual
 225'
 226
 227test_expect_success '--abort after last commit in sequence' '
 228        pristine_detach initial &&
 229        test_expect_code 1 git cherry-pick base..picked &&
 230        git cherry-pick --abort &&
 231        test_path_is_missing .git/sequencer &&
 232        test_cmp_rev initial HEAD &&
 233        git update-index --refresh &&
 234        git diff-index --exit-code HEAD
 235'
 236
 237test_expect_success 'cherry-pick does not implicitly stomp an existing operation' '
 238        pristine_detach initial &&
 239        test_expect_code 1 git cherry-pick base..anotherpick &&
 240        test-chmtime -v +0 .git/sequencer >expect &&
 241        test_expect_code 128 git cherry-pick unrelatedpick &&
 242        test-chmtime -v +0 .git/sequencer >actual &&
 243        test_cmp expect actual
 244'
 245
 246test_expect_success '--continue complains when no cherry-pick is in progress' '
 247        pristine_detach initial &&
 248        test_expect_code 128 git cherry-pick --continue
 249'
 250
 251test_expect_success '--continue complains when there are unresolved conflicts' '
 252        pristine_detach initial &&
 253        test_expect_code 1 git cherry-pick base..anotherpick &&
 254        test_expect_code 128 git cherry-pick --continue
 255'
 256
 257test_expect_success '--continue of single cherry-pick' '
 258        pristine_detach initial &&
 259        echo c >expect &&
 260        test_must_fail git cherry-pick picked &&
 261        echo c >foo &&
 262        git add foo &&
 263        git cherry-pick --continue &&
 264
 265        test_cmp expect foo &&
 266        test_cmp_rev initial HEAD^ &&
 267        git diff --exit-code HEAD &&
 268        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 269'
 270
 271test_expect_success '--continue of single revert' '
 272        pristine_detach initial &&
 273        echo resolved >expect &&
 274        echo "Revert \"picked\"" >expect.msg &&
 275        test_must_fail git revert picked &&
 276        echo resolved >foo &&
 277        git add foo &&
 278        git cherry-pick --continue &&
 279
 280        git diff --exit-code HEAD &&
 281        test_cmp expect foo &&
 282        test_cmp_rev initial HEAD^ &&
 283        git diff-tree -s --pretty=tformat:%s HEAD >msg &&
 284        test_cmp expect.msg msg &&
 285        test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
 286        test_must_fail git rev-parse --verify REVERT_HEAD
 287'
 288
 289test_expect_success '--continue after resolving conflicts' '
 290        pristine_detach initial &&
 291        echo d >expect &&
 292        cat >expect.log <<-\EOF &&
 293        OBJID
 294        :100644 100644 OBJID OBJID M    foo
 295        OBJID
 296        :100644 100644 OBJID OBJID M    foo
 297        OBJID
 298        :100644 100644 OBJID OBJID M    unrelated
 299        OBJID
 300        :000000 100644 OBJID OBJID A    foo
 301        :000000 100644 OBJID OBJID A    unrelated
 302        EOF
 303        test_must_fail git cherry-pick base..anotherpick &&
 304        echo c >foo &&
 305        git add foo &&
 306        git cherry-pick --continue &&
 307        {
 308                git rev-list HEAD |
 309                git diff-tree --root --stdin |
 310                sed "s/$_x40/OBJID/g"
 311        } >actual.log &&
 312        test_cmp expect foo &&
 313        test_cmp expect.log actual.log
 314'
 315
 316test_expect_success '--continue after resolving conflicts and committing' '
 317        pristine_detach initial &&
 318        test_expect_code 1 git cherry-pick base..anotherpick &&
 319        echo "c" >foo &&
 320        git add foo &&
 321        git commit &&
 322        git cherry-pick --continue &&
 323        test_path_is_missing .git/sequencer &&
 324        {
 325                git rev-list HEAD |
 326                git diff-tree --root --stdin |
 327                sed "s/$_x40/OBJID/g"
 328        } >actual &&
 329        cat >expect <<-\EOF &&
 330        OBJID
 331        :100644 100644 OBJID OBJID M    foo
 332        OBJID
 333        :100644 100644 OBJID OBJID M    foo
 334        OBJID
 335        :100644 100644 OBJID OBJID M    unrelated
 336        OBJID
 337        :000000 100644 OBJID OBJID A    foo
 338        :000000 100644 OBJID OBJID A    unrelated
 339        EOF
 340        test_cmp expect actual
 341'
 342
 343test_expect_success '--continue asks for help after resolving patch to nil' '
 344        pristine_detach conflicting &&
 345        test_must_fail git cherry-pick initial..picked &&
 346
 347        test_cmp_rev unrelatedpick CHERRY_PICK_HEAD &&
 348        git checkout HEAD -- unrelated &&
 349        test_must_fail git cherry-pick --continue 2>msg &&
 350        test_i18ngrep "The previous cherry-pick is now empty" msg
 351'
 352
 353test_expect_success 'follow advice and skip nil patch' '
 354        pristine_detach conflicting &&
 355        test_must_fail git cherry-pick initial..picked &&
 356
 357        git checkout HEAD -- unrelated &&
 358        test_must_fail git cherry-pick --continue &&
 359        git reset &&
 360        git cherry-pick --continue &&
 361
 362        git rev-list initial..HEAD >commits &&
 363        test_line_count = 3 commits
 364'
 365
 366test_expect_success '--continue respects opts' '
 367        pristine_detach initial &&
 368        test_expect_code 1 git cherry-pick -x base..anotherpick &&
 369        echo "c" >foo &&
 370        git add foo &&
 371        git commit &&
 372        git cherry-pick --continue &&
 373        test_path_is_missing .git/sequencer &&
 374        git cat-file commit HEAD >anotherpick_msg &&
 375        git cat-file commit HEAD~1 >picked_msg &&
 376        git cat-file commit HEAD~2 >unrelatedpick_msg &&
 377        git cat-file commit HEAD~3 >initial_msg &&
 378        test_must_fail grep "cherry picked from" initial_msg &&
 379        grep "cherry picked from" unrelatedpick_msg &&
 380        grep "cherry picked from" picked_msg &&
 381        grep "cherry picked from" anotherpick_msg
 382'
 383
 384test_expect_success '--continue of single-pick respects -x' '
 385        pristine_detach initial &&
 386        test_must_fail git cherry-pick -x picked &&
 387        echo c >foo &&
 388        git add foo &&
 389        git cherry-pick --continue &&
 390        test_path_is_missing .git/sequencer &&
 391        git cat-file commit HEAD >msg &&
 392        grep "cherry picked from" msg
 393'
 394
 395test_expect_success '--continue respects -x in first commit in multi-pick' '
 396        pristine_detach initial &&
 397        test_must_fail git cherry-pick -x picked anotherpick &&
 398        echo c >foo &&
 399        git add foo &&
 400        git cherry-pick --continue &&
 401        test_path_is_missing .git/sequencer &&
 402        git cat-file commit HEAD^ >msg &&
 403        picked=$(git rev-parse --verify picked) &&
 404        grep "cherry picked from.*$picked" msg
 405'
 406
 407test_expect_failure '--signoff is automatically propagated to resolved conflict' '
 408        pristine_detach initial &&
 409        test_expect_code 1 git cherry-pick --signoff base..anotherpick &&
 410        echo "c" >foo &&
 411        git add foo &&
 412        git commit &&
 413        git cherry-pick --continue &&
 414        test_path_is_missing .git/sequencer &&
 415        git cat-file commit HEAD >anotherpick_msg &&
 416        git cat-file commit HEAD~1 >picked_msg &&
 417        git cat-file commit HEAD~2 >unrelatedpick_msg &&
 418        git cat-file commit HEAD~3 >initial_msg &&
 419        test_must_fail grep "Signed-off-by:" initial_msg &&
 420        grep "Signed-off-by:" unrelatedpick_msg &&
 421        test_must_fail grep "Signed-off-by:" picked_msg &&
 422        grep "Signed-off-by:" anotherpick_msg
 423'
 424
 425test_expect_failure '--signoff dropped for implicit commit of resolution, multi-pick case' '
 426        pristine_detach initial &&
 427        test_must_fail git cherry-pick -s picked anotherpick &&
 428        echo c >foo &&
 429        git add foo &&
 430        git cherry-pick --continue &&
 431
 432        git diff --exit-code HEAD &&
 433        test_cmp_rev initial HEAD^^ &&
 434        git cat-file commit HEAD^ >msg &&
 435        ! grep Signed-off-by: msg
 436'
 437
 438test_expect_failure 'sign-off needs to be reaffirmed after conflict resolution, single-pick case' '
 439        pristine_detach initial &&
 440        test_must_fail git cherry-pick -s picked &&
 441        echo c >foo &&
 442        git add foo &&
 443        git cherry-pick --continue &&
 444
 445        git diff --exit-code HEAD &&
 446        test_cmp_rev initial HEAD^ &&
 447        git cat-file commit HEAD >msg &&
 448        ! grep Signed-off-by: msg
 449'
 450
 451test_expect_success 'malformed instruction sheet 1' '
 452        pristine_detach initial &&
 453        test_expect_code 1 git cherry-pick base..anotherpick &&
 454        echo "resolved" >foo &&
 455        git add foo &&
 456        git commit &&
 457        sed "s/pick /pick/" .git/sequencer/todo >new_sheet &&
 458        cp new_sheet .git/sequencer/todo &&
 459        test_expect_code 128 git cherry-pick --continue
 460'
 461
 462test_expect_success 'malformed instruction sheet 2' '
 463        pristine_detach initial &&
 464        test_expect_code 1 git cherry-pick base..anotherpick &&
 465        echo "resolved" >foo &&
 466        git add foo &&
 467        git commit &&
 468        sed "s/pick/revert/" .git/sequencer/todo >new_sheet &&
 469        cp new_sheet .git/sequencer/todo &&
 470        test_expect_code 128 git cherry-pick --continue
 471'
 472
 473test_expect_success 'empty commit set' '
 474        pristine_detach initial &&
 475        test_expect_code 128 git cherry-pick base..base
 476'
 477
 478test_expect_success 'malformed instruction sheet 3' '
 479        pristine_detach initial &&
 480        test_expect_code 1 git cherry-pick base..anotherpick &&
 481        echo "resolved" >foo &&
 482        git add foo &&
 483        git commit &&
 484        sed "s/pick \([0-9a-f]*\)/pick $_r10/" .git/sequencer/todo >new_sheet &&
 485        cp new_sheet .git/sequencer/todo &&
 486        test_expect_code 128 git cherry-pick --continue
 487'
 488
 489test_expect_success 'instruction sheet, fat-fingers version' '
 490        pristine_detach initial &&
 491        test_expect_code 1 git cherry-pick base..anotherpick &&
 492        echo "c" >foo &&
 493        git add foo &&
 494        git commit &&
 495        sed "s/pick \([0-9a-f]*\)/pick   \1     /" .git/sequencer/todo >new_sheet &&
 496        cp new_sheet .git/sequencer/todo &&
 497        git cherry-pick --continue
 498'
 499
 500test_expect_success 'commit descriptions in insn sheet are optional' '
 501        pristine_detach initial &&
 502        test_expect_code 1 git cherry-pick base..anotherpick &&
 503        echo "c" >foo &&
 504        git add foo &&
 505        git commit &&
 506        cut -d" " -f1,2 .git/sequencer/todo >new_sheet &&
 507        cp new_sheet .git/sequencer/todo &&
 508        git cherry-pick --continue &&
 509        test_path_is_missing .git/sequencer &&
 510        git rev-list HEAD >commits &&
 511        test_line_count = 4 commits
 512'
 513
 514test_done