t / t7611-merge-abort.shon commit Merge branch 'maint-1.7.3' into maint-1.7.4 (ed36a48)
   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        grep -q MERGE_HEAD output &&
  51        test ! -f .git/MERGE_HEAD &&
  52        test "$pre_merge_head" = "$(git rev-parse HEAD)"
  53'
  54
  55test_expect_success 'fails without MERGE_HEAD (completed merge)' '
  56        git merge clean_branch &&
  57        test ! -f .git/MERGE_HEAD &&
  58        # Merge successfully completed
  59        post_merge_head="$(git rev-parse HEAD)" &&
  60        test_must_fail git merge --abort 2>output &&
  61        grep -q MERGE_HEAD output &&
  62        test ! -f .git/MERGE_HEAD &&
  63        test "$post_merge_head" = "$(git rev-parse HEAD)"
  64'
  65
  66test_expect_success 'Forget previous merge' '
  67        git reset --hard "$pre_merge_head"
  68'
  69
  70test_expect_success 'Abort after --no-commit' '
  71        # Redo merge, but stop before creating merge commit
  72        git merge --no-commit clean_branch &&
  73        test -f .git/MERGE_HEAD &&
  74        # Abort non-conflicting merge
  75        git merge --abort &&
  76        test ! -f .git/MERGE_HEAD &&
  77        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
  78        test -z "$(git diff)" &&
  79        test -z "$(git diff --staged)"
  80'
  81
  82test_expect_success 'Abort after conflicts' '
  83        # Create conflicting merge
  84        test_must_fail git merge conflict_branch &&
  85        test -f .git/MERGE_HEAD &&
  86        # Abort 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 'Clean merge with dirty index fails' '
  95        echo xyzzy >> foo &&
  96        git add foo &&
  97        git diff --staged > expect &&
  98        test_must_fail git merge clean_branch &&
  99        test ! -f .git/MERGE_HEAD &&
 100        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 101        test -z "$(git diff)" &&
 102        git diff --staged > actual &&
 103        test_cmp expect actual
 104'
 105
 106test_expect_success 'Conflicting merge with dirty index fails' '
 107        test_must_fail git merge conflict_branch &&
 108        test ! -f .git/MERGE_HEAD &&
 109        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 110        test -z "$(git diff)" &&
 111        git diff --staged > actual &&
 112        test_cmp expect actual
 113'
 114
 115test_expect_success 'Reset index (but preserve worktree changes)' '
 116        git reset "$pre_merge_head" &&
 117        git diff > actual &&
 118        test_cmp expect actual
 119'
 120
 121test_expect_success 'Abort clean merge with non-conflicting dirty worktree' '
 122        git merge --no-commit clean_branch &&
 123        test -f .git/MERGE_HEAD &&
 124        # Abort merge
 125        git merge --abort &&
 126        test ! -f .git/MERGE_HEAD &&
 127        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 128        test -z "$(git diff --staged)" &&
 129        git diff > actual &&
 130        test_cmp expect actual
 131'
 132
 133test_expect_success 'Abort conflicting merge with non-conflicting dirty worktree' '
 134        test_must_fail git merge conflict_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 'Reset worktree changes' '
 146        git reset --hard "$pre_merge_head"
 147'
 148
 149test_expect_success 'Fail clean merge with conflicting dirty worktree' '
 150        echo xyzzy >> bar &&
 151        git diff > expect &&
 152        test_must_fail git merge --no-commit clean_branch &&
 153        test ! -f .git/MERGE_HEAD &&
 154        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 155        test -z "$(git diff --staged)" &&
 156        git diff > actual &&
 157        test_cmp expect actual
 158'
 159
 160test_expect_success 'Fail conflicting merge with conflicting dirty worktree' '
 161        test_must_fail git merge conflict_branch &&
 162        test ! -f .git/MERGE_HEAD &&
 163        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 164        test -z "$(git diff --staged)" &&
 165        git diff > actual &&
 166        test_cmp expect actual
 167'
 168
 169test_expect_success 'Reset worktree changes' '
 170        git reset --hard "$pre_merge_head"
 171'
 172
 173test_expect_success 'Fail clean merge with matching dirty worktree' '
 174        echo bart > bar &&
 175        git diff > expect &&
 176        test_must_fail git merge --no-commit clean_branch &&
 177        test ! -f .git/MERGE_HEAD &&
 178        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 179        test -z "$(git diff --staged)" &&
 180        git diff > actual &&
 181        test_cmp expect actual
 182'
 183
 184test_expect_success 'Abort clean merge with matching dirty index' '
 185        git add bar &&
 186        git diff --staged > expect &&
 187        git merge --no-commit clean_branch &&
 188        test -f .git/MERGE_HEAD &&
 189        ### When aborting the merge, git will discard all staged changes,
 190        ### including those that were staged pre-merge. In other words,
 191        ### --abort will LOSE any staged changes (the staged changes that
 192        ### are lost must match the merge result, or the merge would not
 193        ### have been allowed to start). Change expectations accordingly:
 194        rm expect &&
 195        touch expect &&
 196        # Abort merge
 197        git merge --abort &&
 198        test ! -f .git/MERGE_HEAD &&
 199        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 200        git diff --staged > actual &&
 201        test_cmp expect actual &&
 202        test -z "$(git diff)"
 203'
 204
 205test_expect_success 'Reset worktree changes' '
 206        git reset --hard "$pre_merge_head"
 207'
 208
 209test_expect_success 'Fail conflicting merge with matching dirty worktree' '
 210        echo barf > bar &&
 211        git diff > expect &&
 212        test_must_fail git merge conflict_branch &&
 213        test ! -f .git/MERGE_HEAD &&
 214        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 215        test -z "$(git diff --staged)" &&
 216        git diff > actual &&
 217        test_cmp expect actual
 218'
 219
 220test_expect_success 'Abort conflicting merge with matching dirty index' '
 221        git add bar &&
 222        git diff --staged > expect &&
 223        test_must_fail git merge conflict_branch &&
 224        test -f .git/MERGE_HEAD &&
 225        ### When aborting the merge, git will discard all staged changes,
 226        ### including those that were staged pre-merge. In other words,
 227        ### --abort will LOSE any staged changes (the staged changes that
 228        ### are lost must match the merge result, or the merge would not
 229        ### have been allowed to start). Change expectations accordingly:
 230        rm expect &&
 231        touch expect &&
 232        # Abort merge
 233        git merge --abort &&
 234        test ! -f .git/MERGE_HEAD &&
 235        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 236        git diff --staged > actual &&
 237        test_cmp expect actual &&
 238        test -z "$(git diff)"
 239'
 240
 241test_expect_success 'Reset worktree changes' '
 242        git reset --hard "$pre_merge_head"
 243'
 244
 245test_expect_success 'Abort merge with pre- and post-merge worktree changes' '
 246        # Pre-merge worktree changes
 247        echo xyzzy > foo &&
 248        echo barf > bar &&
 249        git add bar &&
 250        git diff > expect &&
 251        git diff --staged > expect-staged &&
 252        # Perform merge
 253        test_must_fail git merge conflict_branch &&
 254        test -f .git/MERGE_HEAD &&
 255        # Post-merge worktree changes
 256        echo yzxxz > foo &&
 257        echo blech > baz &&
 258        ### When aborting the merge, git will discard staged changes (bar)
 259        ### and unmerged changes (baz). Other changes that are neither
 260        ### staged nor marked as unmerged (foo), will be preserved. For
 261        ### these changed, git cannot tell pre-merge changes apart from
 262        ### post-merge changes, so the post-merge changes will be
 263        ### preserved. Change expectations accordingly:
 264        git diff -- foo > expect &&
 265        rm expect-staged &&
 266        touch expect-staged &&
 267        # Abort merge
 268        git merge --abort &&
 269        test ! -f .git/MERGE_HEAD &&
 270        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 271        git diff > actual &&
 272        test_cmp expect actual &&
 273        git diff --staged > actual-staged &&
 274        test_cmp expect-staged actual-staged
 275'
 276
 277test_expect_success 'Reset worktree changes' '
 278        git reset --hard "$pre_merge_head"
 279'
 280
 281test_expect_success 'Abort merge with pre- and post-merge index changes' '
 282        # Pre-merge worktree changes
 283        echo xyzzy > foo &&
 284        echo barf > bar &&
 285        git add bar &&
 286        git diff > expect &&
 287        git diff --staged > expect-staged &&
 288        # Perform merge
 289        test_must_fail git merge conflict_branch &&
 290        test -f .git/MERGE_HEAD &&
 291        # Post-merge worktree changes
 292        echo yzxxz > foo &&
 293        echo blech > baz &&
 294        git add foo bar &&
 295        ### When aborting the merge, git will discard all staged changes
 296        ### (foo, bar and baz), and no changes will be preserved. Whether
 297        ### the changes were staged pre- or post-merge does not matter
 298        ### (except for not preventing starting the merge).
 299        ### Change expectations accordingly:
 300        rm expect expect-staged &&
 301        touch expect &&
 302        touch expect-staged &&
 303        # Abort merge
 304        git merge --abort &&
 305        test ! -f .git/MERGE_HEAD &&
 306        test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
 307        git diff > actual &&
 308        test_cmp expect actual &&
 309        git diff --staged > actual-staged &&
 310        test_cmp expect-staged actual-staged
 311'
 312
 313test_done