]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/merge.c
Merge branch 'eb/hash-transition'
[thirdparty/git.git] / builtin / merge.c
index 718165d45917b684fea677f9146a2731e7082b69..1cbd6a899ccf2f3a3d92c7f14dcec3074634a3df 100644 (file)
@@ -31,8 +31,6 @@
 #include "unpack-trees.h"
 #include "cache-tree.h"
 #include "dir.h"
-#include "utf8.h"
-#include "log-tree.h"
 #include "color.h"
 #include "rerere.h"
 #include "help.h"
 #include "resolve-undo.h"
 #include "remote.h"
 #include "fmt-merge-msg.h"
-#include "gpg-interface.h"
 #include "sequencer.h"
 #include "string-list.h"
-#include "packfile.h"
 #include "tag.h"
 #include "alias.h"
 #include "branch.h"
@@ -79,8 +75,7 @@ static int overwrite_ignore = 1;
 static struct strbuf merge_msg = STRBUF_INIT;
 static struct strategy **use_strategies;
 static size_t use_strategies_nr, use_strategies_alloc;
-static const char **xopts;
-static size_t xopts_nr, xopts_alloc;
+static struct strvec xopts = STRVEC_INIT;
 static const char *branch;
 static char *branch_mergeoptions;
 static int verbosity;
@@ -197,8 +192,7 @@ static struct strategy *get_strategy(const char *name)
                        int j, found = 0;
                        struct cmdname *ent = main_cmds.names[i];
                        for (j = 0; !found && j < ARRAY_SIZE(all_strategy); j++)
-                               if (!strncmp(ent->name, all_strategy[j].name, ent->len)
-                                               && !all_strategy[j].name[ent->len])
+                               if (!xstrncmpz(all_strategy[j].name, ent->name, ent->len))
                                        found = 1;
                        if (!found)
                                add_cmdname(&not_strategies, ent->name, ent->len);
@@ -232,7 +226,7 @@ static void append_strategy(struct strategy *s)
        use_strategies[use_strategies_nr++] = s;
 }
 
-static int option_parse_strategy(const struct option *opt,
+static int option_parse_strategy(const struct option *opt UNUSED,
                                 const char *name, int unset)
 {
        if (unset)
@@ -242,29 +236,9 @@ static int option_parse_strategy(const struct option *opt,
        return 0;
 }
 
-static int option_parse_x(const struct option *opt,
-                         const char *arg, int unset)
-{
-       if (unset)
-               return 0;
-
-       ALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc);
-       xopts[xopts_nr++] = xstrdup(arg);
-       return 0;
-}
-
-static int option_parse_n(const struct option *opt,
-                         const char *arg, int unset)
-{
-       BUG_ON_OPT_ARG(arg);
-       show_diffstat = unset;
-       return 0;
-}
-
 static struct option builtin_merge_options[] = {
-       OPT_CALLBACK_F('n', NULL, NULL, NULL,
-               N_("do not show a diffstat at the end of the merge"),
-               PARSE_OPT_NOARG, option_parse_n),
+       OPT_SET_INT('n', NULL, &show_diffstat,
+               N_("do not show a diffstat at the end of the merge"), 0),
        OPT_BOOL(0, "stat", &show_diffstat,
                N_("show a diffstat at the end of the merge")),
        OPT_BOOL(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
@@ -285,10 +259,10 @@ static struct option builtin_merge_options[] = {
        OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
        OPT_BOOL(0, "verify-signatures", &verify_signatures,
                N_("verify that the named commit has a valid GPG signature")),
-       OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
+       OPT_CALLBACK('s', "strategy", NULL, N_("strategy"),
                N_("merge strategy to use"), option_parse_strategy),
-       OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
-               N_("option for selected merge strategy"), option_parse_x),
+       OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
+               N_("option for selected merge strategy")),
        OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
                N_("merge commit message (for a non-fast-forward merge)"),
                option_parse_message),
@@ -487,8 +461,7 @@ static void finish(struct commit *head_commit,
        if (new_head && show_diffstat) {
                struct diff_options opts;
                repo_diff_setup(the_repository, &opts);
-               opts.stat_width = -1; /* use full terminal width */
-               opts.stat_graph_width = -1; /* respect statGraphWidth config */
+               init_diffstat_widths(&opts);
                opts.output_format |=
                        DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
                opts.detect_rename = DIFF_DETECT_RENAME;
@@ -502,7 +475,7 @@ static void finish(struct commit *head_commit,
        run_hooks_l("post-merge", squash ? "1" : "0", NULL);
 
        if (new_head)
-               apply_autostash(git_path_merge_autostash(the_repository));
+               apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
        strbuf_release(&reflog_message);
 }
 
@@ -750,9 +723,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                o.show_rename_progress =
                        show_progress == -1 ? isatty(2) : show_progress;
 
-               for (x = 0; x < xopts_nr; x++)
-                       if (parse_merge_opt(&o, xopts[x]))
-                               die(_("unknown strategy option: -X%s"), xopts[x]);
+               for (x = 0; x < xopts.nr; x++)
+                       if (parse_merge_opt(&o, xopts.v[x]))
+                               die(_("unknown strategy option: -X%s"), xopts.v[x]);
 
                o.branch1 = head_arg;
                o.branch2 = merge_remote_util(remoteheads->item)->name;
@@ -778,7 +751,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                return clean ? 0 : 1;
        } else {
                return try_merge_command(the_repository,
-                                        strategy, xopts_nr, xopts,
+                                        strategy, xopts.nr, xopts.v,
                                         common, head_arg, remoteheads);
        }
 }
@@ -892,7 +865,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
                                _(no_scissors_editor_comment), comment_line_char);
        }
        if (signoff)
