| #!/bin/sh | 
 |  | 
 | 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 | 
 | ' | 
 | . ./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 | 
 | ' | 
 |  | 
 | 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 |