]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/merge.c
Merge branch 'vv/merge-squash-with-explicit-commit' into maint
[thirdparty/git.git] / builtin / merge.c
index 5ce8946d390c1c42b885a2c86a363f79aec1b27a..57c2a24f6d82fc7cedcc86979db6ff1a8fa6bc50 100644 (file)
@@ -38,6 +38,7 @@
 #include "tag.h"
 #include "alias.h"
 #include "commit-reach.h"
+#include "wt-status.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -57,7 +58,7 @@ static const char * const builtin_merge_usage[] = {
 };
 
 static int show_diffstat = 1, shortlog_len = -1, squash;
-static int option_commit = 1;
+static int option_commit = -1;
 static int option_edit = -1;
 static int allow_trivial = 1, have_message, verify_signatures;
 static int overwrite_ignore = 1;
@@ -98,6 +99,9 @@ enum ff_type {
 
 static enum ff_type fast_forward = FF_ALLOW;
 
+static const char *cleanup_arg;
+static enum commit_msg_cleanup_mode cleanup_mode;
+
 static int option_parse_message(const struct option *opt,
                                const char *arg, int unset)
 {
@@ -249,6 +253,7 @@ static struct option builtin_merge_options[] = {
                N_("perform a commit if the merge succeeds (default)")),
        OPT_BOOL('e', "edit", &option_edit,
                N_("edit message before committing")),
+       OPT_CLEANUP(&cleanup_arg),
        OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
        OPT_SET_INT_F(0, "ff-only", &fast_forward,
                      N_("abort if fast-forward is not possible"),
@@ -612,6 +617,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
                return git_config_string(&pull_twohead, k, v);
        else if (!strcmp(k, "pull.octopus"))
                return git_config_string(&pull_octopus, k, v);
+       else if (!strcmp(k, "commit.cleanup"))
+               return git_config_string(&cleanup_arg, k, v);
        else if (!strcmp(k, "merge.renormalize"))
                option_renormalize = git_config_bool(k, v);
        else if (!strcmp(k, "merge.ff")) {
@@ -800,8 +807,13 @@ static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
 static const char merge_editor_comment[] =
 N_("Please enter a commit message to explain why this merge is necessary,\n"
    "especially if it merges an updated upstream into a topic branch.\n"
-   "\n"
-   "Lines starting with '%c' will be ignored, and an empty message aborts\n"
+   "\n");
+
+static const char scissors_editor_comment[] =
+N_("An empty message aborts the commit.\n");
+
+static const char no_scissors_editor_comment[] =
+N_("Lines starting with '%c' will be ignored, and an empty message aborts\n"
    "the commit.\n");
 
 static void write_merge_heads(struct commit_list *);
@@ -809,11 +821,19 @@ static void prepare_to_commit(struct commit_list *remoteheads)
 {
        struct strbuf msg = STRBUF_INIT;
        strbuf_addbuf(&msg, &merge_msg);
-       strbuf_addch(&msg, '\n');
        if (squash)
                BUG("the control must not reach here under --squash");
-       if (0 < option_edit)
-               strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
+       if (0 < option_edit) {
+               strbuf_addch(&msg, '\n');
+               if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+                       wt_status_append_cut_line(&msg);
+                       strbuf_commented_addf(&msg, "\n");
+               }
+               strbuf_commented_addf(&msg, _(merge_editor_comment));
+               strbuf_commented_addf(&msg, _(cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS ?
+                       scissors_editor_comment :
+                       no_scissors_editor_comment), comment_line_char);
+       }
        if (signoff)
                append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
        write_merge_heads(remoteheads);
@@ -832,7 +852,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
                abort_commit(remoteheads, NULL);
 
        read_merge_msg(&msg);
-       strbuf_stripspace(&msg, 0 < option_edit);
+       cleanup_message(&msg, cleanup_mode, 0);
        if (!msg.len)
                abort_commit(remoteheads, _("Empty commit message."));
        strbuf_release(&merge_msg);
@@ -880,7 +900,6 @@ static int finish_automerge(struct commit *head,
        parents = remoteheads;
        if (!head_subsumed || fast_forward == FF_NO)
                commit_list_insert(head, &parents);
-       strbuf_addch(&merge_msg, '\n');
        prepare_to_commit(remoteheads);
        if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
                        &result_commit, NULL, sign_commit))
@@ -901,7 +920,15 @@ static int suggest_conflicts(void)
        filename = git_path_merge_msg(the_repository);
        fp = xfopen(filename, "a");
 
-       append_conflicts_hint(&the_index, &msgbuf);
+       /*
+        * We can't use cleanup_mode because if we're not using the editor,
+        * get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
+        * though the message is meant to be processed later by git-commit.
+        * Thus, we will get the cleanup mode which is returned when we _are_
+        * using an editor.
+        */
+       append_conflicts_hint(&the_index, &msgbuf,
+                             get_cleanup_mode(cleanup_arg, 1));
        fputs(msgbuf.buf, fp);
        strbuf_release(&msgbuf);
        fclose(fp);
@@ -1301,15 +1328,30 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        }
        resolve_undo_clear();
 
+       if (option_edit < 0)
+               option_edit = default_edit_option();
+
+       cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit);
+
        if (verbosity < 0)
                show_diffstat = 0;
 
        if (squash) {
                if (fast_forward == FF_NO)
                        die(_("You cannot combine --squash with --no-ff."));
+               if (option_commit > 0)
+                       die(_("You cannot combine --squash with --commit."));
+               /*
+                * squash can now silently disable option_commit - this is not
+                * a problem as it is only overriding the default, not a user
+                * supplied option.
+                */
                option_commit = 0;
        }
 
+       if (option_commit < 0)
+               option_commit = 1;
+
        if (!argc) {
                if (default_to_upstream)
                        argc = setup_with_upstream(&argv);
@@ -1386,9 +1428,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        fast_forward = FF_NO;
        }
 
-       if (option_edit < 0)
-               option_edit = default_edit_option();
-
        if (!use_strategies) {
                if (!remoteheads)
                        ; /* already up-to-date */