Skip to content

Commit

Permalink
Provide 'git merge --abort' as a synonym to 'git reset --merge'
Browse files Browse the repository at this point in the history
Teach 'git merge' the --abort option, which verifies the existence of
MERGE_HEAD and then invokes 'git reset --merge' to abort the current
in-progress merge and attempt to reconstruct the pre-merge state.

The reason for adding this option is to provide a user interface for
aborting an in-progress merge that is consistent with the interface
for aborting a rebase ('git rebase --abort'), aborting the application
of a patch series ('git am --abort'), and aborting an in-progress notes
merge ('git notes merge --abort').

The patch includes documentation and testcases that explain and verify
the various scenarios in which 'git merge --abort' can run. The
testcases also document the cases in which 'git merge --abort' is
unable to correctly restore the pre-merge state (look for the '###'
comments towards the bottom of t/t7609-merge-abort.sh).

This patch has been improved by the following contributions:
- Jonathan Nieder: Move test documentation into test_description

Thanks-to: Jonathan Nieder <[email protected]>
Signed-off-by: Johan Herland <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
jherland authored and gitster committed Nov 17, 2010
1 parent 2a22c1b commit 35d2fff
Show file tree
Hide file tree
Showing 3 changed files with 351 additions and 3 deletions.
27 changes: 24 additions & 3 deletions Documentation/git-merge.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ SYNOPSIS
[-s <strategy>] [-X <strategy-option>]
[--[no-]rerere-autoupdate] [-m <msg>] <commit>...
'git merge' <msg> HEAD <commit>...
'git merge' --abort

DESCRIPTION
-----------
Expand Down Expand Up @@ -47,6 +48,14 @@ The second syntax (<msg> `HEAD` <commit>...) is supported for
historical reasons. Do not use it from the command line or in
new scripts. It is the same as `git merge -m <msg> <commit>...`.

The third syntax ("`git merge --abort`") can only be run after the
merge has resulted in conflicts. 'git merge --abort' will abort the
merge process and try to reconstruct the pre-merge state. However,
if there were uncommitted changes when the merge started (and
especially if those changes were further modified after the merge
was started), 'git merge --abort' will in some cases be unable to
reconstruct the original (pre-merge) changes. Therefore:

*Warning*: Running 'git merge' with uncommitted changes is
discouraged: while possible, it leaves you in a state that is hard to
back out of in the case of a conflict.
Expand All @@ -72,6 +81,18 @@ include::merge-options.txt[]
Allow the rerere mechanism to update the index with the
result of auto-conflict resolution if possible.

--abort::
Abort the current conflict resolution process, and
try to reconstruct the pre-merge state.
+
If there were uncommitted worktree changes present when the merge
started, 'git merge --abort' will in some cases be unable to
reconstruct these changes. It is therefore recommended to always
commit or stash your changes before running 'git merge'.
+
'git merge --abort' is equivalent to 'git reset --merge' when
`MERGE_HEAD` is present.

<commit>...::
Commits, usually other branch heads, to merge into our branch.
You need at least one <commit>. Specifying more than one
Expand Down Expand Up @@ -142,7 +163,7 @@ happens:
i.e. matching `HEAD`.

If you tried a merge which resulted in complex conflicts and
want to start over, you can recover with `git reset --merge`.
want to start over, you can recover with `git merge --abort`.

HOW CONFLICTS ARE PRESENTED
---------------------------
Expand Down Expand Up @@ -213,8 +234,8 @@ After seeing a conflict, you can do two things:

* Decide not to merge. The only clean-ups you need are to reset
the index file to the `HEAD` commit to reverse 2. and to clean
up working tree changes made by 2. and 3.; `git-reset --hard` can
be used for this.
up working tree changes made by 2. and 3.; `git merge --abort`
can be used for this.

* Resolve the conflicts. Git will mark the conflicts in
the working tree. Edit the files into shape and
Expand Down
14 changes: 14 additions & 0 deletions builtin/merge.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ static size_t xopts_nr, xopts_alloc;
static const char *branch;
static int verbosity;
static int allow_rerere_auto;
static int abort_current_merge;

static struct strategy all_strategy[] = {
{ "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL },
Expand Down Expand Up @@ -194,6 +195,8 @@ static struct option builtin_merge_options[] = {
"message to be used for the merge commit (if any)",
option_parse_message),
OPT__VERBOSITY(&verbosity),
OPT_BOOLEAN(0, "abort", &abort_current_merge,
"abort the current in-progress merge"),
OPT_END()
};

Expand Down Expand Up @@ -914,6 +917,17 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, builtin_merge_options,
builtin_merge_usage, 0);

if (abort_current_merge) {
int nargc = 2;
const char *nargv[] = {"reset", "--merge", NULL};

if (!file_exists(git_path("MERGE_HEAD")))
die("There is no merge to abort (MERGE_HEAD missing).");

/* Invoke 'git reset --merge' */
return cmd_reset(nargc, nargv, prefix);
}

if (read_cache_unmerged())
die_resolve_conflict("merge");

Expand Down
Loading

0 comments on commit 35d2fff

Please sign in to comment.