Imported Upstream version 2.27.0
[platform/upstream/git.git] / builtin / merge.c
index d127d22..ca6a5dc 100644 (file)
@@ -40,6 +40,7 @@
 #include "branch.h"
 #include "commit-reach.h"
 #include "wt-status.h"
+#include "commit-graph.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -82,6 +83,7 @@ static int show_progress = -1;
 static int default_to_upstream = 1;
 static int signoff;
 static const char *sign_commit;
+static int autostash;
 static int no_verify;
 
 static struct strategy all_strategy[] = {
@@ -241,9 +243,9 @@ static int option_parse_n(const struct option *opt,
 }
 
 static struct option builtin_merge_options[] = {
-       { OPTION_CALLBACK, 'n', NULL, NULL, NULL,
+       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 },
+               PARSE_OPT_NOARG, option_parse_n),
        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)")),
@@ -286,6 +288,7 @@ static struct option builtin_merge_options[] = {
        OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1),
        { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
          N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+       OPT_AUTOSTASH(&autostash),
        OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
        OPT_BOOL(0, "signoff", &signoff, N_("add Signed-off-by:")),
        OPT_BOOL(0, "no-verify", &no_verify, N_("bypass pre-merge-commit and commit-msg hooks")),
@@ -447,7 +450,6 @@ static void finish(struct commit *head_commit,
                if (verbosity >= 0 && !merge_msg.len)
                        printf(_("No merge message -- not updating HEAD\n"));
                else {
-                       const char *argv_gc_auto[] = { "gc", "--auto", NULL };
                        update_ref(reflog_message.buf, "HEAD", new_head, head,
                                   0, UPDATE_REFS_DIE_ON_ERR);
                        /*
@@ -455,7 +457,7 @@ static void finish(struct commit *head_commit,
                         * user should see them.
                         */
                        close_object_store(the_repository->objects);
-                       run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+                       run_auto_gc(verbosity < 0);
                }
        }
        if (new_head && show_diffstat) {
@@ -475,6 +477,7 @@ static void finish(struct commit *head_commit,
        /* Run a post-merge hook */
        run_hook_le(NULL, "post-merge", squash ? "1" : "0", NULL);
 
+       apply_autostash(git_path_merge_autostash(the_repository));
        strbuf_release(&reflog_message);
 }
 
@@ -597,10 +600,12 @@ static void parse_branch_merge_options(char *bmo)
 static int git_merge_config(const char *k, const char *v, void *cb)
 {
        int status;
+       const char *str;
 
-       if (branch && starts_with(k, "branch.") &&
-               starts_with(k + 7, branch) &&
-               !strcmp(k + 7 + strlen(branch), ".mergeoptions")) {
+       if (branch &&
+           skip_prefix(k, "branch.", &str) &&
+           skip_prefix(str, branch, &str) &&
+           !strcmp(str, ".mergeoptions")) {
                free(branch_mergeoptions);
                branch_mergeoptions = xstrdup(v);
                return 0;
@@ -634,6 +639,9 @@ static int git_merge_config(const char *k, const char *v, void *cb)
                return 0;
        } else if (!strcmp(k, "gpg.mintrustlevel")) {
                check_trust_level = 0;
+       } else if (!strcmp(k, "merge.autostash")) {
+               autostash = git_config_bool(k, v);
+               return 0;
        }
 
        status = fmt_merge_msg_config(k, v, cb);
@@ -1281,6 +1289,7 @@ 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;
 
                if (orig_argc != 2)
                        usage_msg_opt(_("--abort expects no arguments"),
@@ -1289,8 +1298,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));
+
                /* Invoke 'git reset --merge' */
                ret = cmd_reset(nargc, nargv, prefix);
+
+               if (stash_oid.len)
+                       apply_autostash_oid(stash_oid.buf);
+
+               strbuf_release(&stash_oid);
                goto done;
        }
 
@@ -1513,6 +1531,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        goto done;
                }
 
+               if (autostash)
+                       create_autostash(the_repository,
+                                        git_path_merge_autostash(the_repository),
+                                        "merge");
                if (checkout_fast_forward(the_repository,
                                          &head_commit->object.oid,
                                          &commit->object.oid,
@@ -1579,6 +1601,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        if (fast_forward == FF_ONLY)
                die(_("Not possible to fast-forward, aborting."));
 
+       if (autostash)
+               create_autostash(the_repository,
+                                git_path_merge_autostash(the_repository),
+                                "merge");
+
        /* We are going to make a new commit. */
        git_committer_info(IDENT_STRICT);
 
@@ -1673,9 +1700,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                                   head_commit);
        }
 
-       if (squash)
+       if (squash) {
                finish(head_commit, remoteheads, NULL, NULL);
-       else
+
+               git_test_write_commit_graph_or_die();
+       } else
                write_merge_state(remoteheads);
 
        if (merge_was_ok)