summaryrefslogtreecommitdiff
path: root/builtin/merge.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/merge.c')
-rw-r--r--builtin/merge.c57
1 files changed, 43 insertions, 14 deletions
diff --git a/builtin/merge.c b/builtin/merge.c
index 23170f2d2a..f7c92c0e64 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -313,8 +313,16 @@ static int save_state(struct object_id *stash)
int len;
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf buffer = STRBUF_INIT;
+ struct lock_file lock_file = LOCK_INIT;
+ int fd;
int rc = -1;
+ fd = repo_hold_locked_index(the_repository, &lock_file, 0);
+ refresh_cache(REFRESH_QUIET);
+ if (0 <= fd)
+ repo_update_index_if_able(the_repository, &lock_file);
+ rollback_lock_file(&lock_file);
+
strvec_pushl(&cp.args, "stash", "create", NULL);
cp.out = -1;
cp.git_cmd = 1;
@@ -375,22 +383,26 @@ static void reset_hard(const struct object_id *oid, int verbose)
static void restore_state(const struct object_id *head,
const struct object_id *stash)
{
- const char *args[] = { "stash", "apply", NULL, NULL };
-
- if (is_null_oid(stash))
- return;
+ struct strvec args = STRVEC_INIT;
reset_hard(head, 1);
- args[2] = oid_to_hex(stash);
+ if (is_null_oid(stash))
+ goto refresh_cache;
+
+ strvec_pushl(&args, "stash", "apply", "--index", "--quiet", NULL);
+ strvec_push(&args, oid_to_hex(stash));
/*
* It is OK to ignore error here, for example when there was
* nothing to restore.
*/
- run_command_v_opt(args, RUN_GIT_CMD);
+ run_command_v_opt(args.v, RUN_GIT_CMD);
+ strvec_clear(&args);
- refresh_cache(REFRESH_QUIET);
+refresh_cache:
+ if (discard_cache() < 0 || read_cache() < 0)
+ die(_("could not read index"));
}
/* This is called when no merge was necessary. */
@@ -754,8 +766,10 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
else
clean = merge_recursive(&o, head, remoteheads->item,
reversed, &result);
- if (clean < 0)
- exit(128);
+ if (clean < 0) {
+ rollback_lock_file(&lock);
+ return 2;
+ }
if (write_locked_index(&the_index, &lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("unable to write %s"), get_index_file());
@@ -1599,6 +1613,21 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
*/
refresh_cache(REFRESH_QUIET);
if (allow_trivial && fast_forward != FF_ONLY) {
+ /*
+ * Must first ensure that index matches HEAD before
+ * attempting a trivial merge.
+ */
+ struct tree *head_tree = get_commit_tree(head_commit);
+ struct strbuf sb = STRBUF_INIT;
+
+ if (repo_index_has_changes(the_repository, head_tree,
+ &sb)) {
+ error(_("Your local changes to the following files would be overwritten by merge:\n %s"),
+ sb.buf);
+ strbuf_release(&sb);
+ return 2;
+ }
+
/* See if it is really trivial. */
git_committer_info(IDENT_STRICT);
printf(_("Trying really trivial in-index merge...\n"));
@@ -1655,12 +1684,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* tree in the index -- this means that the index must be in
* sync with the head commit. The strategies are responsible
* to ensure this.
+ *
+ * Stash away the local changes so that we can try more than one
+ * and/or recover from merge strategies bailing while leaving the
+ * index and working tree polluted.
*/
- if (use_strategies_nr == 1 ||
- /*
- * Stash away the local changes so that we can try more than one.
- */
- save_state(&stash))
+ if (save_state(&stash))
oidclr(&stash);
for (i = 0; !merge_was_ok && i < use_strategies_nr; i++) {