merge: clarify collect_parents() logic
[gitweb.git] / builtin / merge.c
index 4513fadc5fc3c631591d1a9b65ec939ada5d2de3..d2e36e2051d11a97f5d93ee4833ef60a14544c76 100644 (file)
@@ -491,8 +491,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
        }
        if (len) {
                struct strbuf truname = STRBUF_INIT;
-               strbuf_addstr(&truname, "refs/heads/");
-               strbuf_addstr(&truname, remote);
+               strbuf_addf(&truname, "refs/heads/%s", remote);
                strbuf_setlen(&truname, truname.len - len);
                if (ref_exists(truname.buf)) {
                        strbuf_addf(msg,
@@ -503,6 +502,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
                        strbuf_release(&truname);
                        goto cleanup;
                }
+               strbuf_release(&truname);
        }
 
        if (!strcmp(remote, "FETCH_HEAD") &&
@@ -1061,11 +1061,19 @@ static struct commit_list *collect_parents(struct commit *head_commit,
                                         "not something we can merge");
                remotes = &commit_list_insert(commit, remotes)->next;
        }
-       *remotes = NULL;
 
+       /*
+        * Is the current HEAD reachable from another commit being
+        * merged?  If so we do not want to record it as a parent of
+        * the resulting merge, unless --no-ff is given.  We will flip
+        * this variable to 0 when we find HEAD among the independent
+        * tips being merged.
+        */
+       *head_subsumed = 1;
+
+       /* Find what parents to record by checking independent ones. */
        parents = reduce_heads(remoteheads);
 
-       *head_subsumed = 1; /* we will flip this to 0 when we find it */
        for (remoteheads = NULL, remotes = &remoteheads;
             parents;
             parents = next) {
@@ -1075,6 +1083,7 @@ static struct commit_list *collect_parents(struct commit *head_commit,
                        *head_subsumed = 0;
                else
                        remotes = &commit_list_insert(commit, remotes)->next;
+               free(parents);
        }
        return remoteheads;
 }
@@ -1101,7 +1110,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * Check if we are _not_ on a detached HEAD, i.e. if there is a
         * current branch.
         */
-       branch = branch_to_free = resolve_refdup("HEAD", head_sha1, 0, &flag);
+       branch = branch_to_free = resolve_refdup("HEAD", 0, head_sha1, &flag);
        if (branch && starts_with(branch, "refs/heads/"))
                branch += 11;
        if (!branch || is_null_sha1(head_sha1))
@@ -1165,45 +1174,26 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                option_commit = 0;
        }
 
-       if (!abort_current_merge) {
-               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) {
+               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)
                usage_with_options(builtin_merge_usage,
                        builtin_merge_options);
 
-       /*
-        * This could be traditional "merge <msg> HEAD <commit>..."  and
-        * the way we can tell it is to see if the second token is HEAD,
-        * but some people might have misused the interface and used a
-        * commit-ish that is the same as HEAD there instead.
-        * Traditional format never would have "-m" so it is an
-        * additional safety measure to check for it.
-        */
-
-       if (!have_message && head_commit &&
-           is_old_style_invocation(argc, argv, head_commit->object.sha1)) {
-               strbuf_addstr(&merge_msg, argv[0]);
-               head_arg = argv[1];
-               argv += 2;
-               argc -= 2;
-               remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
-       } else if (!head_commit) {
+       if (!head_commit) {
                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.
                 * We do the same for "git pull".
                 */
-               if (argc != 1)
-                       die(_("Can merge only exactly one commit into "
-                               "empty head"));
                if (squash)
                        die(_("Squash commit into empty head not supported yet"));
                if (fast_forward == FF_NO)
@@ -1213,10 +1203,29 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                remote_head = remoteheads->item;
                if (!remote_head)
                        die(_("%s - not something we can merge"), argv[0]);
+               if (remoteheads->next)
+                       die(_("Can merge only exactly one commit into empty head"));
                read_empty(remote_head->object.sha1, 0);
                update_ref("initial pull", "HEAD", remote_head->object.sha1,
                           NULL, 0, UPDATE_REFS_DIE_ON_ERR);
                goto done;
+       }
+
+       /*
+        * This could be traditional "merge <msg> HEAD <commit>..."  and
+        * the way we can tell it is to see if the second token is HEAD,
+        * but some people might have misused the interface and used a
+        * commit-ish that is the same as HEAD there instead.
+        * Traditional format never would have "-m" so it is an
+        * additional safety measure to check for it.
+        */
+       if (!have_message &&
+           is_old_style_invocation(argc, argv, head_commit->object.sha1)) {
+               strbuf_addstr(&merge_msg, argv[0]);
+               head_arg = argv[1];
+               argv += 2;
+               argc -= 2;
+               remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
        } else {
                struct strbuf merge_names = STRBUF_INIT;