t / t7611-merge-abort.shon commit Merge remote-tracking branch 'ko/maint' into jc/diff-index-quick-exit-early (2d11f21)
   1#!/bin/sh
   2
   3test_description='test aborting in-progress merges
   4
   5Set up repo with conflicting and non-conflicting branches:
   6
   7There are three files foo/bar/baz, and the following graph illustrates the
   8content of these files in each commit:
   9
  10# foo/bar/baz --- foo/bar/bazz     <-- master
  11#             \
  12#              --- foo/barf/bazf   <-- conflict_branch
  13#               \
  14#                --- foo/bart/baz  <-- clean_branch
  15
  16Next, test git merge --abort with the following variables:
  17- before/after successful merge (should fail when not in merge context)
  18- with/without conflicts
  19- clean/dirty index before merge
  20- clean/dirty worktree before merge
  21- dirty index before merge matches contents on remote branch
  22- changed/unchanged worktree after merge
  23- changed/unchanged index after merge
  24'
  25. ./test-lib.sh
  26
  27test_expect_success 'setup' '
  28        # Create the above repo
  29        echo foo > foo &&
  30        echo bar > bar &&
  31        echo baz > baz &&
  32        git add foo bar baz &&
  33        git commit -m initial &&
  34        echo bazz > baz &&
  35        git commit -a -m "second" &&
  36        git checkout -b conflict_branch HEAD^ &&
  37        echo barf > bar &&
  38        echo bazf > baz &&
  39        git commit -a -m "conflict" &&
  40        git checkout -b clean_branch HEAD^ &&
  41        echo bart > bar &&
  42        git commit -a -m "clean" &&
  43        git checkout master
  44'
  45
  46pre_merge_head="$(git rev-parse HEAD)"
  47
  48test_expect_success 'fails without MERGE_HEAD (unstarted merge)' '
  49        test_must_fail git merge --abort 2>output
  50'
  51
  52test_expect_success C_LOCALE_OUTPUT 'fails without MERGE_HEAD (unstarted merge): fatal output' '
  53        grep -q MERGE_HEAD output
  54'
  55
  56test_expect_success 'fails without MERGE_HEAD (unstarted merge): .git/MERGE_HEAD sanity' '
  57        test ! -f .git/MERGE_HEAD &&
  58        test "$pre_merge_head" = "$(git rev-parse HEAD)"
  59'
  60
  61test_expect_success 'fails without MERGE_HEAD (completed merge)' '
  62        git merge clean_branch &&
  63        test ! -f .git/MERGE_HEAD &&
  64        # Merge successfully completed
  65        post_merge_head="$(git rev-parse HEAD)" &&
  66        test_must_fail git merge --abort 2>output
  67'
  68
  69test_expect_success C_LOCALE_OUTPUT 'fails without MERGE_HEAD (completed merge): output' '
  70        grep -q MERGE_HEAD output
  71'
  72
  73test_expect_success 'fails without MERGE_HEAD (completed merge): .git/MERGE_HEAD sanity' '
  74        test ! -f .git/MERGE_HEAD &&
  75        test "$post_merge_head" = "$(git rev-parse HEAD)"
  76'
  77
  78test_expect_success 'Forget previous merge' '
  79        git reset --hard "$pre_merge_head"
  80'
  81
  82test_expect_success 'Abort after --no-commit' '
  83        # Redo merge, but stop before creating merge commit
  84        git merge --no-commit clean_branch &&
  85        test -f .git/MERGE_HEAD &&
  86        # Abort non-conflicting merge
  87        git merge --abort &&
  88        test ! -f .git/MERGE_HEAD &&
  89        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
  90        test -z "$(git diff)" &&
  91        test -z "$(git diff --staged)"
  92'
  93
  94test_expect_success 'Abort after conflicts' '
  95        # Create conflicting merge
  96        test_must_fail git merge conflict_branch &&
  97        test -f .git/MERGE_HEAD &&
  98        # Abort conflicting merge
  99        git merge --abort &&
 100        test ! -f .git/MERGE_HEAD &&
 101        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 102        test -z "$(git diff)" &&
 103        test -z "$(git diff --staged)"
 104'
 105
 106test_expect_success 'Clean merge with dirty index fails' '
 107        echo xyzzy >> foo &&
 108        git add foo &&
 109        git diff --staged > expect &&
 110        test_must_fail git merge clean_branch &&
 111        test ! -f .git/MERGE_HEAD &&
 112        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 113        test -z "$(git diff)" &&
 114        git diff --staged > actual &&
 115        test_cmp expect actual
 116'
 117
 118test_expect_success 'Conflicting merge with dirty index fails' '
 119        test_must_fail git merge conflict_branch &&
 120        test ! -f .git/MERGE_HEAD &&
 121        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 122        test -z "$(git diff)" &&
 123        git diff --staged > actual &&
 124        test_cmp expect actual
 125'
 126
 127test_expect_success 'Reset index (but preserve worktree changes)' '
 128        git reset "$pre_merge_head" &&
 129        git diff > actual &&
 130        test_cmp expect actual
 131'
 132
 133test_expect_success 'Abort clean merge with non-conflicting dirty worktree' '
 134        git merge --no-commit clean_branch &&
 135        test -f .git/MERGE_HEAD &&
 136        # Abort merge
 137        git merge --abort &&
 138        test ! -f .git/MERGE_HEAD &&
 139        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 140        test -z "$(git diff --staged)" &&
 141        git diff > actual &&
 142        test_cmp expect actual
 143'
 144
 145test_expect_success 'Abort conflicting merge with non-conflicting dirty worktree' '
 146        test_must_fail git merge conflict_branch &&
 147        test -f .git/MERGE_HEAD &&
 148        # Abort merge
 149        git merge --abort &&
 150        test ! -f .git/MERGE_HEAD &&
 151        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 152        test -z "$(git diff --staged)" &&
 153        git diff > actual &&
 154        test_cmp expect actual
 155'
 156
 157test_expect_success 'Reset worktree changes' '
 158        git reset --hard "$pre_merge_head"
 159'
 160
 161test_expect_success 'Fail clean merge with conflicting dirty worktree' '
 162        echo xyzzy >> bar &&
 163        git diff > expect &&
 164        test_must_fail git merge --no-commit clean_branch &&
 165        test ! -f .git/MERGE_HEAD &&
 166        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 167        test -z "$(git diff --staged)" &&
 168        git diff > actual &&
 169        test_cmp expect actual
 170'
 171
 172test_expect_success 'Fail conflicting merge with conflicting dirty worktree' '
 173        test_must_fail git merge conflict_branch &&
 174        test ! -f .git/MERGE_HEAD &&
 175        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 176        test -z "$(git diff --staged)" &&
 177        git diff > actual &&
 178        test_cmp expect actual
 179'
 180
 181test_expect_success 'Reset worktree changes' '
 182        git reset --hard "$pre_merge_head"
 183'
 184
 185test_expect_success 'Fail clean merge with matching dirty worktree' '
 186        echo bart > bar &&
 187        git diff > expect &&
 188        test_must_fail git merge --no-commit clean_branch &&
 189        test ! -f .git/MERGE_HEAD &&
 190        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 191        test -z "$(git diff --staged)" &&
 192        git diff > actual &&
 193        test_cmp expect actual
 194'
 195
 196test_expect_success 'Abort clean merge with matching dirty index' '
 197        git add bar &&
 198        git diff --staged > expect &&
 199        git merge --no-commit clean_branch &&
 200        test -f .git/MERGE_HEAD &&
 201        ### When aborting the merge, git will discard all staged changes,
 202        ### including those that were staged pre-merge. In other words,
 203        ### --abort will LOSE any staged changes (the staged changes that
 204        ### are lost must match the merge result, or the merge would not
 205        ### have been allowed to start). Change expectations accordingly:
 206        rm expect &&
 207        touch expect &&
 208        # Abort merge
 209        git merge --abort &&
 210        test ! -f .git/MERGE_HEAD &&
 211        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 212        git diff --staged > actual &&
 213        test_cmp expect actual &&
 214        test -z "$(git diff)"
 215'
 216
 217test_expect_success 'Reset worktree changes' '
 218        git reset --hard "$pre_merge_head"
 219'
 220
 221test_expect_success 'Fail conflicting merge with matching dirty worktree' '
 222        echo barf > bar &&
 223        git diff > expect &&
 224        test_must_fail git merge conflict_branch &&
 225        test ! -f .git/MERGE_HEAD &&
 226        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 227        test -z "$(git diff --staged)" &&
 228        git diff > actual &&
 229        test_cmp expect actual
 230'
 231
 232test_expect_success 'Abort conflicting merge with matching dirty index' '
 233        git add bar &&
 234        git diff --staged > expect &&
 235        test_must_fail git merge conflict_branch &&
 236        test -f .git/MERGE_HEAD &&
 237        ### When aborting the merge, git will discard all staged changes,
 238        ### including those that were staged pre-merge. In other words,
 239        ### --abort will LOSE any staged changes (the staged changes that
 240        ### are lost must match the merge result, or the merge would not
 241        ### have been allowed to start). Change expectations accordingly:
 242        rm expect &&
 243        touch expect &&
 244        # Abort merge
 245        git merge --abort &&
 246        test ! -f .git/MERGE_HEAD &&
 247        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 248        git diff --staged > actual &&
 249        test_cmp expect actual &&
 250        test -z "$(git diff)"
 251'
 252
 253test_expect_success 'Reset worktree changes' '
 254        git reset --hard "$pre_merge_head"
 255'
 256
 257test_expect_success 'Abort merge with pre- and post-merge worktree changes' '
 258        # Pre-merge worktree changes
 259        echo xyzzy > foo &&
 260        echo barf > bar &&
 261        git add bar &&
 262        git diff > expect &&
 263        git diff --staged > expect-staged &&
 264        # Perform merge
 265        test_must_fail git merge conflict_branch &&
 266        test -f .git/MERGE_HEAD &&
 267        # Post-merge worktree changes
 268        echo yzxxz > foo &&
 269        echo blech > baz &&
 270        ### When aborting the merge, git will discard staged changes (bar)
 271        ### and unmerged changes (baz). Other changes that are neither
 272        ### staged nor marked as unmerged (foo), will be preserved. For
 273        ### these changed, git cannot tell pre-merge changes apart from
 274        ### post-merge changes, so the post-merge changes will be
 275        ### preserved. Change expectations accordingly:
 276        git diff -- foo > expect &&
 277        rm expect-staged &&
 278        touch expect-staged &&
 279        # Abort merge
 280        git merge --abort &&
 281        test ! -f .git/MERGE_HEAD &&
 282        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 283        git diff > actual &&
 284        test_cmp expect actual &&
 285        git diff --staged > actual-staged &&
 286        test_cmp expect-staged actual-staged
 287'
 288
 289test_expect_success 'Reset worktree changes' '
 290        git reset --hard "$pre_merge_head"
 291'
 292
 293test_expect_success 'Abort merge with pre- and post-merge index changes' '
 294        # Pre-merge worktree changes
 295        echo xyzzy > foo &&
 296        echo barf > bar &&
 297        git add bar &&
 298        git diff > expect &&
 299        git diff --staged > expect-staged &&
 300        # Perform merge
 301        test_must_fail git merge conflict_branch &&
 302        test -f .git/MERGE_HEAD &&
 303        # Post-merge worktree changes
 304        echo yzxxz > foo &&
 305        echo blech > baz &&
 306        git add foo bar &&
 307        ### When aborting the merge, git will discard all staged changes
 308        ### (foo, bar and baz), and no changes will be preserved. Whether
 309        ### the changes were staged pre- or post-merge does not matter
 310        ### (except for not preventing starting the merge).
 311        ### Change expectations accordingly:
 312        rm expect expect-staged &&
 313        touch expect &&
 314        touch expect-staged &&
 315        # Abort merge
 316        git merge --abort &&
 317        test ! -f .git/MERGE_HEAD &&
 318        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 319        git diff > actual &&
 320        test_cmp expect actual &&
 321        git diff --staged > actual-staged &&
 322        test_cmp expect-staged actual-staged
 323'
 324
 325test_done