#!/bin/sh global test_description := ''test aborting in-progress merges Set up repo with conflicting and non-conflicting branches: There are three files foo/bar/baz, and the following graph illustrates the content of these files in each commit: # foo/bar/baz --- foo/bar/bazz <-- master # \ # --- foo/barf/bazf <-- conflict_branch # \ # --- foo/bart/baz <-- clean_branch Next, test git merge --abort with the following variables: - before/after successful merge (should fail when not in merge context) - with/without conflicts - clean/dirty index before merge - clean/dirty worktree before merge - dirty index before merge matches contents on remote branch - changed/unchanged worktree after merge - changed/unchanged index after merge '' source ./test-lib.sh test_expect_success 'setup' ' # Create the above repo echo foo > foo && echo bar > bar && echo baz > baz && git add foo bar baz && git commit -m initial && echo bazz > baz && git commit -a -m "second" && git checkout -b conflict_branch HEAD^ && echo barf > bar && echo bazf > baz && git commit -a -m "conflict" && git checkout -b clean_branch HEAD^ && echo bart > bar && git commit -a -m "clean" && git checkout master ' global pre_merge_head := $[git rev-parse HEAD] test_expect_success 'fails without MERGE_HEAD (unstarted merge)' ' test_must_fail git merge --abort 2>output && test_i18ngrep MERGE_HEAD output ' test_expect_success 'fails without MERGE_HEAD (unstarted merge): .git/MERGE_HEAD sanity' ' test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" ' test_expect_success 'fails without MERGE_HEAD (completed merge)' ' git merge clean_branch && test ! -f .git/MERGE_HEAD && # Merge successfully completed post_merge_head="$(git rev-parse HEAD)" && test_must_fail git merge --abort 2>output && test_i18ngrep MERGE_HEAD output ' test_expect_success 'fails without MERGE_HEAD (completed merge): .git/MERGE_HEAD sanity' ' test ! -f .git/MERGE_HEAD && test "$post_merge_head" = "$(git rev-parse HEAD)" ' test_expect_success 'Forget previous merge' ' git reset --hard "$pre_merge_head" ' test_expect_success 'Abort after --no-commit' ' # Redo merge, but stop before creating merge commit git merge --no-commit clean_branch && test -f .git/MERGE_HEAD && # Abort non-conflicting merge git merge --abort && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff)" && test -z "$(git diff --staged)" ' test_expect_success 'Abort after conflicts' ' # Create conflicting merge test_must_fail git merge conflict_branch && test -f .git/MERGE_HEAD && # Abort conflicting merge git merge --abort && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff)" && test -z "$(git diff --staged)" ' test_expect_success 'Clean merge with dirty index fails' ' echo xyzzy >> foo && git add foo && git diff --staged > expect && test_must_fail git merge clean_branch && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff)" && git diff --staged > actual && test_cmp expect actual ' test_expect_success 'Conflicting merge with dirty index fails' ' test_must_fail git merge conflict_branch && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff)" && git diff --staged > actual && test_cmp expect actual ' test_expect_success 'Reset index (but preserve worktree changes)' ' git reset "$pre_merge_head" && git diff > actual && test_cmp expect actual ' test_expect_success 'Abort clean merge with non-conflicting dirty worktree' ' git merge --no-commit clean_branch && test -f .git/MERGE_HEAD && # Abort merge git merge --abort && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && test_cmp expect actual ' test_expect_success 'Abort conflicting merge with non-conflicting dirty worktree' ' test_must_fail git merge conflict_branch && test -f .git/MERGE_HEAD && # Abort merge git merge --abort && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && test_cmp expect actual ' test_expect_success 'Reset worktree changes' ' git reset --hard "$pre_merge_head" ' test_expect_success 'Fail clean merge with conflicting dirty worktree' ' echo xyzzy >> bar && git diff > expect && test_must_fail git merge --no-commit clean_branch && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && test_cmp expect actual ' test_expect_success 'Fail conflicting merge with conflicting dirty worktree' ' test_must_fail git merge conflict_branch && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && test_cmp expect actual ' test_expect_success 'Reset worktree changes' ' git reset --hard "$pre_merge_head" ' test_expect_success 'Fail clean merge with matching dirty worktree' ' echo bart > bar && git diff > expect && test_must_fail git merge --no-commit clean_branch && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && test_cmp expect actual ' test_expect_success 'Abort clean merge with matching dirty index' ' git add bar && git diff --staged > expect && git merge --no-commit clean_branch && test -f .git/MERGE_HEAD && ### When aborting the merge, git will discard all staged changes, ### including those that were staged pre-merge. In other words, ### --abort will LOSE any staged changes (the staged changes that ### are lost must match the merge result, or the merge would not ### have been allowed to start). Change expectations accordingly: rm expect && touch expect && # Abort merge git merge --abort && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && git diff --staged > actual && test_cmp expect actual && test -z "$(git diff)" ' test_expect_success 'Reset worktree changes' ' git reset --hard "$pre_merge_head" ' test_expect_success 'Fail conflicting merge with matching dirty worktree' ' echo barf > bar && git diff > expect && test_must_fail git merge conflict_branch && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && test -z "$(git diff --staged)" && git diff > actual && test_cmp expect actual ' test_expect_success 'Abort conflicting merge with matching dirty index' ' git add bar && git diff --staged > expect && test_must_fail git merge conflict_branch && test -f .git/MERGE_HEAD && ### When aborting the merge, git will discard all staged changes, ### including those that were staged pre-merge. In other words, ### --abort will LOSE any staged changes (the staged changes that ### are lost must match the merge result, or the merge would not ### have been allowed to start). Change expectations accordingly: rm expect && touch expect && # Abort merge git merge --abort && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && git diff --staged > actual && test_cmp expect actual && test -z "$(git diff)" ' test_expect_success 'Reset worktree changes' ' git reset --hard "$pre_merge_head" ' test_expect_success 'Abort merge with pre- and post-merge worktree changes' ' # Pre-merge worktree changes echo xyzzy > foo && echo barf > bar && git add bar && git diff > expect && git diff --staged > expect-staged && # Perform merge test_must_fail git merge conflict_branch && test -f .git/MERGE_HEAD && # Post-merge worktree changes echo yzxxz > foo && echo blech > baz && ### When aborting the merge, git will discard staged changes (bar) ### and unmerged changes (baz). Other changes that are neither ### staged nor marked as unmerged (foo), will be preserved. For ### these changed, git cannot tell pre-merge changes apart from ### post-merge changes, so the post-merge changes will be ### preserved. Change expectations accordingly: git diff -- foo > expect && rm expect-staged && touch expect-staged && # Abort merge git merge --abort && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && git diff > actual && test_cmp expect actual && git diff --staged > actual-staged && test_cmp expect-staged actual-staged ' test_expect_success 'Reset worktree changes' ' git reset --hard "$pre_merge_head" ' test_expect_success 'Abort merge with pre- and post-merge index changes' ' # Pre-merge worktree changes echo xyzzy > foo && echo barf > bar && git add bar && git diff > expect && git diff --staged > expect-staged && # Perform merge test_must_fail git merge conflict_branch && test -f .git/MERGE_HEAD && # Post-merge worktree changes echo yzxxz > foo && echo blech > baz && git add foo bar && ### When aborting the merge, git will discard all staged changes ### (foo, bar and baz), and no changes will be preserved. Whether ### the changes were staged pre- or post-merge does not matter ### (except for not preventing starting the merge). ### Change expectations accordingly: rm expect expect-staged && touch expect && touch expect-staged && # Abort merge git merge --abort && test ! -f .git/MERGE_HEAD && test "$pre_merge_head" = "$(git rev-parse HEAD)" && git diff > actual && test_cmp expect actual && git diff --staged > actual-staged && test_cmp expect-staged actual-staged ' test_done (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:test_description) op: Equal rhs: { (SQ <"test aborting in-progress merges\n"> <"\n"> <"Set up repo with conflicting and non-conflicting branches:\n"> <"\n"> <"There are three files foo/bar/baz, and the following graph illustrates the\n"> <"content of these files in each commit:\n"> <"\n"> <"# foo/bar/baz --- foo/bar/bazz <-- master\n"> <"# \\\n"> <"# --- foo/barf/bazf <-- conflict_branch\n"> <"# \\\n"> <"# --- foo/bart/baz <-- clean_branch\n"> <"\n"> <"Next, test git merge --abort with the following variables:\n"> <"- before/after successful merge (should fail when not in merge context)\n"> <"- with/without conflicts\n"> <"- clean/dirty index before merge\n"> <"- clean/dirty worktree before merge\n"> <"- dirty index before merge matches contents on remote branch\n"> <"- changed/unchanged worktree after merge\n"> <"- changed/unchanged index after merge\n"> ) } spids: [4] ) ] spids: [4] ) (C {(.)} {(./test-lib.sh)}) (C {(test_expect_success)} {(SQ )} { (SQ <"\n"> <"\t# Create the above repo\n"> <"\techo foo > foo &&\n"> <"\techo bar > bar &&\n"> <"\techo baz > baz &&\n"> <"\tgit add foo bar baz &&\n"> <"\tgit commit -m initial &&\n"> <"\techo bazz > baz &&\n"> <"\tgit commit -a -m \"second\" &&\n"> <"\tgit checkout -b conflict_branch HEAD^ &&\n"> <"\techo barf > bar &&\n"> <"\techo bazf > baz &&\n"> <"\tgit commit -a -m \"conflict\" &&\n"> <"\tgit checkout -b clean_branch HEAD^ &&\n"> <"\techo bart > bar &&\n"> <"\tgit commit -a -m \"clean\" &&\n"> <"\tgit checkout master\n"> ) } ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:pre_merge_head) op: Equal rhs: { (DQ (CommandSubPart command_list: (CommandList children:[(C {(git)} {(rev-parse)} {(HEAD)})]) left_token: spids: [63 69] ) ) } spids: [61] ) ] spids: [61] ) (C {(test_expect_success)} {(SQ <"fails without MERGE_HEAD (unstarted merge)">)} { (SQ <"\n"> <"\ttest_must_fail git merge --abort 2>output &&\n"> <"\ttest_i18ngrep MERGE_HEAD output\n"> ) } ) (C {(test_expect_success)} {(SQ <"fails without MERGE_HEAD (unstarted merge): .git/MERGE_HEAD sanity">)} { (SQ <"\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"fails without MERGE_HEAD (completed merge)">)} { (SQ <"\n"> <"\tgit merge clean_branch &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\t# Merge successfully completed\n"> <"\tpost_merge_head=\"$(git rev-parse HEAD)\" &&\n"> <"\ttest_must_fail git merge --abort 2>output &&\n"> <"\ttest_i18ngrep MERGE_HEAD output\n"> ) } ) (C {(test_expect_success)} {(SQ <"fails without MERGE_HEAD (completed merge): .git/MERGE_HEAD sanity">)} { (SQ <"\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$post_merge_head\" = \"$(git rev-parse HEAD)\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"Forget previous merge">)} {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)} ) (C {(test_expect_success)} {(SQ <"Abort after --no-commit">)} { (SQ <"\n"> <"\t# Redo merge, but stop before creating merge commit\n"> <"\tgit merge --no-commit clean_branch &&\n"> <"\ttest -f .git/MERGE_HEAD &&\n"> <"\t# Abort non-conflicting merge\n"> <"\tgit merge --abort &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\ttest -z \"$(git diff)\" &&\n"> <"\ttest -z \"$(git diff --staged)\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"Abort after conflicts">)} { (SQ <"\n"> <"\t# Create conflicting merge\n"> <"\ttest_must_fail git merge conflict_branch &&\n"> <"\ttest -f .git/MERGE_HEAD &&\n"> <"\t# Abort conflicting merge\n"> <"\tgit merge --abort &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\ttest -z \"$(git diff)\" &&\n"> <"\ttest -z \"$(git diff --staged)\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"Clean merge with dirty index fails">)} { (SQ <"\n"> <"\techo xyzzy >> foo &&\n"> <"\tgit add foo &&\n"> <"\tgit diff --staged > expect &&\n"> <"\ttest_must_fail git merge clean_branch &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\ttest -z \"$(git diff)\" &&\n"> <"\tgit diff --staged > actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"Conflicting merge with dirty index fails">)} { (SQ <"\n"> <"\ttest_must_fail git merge conflict_branch &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\ttest -z \"$(git diff)\" &&\n"> <"\tgit diff --staged > actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"Reset index (but preserve worktree changes)">)} { (SQ <"\n"> <"\tgit reset \"$pre_merge_head\" &&\n"> <"\tgit diff > actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"Abort clean merge with non-conflicting dirty worktree">)} { (SQ <"\n"> <"\tgit merge --no-commit clean_branch &&\n"> <"\ttest -f .git/MERGE_HEAD &&\n"> <"\t# Abort merge\n"> <"\tgit merge --abort &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\ttest -z \"$(git diff --staged)\" &&\n"> <"\tgit diff > actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"Abort conflicting merge with non-conflicting dirty worktree">)} { (SQ <"\n"> <"\ttest_must_fail git merge conflict_branch &&\n"> <"\ttest -f .git/MERGE_HEAD &&\n"> <"\t# Abort merge\n"> <"\tgit merge --abort &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\ttest -z \"$(git diff --staged)\" &&\n"> <"\tgit diff > actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"Reset worktree changes">)} {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)} ) (C {(test_expect_success)} {(SQ <"Fail clean merge with conflicting dirty worktree">)} { (SQ <"\n"> <"\techo xyzzy >> bar &&\n"> <"\tgit diff > expect &&\n"> <"\ttest_must_fail git merge --no-commit clean_branch &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\ttest -z \"$(git diff --staged)\" &&\n"> <"\tgit diff > actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"Fail conflicting merge with conflicting dirty worktree">)} { (SQ <"\n"> <"\ttest_must_fail git merge conflict_branch &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\ttest -z \"$(git diff --staged)\" &&\n"> <"\tgit diff > actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"Reset worktree changes">)} {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)} ) (C {(test_expect_success)} {(SQ <"Fail clean merge with matching dirty worktree">)} { (SQ <"\n"> <"\techo bart > bar &&\n"> <"\tgit diff > expect &&\n"> <"\ttest_must_fail git merge --no-commit clean_branch &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\ttest -z \"$(git diff --staged)\" &&\n"> <"\tgit diff > actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"Abort clean merge with matching dirty index">)} { (SQ <"\n"> <"\tgit add bar &&\n"> <"\tgit diff --staged > expect &&\n"> <"\tgit merge --no-commit clean_branch &&\n"> <"\ttest -f .git/MERGE_HEAD &&\n"> <"\t### When aborting the merge, git will discard all staged changes,\n"> <"\t### including those that were staged pre-merge. In other words,\n"> <"\t### --abort will LOSE any staged changes (the staged changes that\n"> <"\t### are lost must match the merge result, or the merge would not\n"> <"\t### have been allowed to start). Change expectations accordingly:\n"> <"\trm expect &&\n"> <"\ttouch expect &&\n"> <"\t# Abort merge\n"> <"\tgit merge --abort &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\tgit diff --staged > actual &&\n"> <"\ttest_cmp expect actual &&\n"> <"\ttest -z \"$(git diff)\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"Reset worktree changes">)} {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)} ) (C {(test_expect_success)} {(SQ <"Fail conflicting merge with matching dirty worktree">)} { (SQ <"\n"> <"\techo barf > bar &&\n"> <"\tgit diff > expect &&\n"> <"\ttest_must_fail git merge conflict_branch &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\ttest -z \"$(git diff --staged)\" &&\n"> <"\tgit diff > actual &&\n"> <"\ttest_cmp expect actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"Abort conflicting merge with matching dirty index">)} { (SQ <"\n"> <"\tgit add bar &&\n"> <"\tgit diff --staged > expect &&\n"> <"\ttest_must_fail git merge conflict_branch &&\n"> <"\ttest -f .git/MERGE_HEAD &&\n"> <"\t### When aborting the merge, git will discard all staged changes,\n"> <"\t### including those that were staged pre-merge. In other words,\n"> <"\t### --abort will LOSE any staged changes (the staged changes that\n"> <"\t### are lost must match the merge result, or the merge would not\n"> <"\t### have been allowed to start). Change expectations accordingly:\n"> <"\trm expect &&\n"> <"\ttouch expect &&\n"> <"\t# Abort merge\n"> <"\tgit merge --abort &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\tgit diff --staged > actual &&\n"> <"\ttest_cmp expect actual &&\n"> <"\ttest -z \"$(git diff)\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"Reset worktree changes">)} {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)} ) (C {(test_expect_success)} {(SQ <"Abort merge with pre- and post-merge worktree changes">)} { (SQ <"\n"> <"\t# Pre-merge worktree changes\n"> <"\techo xyzzy > foo &&\n"> <"\techo barf > bar &&\n"> <"\tgit add bar &&\n"> <"\tgit diff > expect &&\n"> <"\tgit diff --staged > expect-staged &&\n"> <"\t# Perform merge\n"> <"\ttest_must_fail git merge conflict_branch &&\n"> <"\ttest -f .git/MERGE_HEAD &&\n"> <"\t# Post-merge worktree changes\n"> <"\techo yzxxz > foo &&\n"> <"\techo blech > baz &&\n"> <"\t### When aborting the merge, git will discard staged changes (bar)\n"> <"\t### and unmerged changes (baz). Other changes that are neither\n"> <"\t### staged nor marked as unmerged (foo), will be preserved. For\n"> <"\t### these changed, git cannot tell pre-merge changes apart from\n"> <"\t### post-merge changes, so the post-merge changes will be\n"> <"\t### preserved. Change expectations accordingly:\n"> <"\tgit diff -- foo > expect &&\n"> <"\trm expect-staged &&\n"> <"\ttouch expect-staged &&\n"> <"\t# Abort merge\n"> <"\tgit merge --abort &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\tgit diff > actual &&\n"> <"\ttest_cmp expect actual &&\n"> <"\tgit diff --staged > actual-staged &&\n"> <"\ttest_cmp expect-staged actual-staged\n"> ) } ) (C {(test_expect_success)} {(SQ <"Reset worktree changes">)} {(SQ <"\n"> <"\tgit reset --hard \"$pre_merge_head\"\n">)} ) (C {(test_expect_success)} {(SQ <"Abort merge with pre- and post-merge index changes">)} { (SQ <"\n"> <"\t# Pre-merge worktree changes\n"> <"\techo xyzzy > foo &&\n"> <"\techo barf > bar &&\n"> <"\tgit add bar &&\n"> <"\tgit diff > expect &&\n"> <"\tgit diff --staged > expect-staged &&\n"> <"\t# Perform merge\n"> <"\ttest_must_fail git merge conflict_branch &&\n"> <"\ttest -f .git/MERGE_HEAD &&\n"> <"\t# Post-merge worktree changes\n"> <"\techo yzxxz > foo &&\n"> <"\techo blech > baz &&\n"> <"\tgit add foo bar &&\n"> <"\t### When aborting the merge, git will discard all staged changes\n"> <"\t### (foo, bar and baz), and no changes will be preserved. Whether\n"> <"\t### the changes were staged pre- or post-merge does not matter\n"> <"\t### (except for not preventing starting the merge).\n"> <"\t### Change expectations accordingly:\n"> <"\trm expect expect-staged &&\n"> <"\ttouch expect &&\n"> <"\ttouch expect-staged &&\n"> <"\t# Abort merge\n"> <"\tgit merge --abort &&\n"> <"\ttest ! -f .git/MERGE_HEAD &&\n"> <"\ttest \"$pre_merge_head\" = \"$(git rev-parse HEAD)\" &&\n"> <"\tgit diff > actual &&\n"> <"\ttest_cmp expect actual &&\n"> <"\tgit diff --staged > actual-staged &&\n"> <"\ttest_cmp expect-staged actual-staged\n"> ) } ) (C {(test_done)}) ] )