Merge branch 'js/sleep-without-select'
[gitweb.git] / builtin / merge.c
index a972ed6422f3de693f217ef7169ced924fd19402..85c54dcd5a21f2b8413e5f73585f5f0a6c4c5715 100644 (file)
@@ -29,6 +29,7 @@
 #include "remote.h"
 #include "fmt-merge-msg.h"
 #include "gpg-interface.h"
+#include "sequencer.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -41,8 +42,8 @@ struct strategy {
 };
 
 static const char * const builtin_merge_usage[] = {
-       N_("git merge [options] [<commit>...]"),
-       N_("git merge [options] <msg> HEAD <commit>"),
+       N_("git merge [<options>] [<commit>...]"),
+       N_("git merge [<options>] <msg> HEAD <commit>"),
        N_("git merge --abort"),
        NULL
 };
@@ -505,28 +506,6 @@ static void merge_name(const char *remote, struct strbuf *msg)
                strbuf_release(&truname);
        }
 
-       if (!strcmp(remote, "FETCH_HEAD") &&
-                       !access(git_path("FETCH_HEAD"), R_OK)) {
-               const char *filename;
-               FILE *fp;
-               struct strbuf line = STRBUF_INIT;
-               char *ptr;
-
-               filename = git_path("FETCH_HEAD");
-               fp = fopen(filename, "r");
-               if (!fp)
-                       die_errno(_("could not open '%s' for reading"),
-                                 filename);
-               strbuf_getline(&line, fp, '\n');
-               fclose(fp);
-               ptr = strstr(line.buf, "\tnot-for-merge\t");
-               if (ptr)
-                       strbuf_remove(&line, ptr-line.buf+1, 13);
-               strbuf_addbuf(msg, &line);
-               strbuf_release(&line);
-               goto cleanup;
-       }
-
        if (remote_head->util) {
                struct merge_remote_desc *desc;
                desc = merge_remote_util(remote_head);
@@ -880,28 +859,20 @@ static int finish_automerge(struct commit *head,
        return 0;
 }
 
-static int suggest_conflicts(int renormalizing)
+static int suggest_conflicts(void)
 {
        const char *filename;
        FILE *fp;
-       int pos;
+       struct strbuf msgbuf = STRBUF_INIT;
 
        filename = git_path("MERGE_MSG");
        fp = fopen(filename, "a");
        if (!fp)
                die_errno(_("Could not open '%s' for writing"), filename);
-       fprintf(fp, "\nConflicts:\n");
-       for (pos = 0; pos < active_nr; pos++) {
-               const struct cache_entry *ce = active_cache[pos];
-
-               if (ce_stage(ce)) {
-                       fprintf(fp, "\t%s\n", ce->name);
-                       while (pos + 1 < active_nr &&
-                                       !strcmp(ce->name,
-                                               active_cache[pos + 1]->name))
-                               pos++;
-               }
-       }
+
+       append_conflicts_hint(&msgbuf);
+       fputs(msgbuf.buf, fp);
+       strbuf_release(&msgbuf);
        fclose(fp);
        rerere(allow_rerere_auto);
        printf(_("Automatic merge failed; "
@@ -962,7 +933,7 @@ static int setup_with_upstream(const char ***argv)
 
        if (!branch)
                die(_("No current branch."));
-       if (!branch->remote)
+       if (!branch->remote_name)
                die(_("No remote for the current branch."));
        if (!branch->merge_nr)
                die(_("No default upstream defined for the current branch."));
@@ -1090,25 +1061,101 @@ static void prepare_merge_message(struct strbuf *merge_names, struct strbuf *mer
                strbuf_setlen(merge_msg, merge_msg->len - 1);
 }
 
+static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge_names)
+{
+       const char *filename;
+       int fd, pos, npos;
+       struct strbuf fetch_head_file = STRBUF_INIT;
+
+       if (!merge_names)
+               merge_names = &fetch_head_file;
+
+       filename = git_path("FETCH_HEAD");
+       fd = open(filename, O_RDONLY);
+       if (fd < 0)
+               die_errno(_("could not open '%s' for reading"), filename);
+
+       if (strbuf_read(merge_names, fd, 0) < 0)
+               die_errno(_("could not read '%s'"), filename);
+       if (close(fd) < 0)
+               die_errno(_("could not close '%s'"), filename);
+
+       for (pos = 0; pos < merge_names->len; pos = npos) {
+               unsigned char sha1[20];
+               char *ptr;
+               struct commit *commit;
+
+               ptr = strchr(merge_names->buf + pos, '\n');
+               if (ptr)
+                       npos = ptr - merge_names->buf + 1;
+               else
+                       npos = merge_names->len;
+
+               if (npos - pos < 40 + 2 ||
+                   get_sha1_hex(merge_names->buf + pos, sha1))
+                       commit = NULL; /* bad */
+               else if (memcmp(merge_names->buf + pos + 40, "\t\t", 2))
+                       continue; /* not-for-merge */
+               else {
+                       char saved = merge_names->buf[pos + 40];
+                       merge_names->buf[pos + 40] = '\0';
+                       commit = get_merge_parent(merge_names->buf + pos);
+                       merge_names->buf[pos + 40] = saved;
+               }
+               if (!commit) {
+                       if (ptr)
+                               *ptr = '\0';
+                       die("not something we can merge in %s: %s",
+                           filename, merge_names->buf + pos);
+               }
+               remotes = &commit_list_insert(commit, remotes)->next;
+       }
+
+       if (merge_names == &fetch_head_file)
+               strbuf_release(&fetch_head_file);
+}
+
 static struct commit_list *collect_parents(struct commit *head_commit,
                                           int *head_subsumed,
-                                          int argc, const char **argv)
+                                          int argc, const char **argv,
+                                          struct strbuf *merge_msg)
 {
        int i;
        struct commit_list *remoteheads = NULL;
        struct commit_list **remotes = &remoteheads;
+       struct strbuf merge_names = STRBUF_INIT, *autogen = NULL;
+
+       if (merge_msg && (!have_message || shortlog_len))
+               autogen = &merge_names;
 
        if (head_commit)
                remotes = &commit_list_insert(head_commit, remotes)->next;
-       for (i = 0; i < argc; i++) {
-               struct commit *commit = get_merge_parent(argv[i]);
-               if (!commit)
-                       help_unknown_ref(argv[i], "merge",
-                                        "not something we can merge");
-               remotes = &commit_list_insert(commit, remotes)->next;
+
+       if (argc == 1 && !strcmp(argv[0], "FETCH_HEAD")) {
+               handle_fetch_head(remotes, autogen);
+               remoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);
+       } else {
+               for (i = 0; i < argc; i++) {
+                       struct commit *commit = get_merge_parent(argv[i]);
+                       if (!commit)
+                               help_unknown_ref(argv[i], "merge",
+                                                "not something we can merge");
+                       remotes = &commit_list_insert(commit, remotes)->next;
+               }
+               remoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);
+               if (autogen) {
+                       struct commit_list *p;
+                       for (p = remoteheads; p; p = p->next)
+                               merge_name(merge_remote_util(p->item)->name, autogen);
+               }
+       }
+
+       if (autogen) {
+               prepare_merge_message(autogen, merge_msg);
+               strbuf_release(autogen);
        }
 
-       return reduce_parents(head_commit, head_subsumed, remoteheads);
+       return remoteheads;
 }
 
 int cmd_merge(int argc, const char **argv, const char *prefix)
@@ -1222,7 +1269,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                if (fast_forward == FF_NO)
                        die(_("Non-fast-forward commit does not make sense into "
                            "an empty head"));
-               remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
+               remoteheads = collect_parents(head_commit, &head_subsumed,
+                                             argc, argv, NULL);
                remote_head = remoteheads->item;
                if (!remote_head)
                        die(_("%s - not something we can merge"), argv[0]);
@@ -1244,11 +1292,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         */
        if (!have_message &&
            is_old_style_invocation(argc, argv, head_commit->object.sha1)) {
+               warning("old-style 'git merge <msg> HEAD <commit>' is deprecated.");
                strbuf_addstr(&merge_msg, argv[0]);
                head_arg = argv[1];
                argv += 2;
                argc -= 2;
-               remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
+               remoteheads = collect_parents(head_commit, &head_subsumed,
+                                             argc, argv, NULL);
        } else {
                /* We are invoked directly as the first-class UI. */
                head_arg = "HEAD";
@@ -1258,16 +1308,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                 * the standard merge summary message to be appended
                 * to the given message.
                 */
-               remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv);
-
-               if (!have_message || shortlog_len) {
-                       struct strbuf merge_names = STRBUF_INIT;
-
-                       for (p = remoteheads; p; p = p->next)
-                               merge_name(merge_remote_util(p->item)->name, &merge_names);
-                       prepare_merge_message(&merge_names, &merge_msg);
-                       strbuf_release(&merge_names);
-               }
+               remoteheads = collect_parents(head_commit, &head_subsumed,
+                                             argc, argv, &merge_msg);
        }
 
        if (!head_commit || !argc)
@@ -1345,7 +1387,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        if (!remoteheads)
                ; /* already up-to-date */
        else if (!remoteheads->next)
-               common = get_merge_bases(head_commit, remoteheads->item, 1);
+               common = get_merge_bases(head_commit, remoteheads->item);
        else {
                struct commit_list *list = remoteheads;
                commit_list_insert(head_commit, &list);
@@ -1442,7 +1484,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                         * merge_bases again, otherwise "git merge HEAD^
                         * HEAD^^" would be missed.
                         */
-                       common_one = get_merge_bases(head_commit, j->item, 1);
+                       common_one = get_merge_bases(head_commit, j->item);
                        if (hashcmp(common_one->item->object.sha1,
                                j->item->object.sha1)) {
                                up_to_date = 0;
@@ -1575,7 +1617,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                fprintf(stderr, _("Automatic merge went well; "
                        "stopped before committing as requested\n"));
        else
-               ret = suggest_conflicts(option_renormalize);
+               ret = suggest_conflicts();
 
 done:
        free(branch_to_free);