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