-               append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
+               append_signoff(&msg, ignored_log_message_bytes(msg.buf, msg.len), 0);
        write_merge_heads(remoteheads);
        write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len);
        if (run_commit_hook(0 < option_edit, get_index_file(), NULL,
@@ -1342,7 +1315,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        if (abort_current_merge) {
                int nargc = 2;
                const char *nargv[] = {"reset", "--merge", NULL};
-               struct strbuf stash_oid = STRBUF_INIT;
+               char stash_oid_hex[GIT_MAX_HEXSZ + 1];
+               struct object_id stash_oid = {0};
 
                if (orig_argc != 2)
                        usage_msg_opt(_("--abort expects no arguments"),
@@ -1351,17 +1325,17 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                if (!file_exists(git_path_merge_head(the_repository)))
                        die(_("There is no merge to abort (MERGE_HEAD missing)."));
 
-               if (read_oneliner(&stash_oid, git_path_merge_autostash(the_repository),
-                   READ_ONELINER_SKIP_IF_EMPTY))
-                       unlink(git_path_merge_autostash(the_repository));
+               if (!read_ref("MERGE_AUTOSTASH", &stash_oid))
+                       delete_ref("", "MERGE_AUTOSTASH", &stash_oid, REF_NO_DEREF);
 
                /* Invoke 'git reset --merge' */
                ret = cmd_reset(nargc, nargv, prefix);
 
-               if (stash_oid.len)
-                       apply_autostash_oid(stash_oid.buf);
+               if (!is_null_oid(&stash_oid)) {
+                       oid_to_hex_r(stash_oid_hex, &stash_oid);
+                       apply_autostash_oid(stash_oid_hex);
+               }
 
-               strbuf_release(&stash_oid);
                goto done;
        }
 
@@ -1540,13 +1514,20 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 
        if (!remoteheads)
                ; /* already up-to-date */
-       else if (!remoteheads->next)
-               common = repo_get_merge_bases(the_repository, head_commit,
-                                             remoteheads->item);
-       else {
+       else if (!remoteheads->next) {
+               if (repo_get_merge_bases(the_repository, head_commit,
+                                        remoteheads->item, &common) < 0) {
+                       ret = 2;
+                       goto done;
+               }
+       } else {
                struct commit_list *list = remoteheads;
                commit_list_insert(head_commit, &list);
-               common = get_octopus_merge_bases(list);
+               if (get_octopus_merge_bases(list, &common) < 0) {
+                       free(list);
+                       ret = 2;
+                       goto done;
+               }
                free(list);
        }
 
@@ -1590,13 +1571,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                }
 
                if (autostash)
-                       create_autostash(the_repository,
-                                        git_path_merge_autostash(the_repository));
+                       create_autostash_ref(the_repository, "MERGE_AUTOSTASH");
                if (checkout_fast_forward(the_repository,
                                          &head_commit->object.oid,
                                          &commit->object.oid,
                                          overwrite_ignore)) {
-                       apply_autostash(git_path_merge_autostash(the_repository));
+                       apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
                        ret = 1;
                        goto done;
                }
@@ -1654,17 +1634,21 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                struct commit_list *j;
 
                for (j = remoteheads; j; j = j->next) {
-                       struct commit_list *common_one;
+                       struct commit_list *common_one = NULL;
+                       struct commit *common_item;
 
                        /*
                         * Here we *have* to calculate the individual
                         * merge_bases again, otherwise "git merge HEAD^
                         * HEAD^^" would be missed.
                         */
-                       common_one = repo_get_merge_bases(the_repository,
-                                                         head_commit,
-                                                         j->item);
-                       if (!oideq(&common_one->item->object.oid, &j->item->object.oid)) {
+                       if (repo_get_merge_bases(the_repository, head_commit,
+                                                j->item, &common_one) < 0)
+                               exit(128);
+
+                       common_item = common_one->item;
+                       free_commit_list(common_one);
+                       if (!oideq(&common_item->object.oid, &j->item->object.oid)) {
                                up_to_date = 0;
                                break;
                        }
@@ -1679,8 +1663,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                die_ff_impossible();
 
        if (autostash)
-               create_autostash(the_repository,
-                                git_path_merge_autostash(the_repository));
+               create_autostash_ref(the_repository, "MERGE_AUTOSTASH");
 
        /* We are going to make a new commit. */
        git_committer_info(IDENT_STRICT);
@@ -1765,7 +1748,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                else
                        fprintf(stderr, _("Merge with strategy %s failed.\n"),
                                use_strategies[0]->name);
-               apply_autostash(git_path_merge_autostash(the_repository));
+               apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
                ret = 2;
                goto done;
        } else if (best_strategy == wt_strategy)