This option allows to create merge commit when fast-forward is
possible, and abort otherwise. I.e. it's equivalent to --ff-only,
except that it finally creates merge commit instead of
fast-forwarding.

One may also consider this option to be equivalent to --no-ff with
additional check that the command without --no-ff  would indeed result
in fast-forward.

Useful to incorporate topic branch as single merge commit, ensuring
the left-side of the merge has no changes (our-diff-empty-merge).

Signed-off-by: Sergey Organov <[email protected]>
---
 builtin/merge.c | 39 ++++++++++++++++++++++++++++++---------
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index dff043d..39d0f1e 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -79,7 +79,8 @@ static const char *pull_twohead, *pull_octopus;
 enum ff_type {
        FF_NO,
        FF_ALLOW,
-       FF_ONLY
+       FF_ONLY,
+       FF_ONLY_MERGE
 };
 
 static enum ff_type fast_forward = FF_ALLOW;
@@ -206,6 +207,9 @@ static struct option builtin_merge_options[] = {
        { OPTION_SET_INT, 0, "ff-only", &fast_forward, NULL,
                N_("abort if fast-forward is not possible"),
                PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, FF_ONLY },
+       { OPTION_SET_INT, 0, "ff-only-merge", &fast_forward, NULL,
+               N_("create merge commit when fast-forward is possible, abort 
otherwise"),
+               PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, FF_ONLY_MERGE },
        OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
        OPT_BOOL(0, "verify-signatures", &verify_signatures,
                N_("Verify that the named commit has a valid GPG signature")),
@@ -591,6 +595,8 @@ static int git_merge_config(const char *k, const char *v, 
void *cb)
                        fast_forward = boolval ? FF_ALLOW : FF_NO;
                } else if (v && !strcmp(v, "only")) {
                        fast_forward = FF_ONLY;
+               } else if (v && !strcmp(v, "merge")) {
+                       fast_forward = FF_ONLY_MERGE;
                } /* do not barf on values from future versions of git */
                return 0;
        } else if (!strcmp(k, "merge.defaulttoupstream")) {
@@ -866,7 +872,7 @@ static int finish_automerge(struct commit *head,
 
        free_commit_list(common);
        parents = remoteheads;
-       if (!head_subsumed || fast_forward == FF_NO)
+       if (!head_subsumed || (fast_forward == FF_NO || fast_forward == 
FF_ONLY_MERGE))
                commit_list_insert(head, &parents);
        strbuf_addch(&merge_msg, '\n');
        prepare_to_commit(remoteheads);
@@ -1162,6 +1168,8 @@ int cmd_merge(int argc, const char **argv, const char 
*prefix)
        if (squash) {
                if (fast_forward == FF_NO)
                        die(_("You cannot combine --squash with --no-ff."));
+               if (fast_forward == FF_ONLY_MERGE)
+                       die(_("You cannot combine --squash with 
--ff-only-merge."));
                option_commit = 0;
        }
 
@@ -1206,7 +1214,7 @@ int cmd_merge(int argc, const char **argv, const char 
*prefix)
                                "empty head"));
                if (squash)
                        die(_("Squash commit into empty head not supported 
yet"));
-               if (fast_forward == FF_NO)
+               if (fast_forward == FF_NO || fast_forward == FF_ONLY_MERGE)
                        die(_("Non-fast-forward commit does not make sense into 
"
                            "an empty head"));
                remoteheads = collect_parents(head_commit, &head_subsumed, 
argc, argv);
@@ -1292,6 +1300,7 @@ int cmd_merge(int argc, const char **argv, const char 
*prefix)
                setenv(buf.buf, merge_remote_util(commit)->name, 1);
                strbuf_reset(&buf);
                if (fast_forward != FF_ONLY &&
+                   fast_forward != FF_ONLY_MERGE &&
                    merge_remote_util(commit) &&
                    merge_remote_util(commit)->obj &&
                    merge_remote_util(commit)->obj->type == OBJ_TAG)
@@ -1312,7 +1321,8 @@ int cmd_merge(int argc, const char **argv, const char 
*prefix)
 
        for (i = 0; i < use_strategies_nr; i++) {
                if (use_strategies[i]->attr & NO_FAST_FORWARD)
-                       fast_forward = FF_NO;
+                       if(fast_forward != FF_ONLY_MERGE)
+                               fast_forward = FF_NO;
                if (use_strategies[i]->attr & NO_TRIVIAL)
                        allow_trivial = 0;
        }
@@ -1342,9 +1352,19 @@ int cmd_merge(int argc, const char **argv, const char 
*prefix)
                 */
                finish_up_to_date("Already up-to-date.");
                goto done;
-       } else if (fast_forward != FF_NO && !remoteheads->next &&
-                       !common->next &&
-                       !hashcmp(common->item->object.sha1, 
head_commit->object.sha1)) {
+       } else if (fast_forward != FF_NO &&
+                  !remoteheads->next &&
+                  !common->next &&
+                  !hashcmp(common->item->object.sha1, 
head_commit->object.sha1)) {
+
+               if (fast_forward == FF_ONLY_MERGE) {
+                       /*
+                        * We are going to fast-forward, but options force us 
to create
+                        * merge commit instead.
+                        */
+                       goto commit;
+               }
+
                /* Again the most common case of merging one remote. */
                struct strbuf msg = STRBUF_INIT;
                struct commit *commit;
@@ -1389,7 +1409,7 @@ int cmd_merge(int argc, const char **argv, const char 
*prefix)
                 * only one common.
                 */
                refresh_cache(REFRESH_QUIET);
-               if (allow_trivial && fast_forward != FF_ONLY) {
+               if (allow_trivial && fast_forward != FF_ONLY && fast_forward != 
FF_ONLY_MERGE) {
                        /* See if it is really trivial. */
                        git_committer_info(IDENT_STRICT);
                        printf(_("Trying really trivial in-index merge...\n"));
@@ -1430,9 +1450,10 @@ int cmd_merge(int argc, const char **argv, const char 
*prefix)
                }
        }
 
-       if (fast_forward == FF_ONLY)
+       if (fast_forward == FF_ONLY || fast_forward == FF_ONLY_MERGE)
                die(_("Not possible to fast-forward, aborting."));
 
+commit:        
        /* We are going to make a new commit. */
        git_committer_info(IDENT_STRICT);
 
-- 
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to