aboutsummaryrefslogtreecommitdiffstats
path: root/builtin/merge.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/merge.c')
-rw-r--r--builtin/merge.c160
1 files changed, 94 insertions, 66 deletions
diff --git a/builtin/merge.c b/builtin/merge.c
index f178f5a3ee..0f093f2a4f 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_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
+ 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;
@@ -337,62 +345,54 @@ out:
return rc;
}
-static void read_empty(const struct object_id *oid, int verbose)
+static void read_empty(const struct object_id *oid)
{
- int i = 0;
- const char *args[7];
-
- args[i++] = "read-tree";
- if (verbose)
- args[i++] = "-v";
- args[i++] = "-m";
- args[i++] = "-u";
- args[i++] = empty_tree_oid_hex();
- args[i++] = oid_to_hex(oid);
- args[i] = NULL;
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ strvec_pushl(&cmd.args, "read-tree", "-m", "-u", empty_tree_oid_hex(),
+ oid_to_hex(oid), NULL);
+ cmd.git_cmd = 1;
- if (run_command_v_opt(args, RUN_GIT_CMD))
+ if (run_command(&cmd))
die(_("read-tree failed"));
}
-static void reset_hard(const struct object_id *oid, int verbose)
+static void reset_hard(const struct object_id *oid)
{
- int i = 0;
- const char *args[6];
-
- args[i++] = "read-tree";
- if (verbose)
- args[i++] = "-v";
- args[i++] = "--reset";
- args[i++] = "-u";
- args[i++] = oid_to_hex(oid);
- args[i] = NULL;
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ strvec_pushl(&cmd.args, "read-tree", "-v", "--reset", "-u",
+ oid_to_hex(oid), NULL);
+ cmd.git_cmd = 1;
- if (run_command_v_opt(args, RUN_GIT_CMD))
+ if (run_command(&cmd))
die(_("read-tree failed"));
}
static void restore_state(const struct object_id *head,
const struct object_id *stash)
{
- struct strbuf sb = STRBUF_INIT;
- const char *args[] = { "stash", "apply", NULL, NULL };
+ struct child_process cmd = CHILD_PROCESS_INIT;
- if (is_null_oid(stash))
- return;
+ reset_hard(head);
- reset_hard(head, 1);
+ if (is_null_oid(stash))
+ goto refresh_cache;
- args[2] = oid_to_hex(stash);
+ strvec_pushl(&cmd.args, "stash", "apply", "--index", "--quiet", NULL);
+ strvec_push(&cmd.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);
+ cmd.git_cmd = 1;
+ run_command(&cmd);
- strbuf_release(&sb);
- refresh_cache(REFRESH_QUIET);
+refresh_cache:
+ discard_cache();
+ if (read_cache() < 0)
+ die(_("could not read index"));
}
/* This is called when no merge was necessary. */
@@ -443,6 +443,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
}
write_file_buf(git_path_squash_msg(the_repository), out.buf, out.len);
strbuf_release(&out);
+ release_revisions(&rev);
}
static void finish(struct commit *head_commit,
@@ -492,7 +493,8 @@ static void finish(struct commit *head_commit,
/* Run a post-merge hook */
run_hooks_l("post-merge", squash ? "1" : "0", NULL);
- apply_autostash(git_path_merge_autostash(the_repository));
+ if (new_head)
+ apply_autostash(git_path_merge_autostash(the_repository));
strbuf_release(&reflog_message);
}
@@ -501,7 +503,6 @@ static void merge_name(const char *remote, struct strbuf *msg)
{
struct commit *remote_head;
struct object_id branch_head;
- struct strbuf buf = STRBUF_INIT;
struct strbuf bname = STRBUF_INIT;
struct merge_remote_desc *desc;
const char *ptr;
@@ -589,7 +590,6 @@ static void merge_name(const char *remote, struct strbuf *msg)
oid_to_hex(&remote_head->object.oid), remote);
cleanup:
free(found_ref);
- strbuf_release(&buf);
strbuf_release(&bname);
}
@@ -694,7 +694,7 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
if (!trees[nr_trees++])
return -1;
opts.fn = threeway_merge;
- cache_tree_free(&active_cache_tree);
+ cache_tree_free(&the_index.cache_tree);
for (i = 0; i < nr_trees; i++) {
parse_tree(trees[i]);
init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
@@ -716,7 +716,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
{
const char *head_arg = "HEAD";
- if (refresh_and_write_cache(REFRESH_QUIET, SKIP_IF_UNCHANGED, 0) < 0)
+ if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET,
+ SKIP_IF_UNCHANGED, 0, NULL, NULL,
+ NULL) < 0)
return error(_("Unable to write index."));
if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree") ||
@@ -750,15 +752,18 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
for (j = common; j; j = j->next)
commit_list_insert(j->item, &reversed);
- hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
+ repo_hold_locked_index(the_repository, &lock,
+ LOCK_DIE_ON_ERROR);
if (!strcmp(strategy, "ort"))
clean = merge_ort_recursive(&o, head, remoteheads->item,
reversed, &result);
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());
@@ -771,7 +776,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
}
static void count_diff_files(struct diff_queue_struct *q,
- struct diff_options *opt, void *data)
+ struct diff_options *opt UNUSED, void *data)
{
int *count = data;
@@ -782,8 +787,8 @@ static int count_unmerged_entries(void)
{
int i, ret = 0;
- for (i = 0; i < active_nr; i++)
- if (ce_stage(active_cache[i]))
+ for (i = 0; i < the_index.cache_nr; i++)
+ if (ce_stage(the_index.cache[i]))
ret++;
return ret;
@@ -857,9 +862,9 @@ static void prepare_to_commit(struct commit_list *remoteheads)
* the editor and after we invoke run_status above.
*/
if (invoked_hook)
- discard_cache();
+ discard_index(&the_index);
}
- read_cache_from(index_file);
+ read_index_from(&the_index, index_file, get_git_dir());
strbuf_addbuf(&msg, &merge_msg);
if (squash)
BUG("the control must not reach here under --squash");
@@ -908,7 +913,9 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
struct object_id result_tree, result_commit;
struct commit_list *parents, **pptr = &parents;
- if (refresh_and_write_cache(REFRESH_QUIET, SKIP_IF_UNCHANGED, 0) < 0)
+ if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET,
+ SKIP_IF_UNCHANGED, 0, NULL, NULL,
+ NULL) < 0)
return error(_("Unable to write index."));
write_tree_trivial(&result_tree);
@@ -998,6 +1005,7 @@ static int evaluate_result(void)
*/
cnt += count_unmerged_entries();
+ release_revisions(&rev);
return cnt;
}
@@ -1373,7 +1381,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
goto done;
}
- if (read_cache_unmerged())
+ if (repo_read_index_unmerged(the_repository))
die_resolve_conflict("merge");
if (file_exists(git_path_merge_head(the_repository))) {
@@ -1394,7 +1402,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."));
}
- resolve_undo_clear();
+ resolve_undo_clear_index(&the_index);
if (option_edit < 0)
option_edit = default_edit_option();
@@ -1457,7 +1465,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
check_trust_level);
remote_head_oid = &remoteheads->item->object.oid;
- read_empty(remote_head_oid, 0);
+ read_empty(remote_head_oid);
update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
goto done;
@@ -1599,8 +1607,23 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* We are not doing octopus, not fast-forward, and have
* only one common.
*/
- refresh_cache(REFRESH_QUIET);
+ refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
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"));
@@ -1657,15 +1680,15 @@ 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++) {
+ for (i = 0; i < use_strategies_nr; i++) {
int ret, cnt;
if (i) {
printf(_("Rewinding the tree to pristine...\n"));
@@ -1680,7 +1703,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
*/
wt_strategy = use_strategies[i]->name;
- ret = try_merge_strategy(use_strategies[i]->name,
+ ret = try_merge_strategy(wt_strategy,
common, remoteheads,
head_commit);
/*
@@ -1690,16 +1713,17 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
*/
if (ret < 2) {
if (!ret) {
- if (option_commit) {
- /* Automerge succeeded. */
- automerge_was_ok = 1;
- break;
- }
+ /*
+ * This strategy worked; no point in trying
+ * another.
+ */
merge_was_ok = 1;
+ best_strategy = wt_strategy;
+ break;
}
cnt = (use_strategies_nr > 1) ? evaluate_result() : 0;
if (best_cnt <= 0 || cnt <= best_cnt) {
- best_strategy = use_strategies[i]->name;
+ best_strategy = wt_strategy;
best_cnt = cnt;
}
}
@@ -1709,7 +1733,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* If we have a resulting tree, that means the strategy module
* auto resolved the merge cleanly.
*/
- if (automerge_was_ok) {
+ if (merge_was_ok && option_commit) {
+ automerge_was_ok = 1;
ret = finish_automerge(head_commit, head_subsumed,
common, remoteheads,
&result_tree, wt_strategy);
@@ -1754,6 +1779,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
"stopped before committing as requested\n"));
else
ret = suggest_conflicts();
+ if (autostash)
+ printf(_("When finished, apply stashed changes with `git stash pop`\n"));
done:
if (!automerge_was_ok) {
@@ -1762,5 +1789,6 @@ done:
}
strbuf_release(&buf);
free(branch_to_free);
+ discard_index(&the_index);
return ret;
}