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