Pass a (ref_cache *) to the resolve_gitlink_*() helper functions
[gitweb.git] / builtin / merge.c
index 7d593097dea987e580d1e79f010faf23c1f98fb0..a1c85344b2b54f957ea69ace864ea99b7d295405 100644 (file)
@@ -26,6 +26,7 @@
 #include "merge-recursive.h"
 #include "resolve-undo.h"
 #include "remote.h"
+#include "fmt-merge-msg.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -44,9 +45,9 @@ static const char * const builtin_merge_usage[] = {
        NULL
 };
 
-static int show_diffstat = 1, shortlog_len, squash;
+static int show_diffstat = 1, shortlog_len = -1, squash;
 static int option_commit = 1, allow_fast_forward = 1;
-static int fast_forward_only;
+static int fast_forward_only, option_edit;
 static int allow_trivial = 1, have_message;
 static struct strbuf merge_msg;
 static struct commit_list *remoteheads;
@@ -189,6 +190,8 @@ static struct option builtin_merge_options[] = {
                "create a single commit instead of doing a merge"),
        OPT_BOOLEAN(0, "commit", &option_commit,
                "perform a commit if the merge succeeds (default)"),
+       OPT_BOOLEAN('e', "edit", &option_edit,
+               "edit message before committing"),
        OPT_BOOLEAN(0, "ff", &allow_fast_forward,
                "allow fast-forward (default)"),
        OPT_BOOLEAN(0, "ff-only", &fast_forward_only,
@@ -314,13 +317,15 @@ static void squash_message(struct commit *commit)
        struct rev_info rev;
        struct strbuf out = STRBUF_INIT;
        struct commit_list *j;
+       const char *filename;
        int fd;
        struct pretty_print_context ctx = {0};
 
        printf(_("Squash commit -- not updating HEAD\n"));
-       fd = open(git_path("SQUASH_MSG"), O_WRONLY | O_CREAT, 0666);
+       filename = git_path("SQUASH_MSG");
+       fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
-               die_errno(_("Could not write to '%s'"), git_path("SQUASH_MSG"));
+               die_errno(_("Could not write to '%s'"), filename);
 
        init_revisions(&rev, NULL);
        rev.ignore_merges = 1;
@@ -404,21 +409,11 @@ static void finish(struct commit *head_commit,
        strbuf_release(&reflog_message);
 }
 
-static struct object *want_commit(const char *name)
-{
-       struct object *obj;
-       unsigned char sha1[20];
-       if (get_sha1(name, sha1))
-               return NULL;
-       obj = parse_object(sha1);
-       return peel_to_type(name, 0, obj, OBJ_COMMIT);
-}
-
 /* Get the name for the merge commit's message. */
 static void merge_name(const char *remote, struct strbuf *msg)
 {
-       struct object *remote_head;
-       unsigned char branch_head[20], buf_sha[20];
+       struct commit *remote_head;
+       unsigned char branch_head[20];
        struct strbuf buf = STRBUF_INIT;
        struct strbuf bname = STRBUF_INIT;
        const char *ptr;
@@ -429,7 +424,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
        remote = bname.buf;
 
        memset(branch_head, 0, sizeof(branch_head));
-       remote_head = want_commit(remote);
+       remote_head = get_merge_parent(remote);
        if (!remote_head)
                die(_("'%s' does not point to a commit"), remote);
 
@@ -439,6 +434,11 @@ static void merge_name(const char *remote, struct strbuf *msg)
                                    sha1_to_hex(branch_head), remote);
                        goto cleanup;
                }
+               if (!prefixcmp(found_ref, "refs/tags/")) {
+                       strbuf_addf(msg, "%s\t\ttag '%s' of .\n",
+                                   sha1_to_hex(branch_head), remote);
+                       goto cleanup;
+               }
                if (!prefixcmp(found_ref, "refs/remotes/")) {
                        strbuf_addf(msg, "%s\t\tremote-tracking branch '%s' of .\n",
                                    sha1_to_hex(branch_head), remote);
@@ -477,10 +477,10 @@ static void merge_name(const char *remote, struct strbuf *msg)
                strbuf_addstr(&truname, "refs/heads/");
                strbuf_addstr(&truname, remote);
                strbuf_setlen(&truname, truname.len - len);
-               if (resolve_ref(truname.buf, buf_sha, 1, NULL)) {
+               if (ref_exists(truname.buf)) {
                        strbuf_addf(msg,
                                    "%s\t\tbranch '%s'%s of .\n",
-                                   sha1_to_hex(remote_head->sha1),
+                                   sha1_to_hex(remote_head->object.sha1),
                                    truname.buf + 11,
                                    (early ? " (early part)" : ""));
                        strbuf_release(&truname);
@@ -490,14 +490,16 @@ static void merge_name(const char *remote, struct strbuf *msg)
 
        if (!strcmp(remote, "FETCH_HEAD") &&
                        !access(git_path("FETCH_HEAD"), R_OK)) {
+               const char *filename;
                FILE *fp;
                struct strbuf line = STRBUF_INIT;
                char *ptr;
 
-               fp = fopen(git_path("FETCH_HEAD"), "r");
+               filename = git_path("FETCH_HEAD");
+               fp = fopen(filename, "r");
                if (!fp)
                        die_errno(_("could not open '%s' for reading"),
-                                 git_path("FETCH_HEAD"));
+                                 filename);
                strbuf_getline(&line, fp, '\n');
                fclose(fp);
                ptr = strstr(line.buf, "\tnot-for-merge\t");
@@ -508,7 +510,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
                goto cleanup;
        }
        strbuf_addf(msg, "%s\t\tcommit '%s'\n",
-               sha1_to_hex(remote_head->sha1), remote);
+               sha1_to_hex(remote_head->object.sha1), remote);
 cleanup:
        strbuf_release(&buf);
        strbuf_release(&bname);
@@ -536,6 +538,8 @@ static void parse_branch_merge_options(char *bmo)
 
 static int git_merge_config(const char *k, const char *v, void *cb)
 {
+       int status;
+
        if (branch && !prefixcmp(k, "branch.") &&
                !prefixcmp(k + 7, branch) &&
                !strcmp(k + 7 + strlen(branch), ".mergeoptions")) {
@@ -552,15 +556,7 @@ static int git_merge_config(const char *k, const char *v, void *cb)
                return git_config_string(&pull_octopus, k, v);
        else if (!strcmp(k, "merge.renormalize"))
                option_renormalize = git_config_bool(k, v);
-       else if (!strcmp(k, "merge.log") || !strcmp(k, "merge.summary")) {
-               int is_bool;
-               shortlog_len = git_config_bool_or_int(k, v, &is_bool);
-               if (!is_bool && shortlog_len < 0)
-                       return error(_("%s: negative length %s"), k, v);
-               if (is_bool && shortlog_len)
-                       shortlog_len = DEFAULT_MERGE_LOG_LEN;
-               return 0;
-       } else if (!strcmp(k, "merge.ff")) {
+       else if (!strcmp(k, "merge.ff")) {
                int boolval = git_config_maybe_bool(k, v);
                if (0 <= boolval) {
                        allow_fast_forward = boolval;
@@ -573,6 +569,9 @@ static int git_merge_config(const char *k, const char *v, void *cb)
                default_to_upstream = git_config_bool(k, v);
                return 0;
        }
+       status = fmt_merge_msg_config(k, v, cb);
+       if (status)
+               return status;
        return git_diff_ui_config(k, v, cb);
 }
 
@@ -712,7 +711,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                                die(_("Unknown option for merge-recursive: -X%s"), xopts[x]);
 
                o.branch1 = head_arg;
-               o.branch2 = remoteheads->item->util;
+               o.branch2 = merge_remote_util(remoteheads->item)->name;
 
                for (j = common; j; j = j->next)
                        commit_list_insert(j->item, &reversed);
@@ -769,7 +768,7 @@ int checkout_fast_forward(const unsigned char *head, const unsigned char *remote
        memset(&t, 0, sizeof(t));
        memset(&dir, 0, sizeof(dir));
        dir.flags |= DIR_SHOW_IGNORED;
-       dir.exclude_per_dir = ".gitignore";
+       setup_standard_excludes(&dir);
        opts.dir = &dir;
 
        opts.head_idx = 1;
@@ -843,30 +842,56 @@ static void add_strategies(const char *string, unsigned attr)
 
 }
 
-static void write_merge_msg(void)
+static void write_merge_msg(struct strbuf *msg)
 {
-       int fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
+       const char *filename = git_path("MERGE_MSG");
+       int fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
                die_errno(_("Could not open '%s' for writing"),
-                         git_path("MERGE_MSG"));
-       if (write_in_full(fd, merge_msg.buf, merge_msg.len) != merge_msg.len)
-               die_errno(_("Could not write to '%s'"), git_path("MERGE_MSG"));
+                         filename);
+       if (write_in_full(fd, msg->buf, msg->len) != msg->len)
+               die_errno(_("Could not write to '%s'"), filename);
        close(fd);
 }
 
-static void read_merge_msg(void)
+static void read_merge_msg(struct strbuf *msg)
 {
-       strbuf_reset(&merge_msg);
-       if (strbuf_read_file(&merge_msg, git_path("MERGE_MSG"), 0) < 0)
-               die_errno(_("Could not read from '%s'"), git_path("MERGE_MSG"));
+       const char *filename = git_path("MERGE_MSG");
+       strbuf_reset(msg);
+       if (strbuf_read_file(msg, filename, 0) < 0)
+               die_errno(_("Could not read from '%s'"), filename);
 }
 
-static void run_prepare_commit_msg(void)
+static void write_merge_state(void);
+static void abort_commit(const char *err_msg)
 {
-       write_merge_msg();
+       if (err_msg)
+               error("%s", err_msg);
+       fprintf(stderr,
+               _("Not committing merge; use 'git commit' to complete the merge.\n"));
+       write_merge_state();
+       exit(1);
+}
+
+static void prepare_to_commit(void)
+{
+       struct strbuf msg = STRBUF_INIT;
+       strbuf_addbuf(&msg, &merge_msg);
+       strbuf_addch(&msg, '\n');
+       write_merge_msg(&msg);
        run_hook(get_index_file(), "prepare-commit-msg",
                 git_path("MERGE_MSG"), "merge", NULL, NULL);
-       read_merge_msg();
+       if (option_edit) {
+               if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
+                       abort_commit(NULL);
+       }
+       read_merge_msg(&msg);
+       stripspace(&msg, option_edit);
+       if (!msg.len)
+               abort_commit(_("Empty commit message."));
+       strbuf_release(&merge_msg);
+       strbuf_addbuf(&merge_msg, &msg);
+       strbuf_release(&msg);
 }
 
 static int merge_trivial(struct commit *head)
@@ -880,7 +905,7 @@ static int merge_trivial(struct commit *head)
        parent->next = xmalloc(sizeof(*parent->next));
        parent->next->item = remoteheads->item;
        parent->next->next = NULL;
-       run_prepare_commit_msg();
+       prepare_to_commit();
        commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
        finish(head, result_commit, "In-index merge");
        drop_save();
@@ -909,9 +934,9 @@ static int finish_automerge(struct commit *head,
                for (j = remoteheads; j; j = j->next)
                        pptr = &commit_list_insert(j->item, pptr)->next;
        }
-       free_commit_list(remoteheads);
        strbuf_addch(&merge_msg, '\n');
-       run_prepare_commit_msg();
+       prepare_to_commit();
+       free_commit_list(remoteheads);
        commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
        strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
        finish(head, result_commit, buf.buf);
@@ -922,13 +947,14 @@ static int finish_automerge(struct commit *head,
 
 static int suggest_conflicts(int renormalizing)
 {
+       const char *filename;
        FILE *fp;
        int pos;
 
-       fp = fopen(git_path("MERGE_MSG"), "a");
+       filename = git_path("MERGE_MSG");
+       fp = fopen(filename, "a");
        if (!fp)
-               die_errno(_("Could not open '%s' for writing"),
-                         git_path("MERGE_MSG"));
+               die_errno(_("Could not open '%s' for writing"), filename);
        fprintf(fp, "\nConflicts:\n");
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
@@ -1018,6 +1044,45 @@ static int setup_with_upstream(const char ***argv)
        return i;
 }
 
+static void write_merge_state(void)
+{
+       const char *filename;
+       int fd;
+       struct commit_list *j;
+       struct strbuf buf = STRBUF_INIT;
+
+       for (j = remoteheads; j; j = j->next) {
+               unsigned const char *sha1;
+               struct commit *c = j->item;
+               if (c->util && merge_remote_util(c)->obj) {
+                       sha1 = merge_remote_util(c)->obj->sha1;
+               } else {
+                       sha1 = c->object.sha1;
+               }
+               strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1));
+       }
+       filename = git_path("MERGE_HEAD");
+       fd = open(filename, O_WRONLY | O_CREAT, 0666);
+       if (fd < 0)
+               die_errno(_("Could not open '%s' for writing"), filename);
+       if (write_in_full(fd, buf.buf, buf.len) != buf.len)
+               die_errno(_("Could not write to '%s'"), filename);
+       close(fd);
+       strbuf_addch(&merge_msg, '\n');
+       write_merge_msg(&merge_msg);
+
+       filename = git_path("MERGE_MODE");
+       fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+       if (fd < 0)
+               die_errno(_("Could not open '%s' for writing"), filename);
+       strbuf_reset(&buf);
+       if (!allow_fast_forward)
+               strbuf_addf(&buf, "no-ff");
+       if (write_in_full(fd, buf.buf, buf.len) != buf.len)
+               die_errno(_("Could not write to '%s'"), filename);
+       close(fd);
+}
+
 int cmd_merge(int argc, const char **argv, const char *prefix)
 {
        unsigned char result_tree[20];
@@ -1026,7 +1091,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        struct commit *head_commit;
        struct strbuf buf = STRBUF_INIT;
        const char *head_arg;
-       int flag, i;
+       int flag, i, ret = 0;
        int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
        struct commit_list *common = NULL;
        const char *best_strategy = NULL, *wt_strategy = NULL;
@@ -1040,8 +1105,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * current branch.
         */
        branch = resolve_ref("HEAD", head_sha1, 0, &flag);
-       if (branch && !prefixcmp(branch, "refs/heads/"))
-               branch += 11;
+       if (branch) {
+               if (!prefixcmp(branch, "refs/heads/"))
+                       branch += 11;
+               branch = xstrdup(branch);
+       }
        if (!branch || is_null_sha1(head_sha1))
                head_commit = NULL;
        else
@@ -1053,6 +1121,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                parse_branch_merge_options(branch_mergeoptions);
        argc = parse_options(argc, argv, prefix, builtin_merge_options,
                        builtin_merge_usage, 0);
+       if (shortlog_len < 0)
+               shortlog_len = (merge_log_config > 0) ? merge_log_config : 0;
 
        if (verbosity < 0 && show_progress == -1)
                show_progress = 0;
@@ -1065,7 +1135,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        die(_("There is no merge to abort (MERGE_HEAD missing)."));
 
                /* Invoke 'git reset --merge' */
-               return cmd_reset(nargc, nargv, prefix);
+               ret = cmd_reset(nargc, nargv, prefix);
+               goto done;
        }
 
        if (read_cache_unmerged())
@@ -1104,9 +1175,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                die(_("You cannot combine --no-ff with --ff-only."));
 
        if (!abort_current_merge) {
-               if (!argc && default_to_upstream)
-                       argc = setup_with_upstream(&argv);
-               else if (argc == 1 && !strcmp(argv[0], "-"))
+               if (!argc) {
+                       if (default_to_upstream)
+                               argc = setup_with_upstream(&argv);
+                       else
+                               die(_("No commit specified and merge.defaultToUpstream not set."));
+               } else if (argc == 1 && !strcmp(argv[0], "-"))
                        argv[0] = "@{-1}";
        }
        if (!argc)
@@ -1129,7 +1203,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                argv += 2;
                argc -= 2;
        } else if (!head_commit) {
-               struct object *remote_head;
+               struct commit *remote_head;
                /*
                 * If the merged head is a valid one there is no reason
                 * to forbid "git merge" into a branch yet to be born.
@@ -1143,13 +1217,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                if (!allow_fast_forward)
                        die(_("Non-fast-forward commit does not make sense into "
                            "an empty head"));
-               remote_head = want_commit(argv[0]);
+               remote_head = get_merge_parent(argv[0]);
                if (!remote_head)
                        die(_("%s - not something we can merge"), argv[0]);
-               read_empty(remote_head->sha1, 0);
-               update_ref("initial pull", "HEAD", remote_head->sha1, NULL, 0,
-                               DIE_ON_ERR);
-               return 0;
+               read_empty(remote_head->object.sha1, 0);
+               update_ref("initial pull", "HEAD", remote_head->object.sha1,
+                          NULL, 0, DIE_ON_ERR);
+               goto done;
        } else {
                struct strbuf merge_names = STRBUF_INIT;
 
@@ -1157,19 +1231,20 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                head_arg = "HEAD";
 
                /*
-                * All the rest are the commits being merged;
-                * prepare the standard merge summary message to
-                * be appended to the given message.  If remote
-                * is invalid we will die later in the common
-                * codepath so we discard the error in this
-                * loop.
+                * All the rest are the commits being merged; prepare
+                * the standard merge summary message to be appended
+                * to the given message.
                 */
                for (i = 0; i < argc; i++)
                        merge_name(argv[i], &merge_names);
 
                if (!have_message || shortlog_len) {
-                       fmt_merge_msg(&merge_names, &merge_msg, !have_message,
-                                     shortlog_len);
+                       struct fmt_merge_msg_opts opts;
+                       memset(&opts, 0, sizeof(opts));
+                       opts.add_title = !have_message;
+                       opts.shortlog_len = shortlog_len;
+
+                       fmt_merge_msg(&merge_names, &merge_msg, &opts);
                        if (merge_msg.len)
                                strbuf_setlen(&merge_msg, merge_msg.len - 1);
                }
@@ -1186,19 +1261,20 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        strbuf_reset(&buf);
 
        for (i = 0; i < argc; i++) {
-               struct object *o;
-               struct commit *commit;
-
-               o = want_commit(argv[i]);
-               if (!o)
+               struct commit *commit = get_merge_parent(argv[i]);
+               if (!commit)
                        die(_("%s - not something we can merge"), argv[i]);
-               commit = lookup_commit(o->sha1);
-               commit->util = (void *)argv[i];
                remotes = &commit_list_insert(commit, remotes)->next;
-
-               strbuf_addf(&buf, "GITHEAD_%s", sha1_to_hex(o->sha1));
+               strbuf_addf(&buf, "GITHEAD_%s",
+                           sha1_to_hex(commit->object.sha1));
                setenv(buf.buf, argv[i], 1);
                strbuf_reset(&buf);
+               if (merge_remote_util(commit) &&
+                   merge_remote_util(commit)->obj &&
+                   merge_remote_util(commit)->obj->type == OBJ_TAG) {
+                       option_edit = 1;
+                       allow_fast_forward = 0;
+               }
        }
 
        if (!use_strategies) {
@@ -1236,13 +1312,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                 * but first the most common case of merging one remote.
                 */
                finish_up_to_date("Already up-to-date.");
-               return 0;
+               goto done;
        } else if (allow_fast_forward && !remoteheads->next &&
                        !common->next &&
                        !hashcmp(common->item->object.sha1, head_commit->object.sha1)) {
                /* Again the most common case of merging one remote. */
                struct strbuf msg = STRBUF_INIT;
-               struct object *o;
+               struct commit *commit;
                char hex[41];
 
                strcpy(hex, find_unique_abbrev(head_commit->object.sha1, DEFAULT_ABBREV));
@@ -1256,16 +1332,21 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                if (have_message)
                        strbuf_addstr(&msg,
                                " (no commit created; -m option ignored)");
-               o = want_commit(sha1_to_hex(remoteheads->item->object.sha1));
-               if (!o)
-                       return 1;
+               commit = remoteheads->item;
+               if (!commit) {
+                       ret = 1;
+                       goto done;
+               }
 
-               if (checkout_fast_forward(head_commit->object.sha1, remoteheads->item->object.sha1))
-                       return 1;
+               if (checkout_fast_forward(head_commit->object.sha1,
+                                         commit->object.sha1)) {
+                       ret = 1;
+                       goto done;
+               }
 
-               finish(head_commit, o->sha1, msg.buf);
+               finish(head_commit, commit->object.sha1, msg.buf);
                drop_save();
-               return 0;
+               goto done;
        } else if (!remoteheads->next && common->next)
                ;
                /*
@@ -1283,8 +1364,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        git_committer_info(IDENT_ERROR_ON_NO_NAME);
                        printf(_("Trying really trivial in-index merge...\n"));
                        if (!read_tree_trivial(common->item->object.sha1,
-                                       head_commit->object.sha1, remoteheads->item->object.sha1))
-                               return merge_trivial(head_commit);
+                                              head_commit->object.sha1,
+                                              remoteheads->item->object.sha1)) {
+                               ret = merge_trivial(head_commit);
+                               goto done;
+                       }
                        printf(_("Nope.\n"));
                }
        } else {
@@ -1312,7 +1396,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                }
                if (up_to_date) {
                        finish_up_to_date("Already up-to-date. Yeeah!");
-                       return 0;
+                       goto done;
                }
        }
 
@@ -1394,9 +1478,11 @@ 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)
-               return finish_automerge(head_commit, common, result_tree,
-                                       wt_strategy);
+       if (automerge_was_ok) {
+               ret = finish_automerge(head_commit, common, result_tree,
+                                      wt_strategy);
+               goto done;
+       }
 
        /*
         * Pick the result from the best strategy and have the user fix
@@ -1410,7 +1496,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                else
                        fprintf(stderr, _("Merge with strategy %s failed.\n"),
                                use_strategies[0]->name);
-               return 2;
+               ret = 2;
+               goto done;
        } else if (best_strategy == wt_strategy)
                ; /* We already have its result in the working tree. */
        else {
@@ -1423,38 +1510,16 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 
        if (squash)
                finish(head_commit, NULL, NULL);
-       else {
-               int fd;
-               struct commit_list *j;
-
-               for (j = remoteheads; j; j = j->next)
-                       strbuf_addf(&buf, "%s\n",
-                               sha1_to_hex(j->item->object.sha1));
-               fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666);
-               if (fd < 0)
-                       die_errno(_("Could not open '%s' for writing"),
-                                 git_path("MERGE_HEAD"));
-               if (write_in_full(fd, buf.buf, buf.len) != buf.len)
-                       die_errno(_("Could not write to '%s'"), git_path("MERGE_HEAD"));
-               close(fd);
-               strbuf_addch(&merge_msg, '\n');
-               write_merge_msg();
-               fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666);
-               if (fd < 0)
-                       die_errno(_("Could not open '%s' for writing"),
-                                 git_path("MERGE_MODE"));
-               strbuf_reset(&buf);
-               if (!allow_fast_forward)
-                       strbuf_addf(&buf, "no-ff");
-               if (write_in_full(fd, buf.buf, buf.len) != buf.len)
-                       die_errno(_("Could not write to '%s'"), git_path("MERGE_MODE"));
-               close(fd);
-       }
+       else
+               write_merge_state();
 
-       if (merge_was_ok) {
+       if (merge_was_ok)
                fprintf(stderr, _("Automatic merge went well; "
                        "stopped before committing as requested\n"));
-               return 0;
-       } else
-               return suggest_conflicts(option_renormalize);
+       else
+               ret = suggest_conflicts(option_renormalize);
+
+done:
+       free((char *)branch);
+       return ret;
 }