]> asedeno.scripts.mit.edu Git - git.git/blobdiff - builtin-merge.c
git grep: Add "-z/--null" option as in GNU's grep.
[git.git] / builtin-merge.c
index 3e8db0d383430eaa45fa4ffc4929609efd9932b4..5c65a5869900ad1a1014fb3aad88c874a5410bf7 100644 (file)
@@ -23,6 +23,7 @@
 #include "color.h"
 #include "rerere.h"
 #include "help.h"
+#include "merge-recursive.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -80,7 +81,7 @@ static struct strategy *get_strategy(const char *name)
        int i;
        struct strategy *ret;
        static struct cmdnames main_cmds, other_cmds;
-       static int longest;
+       static int loaded;
 
        if (!name)
                return NULL;
@@ -89,14 +90,12 @@ static struct strategy *get_strategy(const char *name)
                if (!strcmp(name, all_strategy[i].name))
                        return &all_strategy[i];
 
-       if (!longest) {
+       if (!loaded) {
                struct cmdnames not_strategies;
+               loaded = 1;
 
-               memset(&main_cmds, 0, sizeof(struct cmdnames));
-               memset(&other_cmds, 0, sizeof(struct cmdnames));
                memset(&not_strategies, 0, sizeof(struct cmdnames));
-               longest = load_command_list("git-merge-", &main_cmds,
-                               &other_cmds);
+               load_command_list("git-merge-", &main_cmds, &other_cmds);
                for (i = 0; i < main_cmds.cnt; i++) {
                        int j, found = 0;
                        struct cmdname *ent = main_cmds.names[i];
@@ -432,12 +431,12 @@ static void merge_name(const char *remote, struct strbuf *msg)
                struct strbuf truname = STRBUF_INIT;
                strbuf_addstr(&truname, "refs/heads/");
                strbuf_addstr(&truname, remote);
-               strbuf_setlen(&truname, len+11);
+               strbuf_setlen(&truname, truname.len - len);
                if (resolve_ref(truname.buf, buf_sha, 0, 0)) {
                        strbuf_addf(msg,
                                    "%s\t\tbranch '%s'%s of .\n",
                                    sha1_to_hex(remote_head->sha1),
-                                   truname.buf,
+                                   truname.buf + 11,
                                    (early ? " (early part)" : ""));
                        return;
                }
@@ -478,6 +477,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 
                buf = xstrdup(v);
                argc = split_cmdline(buf, &argv);
+               if (argc < 0)
+                       die("Bad branch.%s.mergeoptions string", branch);
                argv = xrealloc(argv, sizeof(*argv) * (argc + 2));
                memmove(argv + 1, argv, sizeof(*argv) * (argc + 1));
                argc++;
@@ -547,28 +548,65 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
        struct commit_list *j;
        struct strbuf buf;
 
-       args = xmalloc((4 + commit_list_count(common) +
-                       commit_list_count(remoteheads)) * sizeof(char *));
-       strbuf_init(&buf, 0);
-       strbuf_addf(&buf, "merge-%s", strategy);
-       args[i++] = buf.buf;
-       for (j = common; j; j = j->next)
-               args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
-       args[i++] = "--";
-       args[i++] = head_arg;
-       for (j = remoteheads; j; j = j->next)
-               args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
-       args[i] = NULL;
-       ret = run_command_v_opt(args, RUN_GIT_CMD);
-       strbuf_release(&buf);
-       i = 1;
-       for (j = common; j; j = j->next)
-               free((void *)args[i++]);
-       i += 2;
-       for (j = remoteheads; j; j = j->next)
-               free((void *)args[i++]);
-       free(args);
-       return -ret;
+       if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) {
+               int clean;
+               struct commit *result;
+               struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+               int index_fd;
+               struct commit_list *reversed = NULL;
+               struct merge_options o;
+
+               if (remoteheads->next) {
+                       error("Not handling anything other than two heads merge.");
+                       return 2;
+               }
+
+               init_merge_options(&o);
+               if (!strcmp(strategy, "subtree"))
+                       o.subtree_merge = 1;
+
+               o.branch1 = head_arg;
+               o.branch2 = remoteheads->item->util;
+
+               for (j = common; j; j = j->next)
+                       commit_list_insert(j->item, &reversed);
+
+               index_fd = hold_locked_index(lock, 1);
+               clean = merge_recursive(&o, lookup_commit(head),
+                               remoteheads->item, reversed, &result);
+               if (active_cache_changed &&
+                               (write_cache(index_fd, active_cache, active_nr) ||
+                                commit_locked_index(lock)))
+                       die ("unable to write %s", get_index_file());
+               rollback_lock_file(lock);
+               return clean ? 0 : 1;
+       } else {
+               args = xmalloc((4 + commit_list_count(common) +
+                                       commit_list_count(remoteheads)) * sizeof(char *));
+               strbuf_init(&buf, 0);
+               strbuf_addf(&buf, "merge-%s", strategy);
+               args[i++] = buf.buf;
+               for (j = common; j; j = j->next)
+                       args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
+               args[i++] = "--";
+               args[i++] = head_arg;
+               for (j = remoteheads; j; j = j->next)
+                       args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));
+               args[i] = NULL;
+               ret = run_command_v_opt(args, RUN_GIT_CMD);
+               strbuf_release(&buf);
+               i = 1;
+               for (j = common; j; j = j->next)
+                       free((void *)args[i++]);
+               i += 2;
+               for (j = remoteheads; j; j = j->next)
+                       free((void *)args[i++]);
+               free(args);
+               discard_cache();
+               if (read_cache() < 0)
+                       die("failed to read the cache");
+               return -ret;
+       }
 }
 
 static void count_diff_files(struct diff_queue_struct *q,
@@ -600,8 +638,7 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote)
        struct dir_struct dir;
        struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
 
-       if (read_cache_unmerged())
-               die("you need to resolve your current index first");
+       refresh_cache(REFRESH_QUIET);
 
        fd = hold_locked_index(lock_file, 1);
 
@@ -686,13 +723,15 @@ static void add_strategies(const char *string, unsigned attr)
 static int merge_trivial(void)
 {
        unsigned char result_tree[20], result_commit[20];
-       struct commit_list parent;
+       struct commit_list *parent = xmalloc(sizeof(struct commit_list *));
 
        write_tree_trivial(result_tree);
        printf("Wonderful.\n");
-       parent.item = remoteheads->item;
-       parent.next = NULL;
-       commit_tree(merge_msg.buf, result_tree, &parent, result_commit);
+       parent->item = lookup_commit(head);
+       parent->next = xmalloc(sizeof(struct commit_list *));
+       parent->next->item = remoteheads->item;
+       parent->next->next = NULL;
+       commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
        finish(result_commit, "In-index merge");
        drop_save();
        return 0;
@@ -721,7 +760,7 @@ static int finish_automerge(struct commit_list *common,
        }
        free_commit_list(remoteheads);
        strbuf_addch(&merge_msg, '\n');
-       commit_tree(merge_msg.buf, result_tree, parents, result_commit);
+       commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
        strbuf_addf(&buf, "Merge made by %s.", wt_strategy);
        finish(result_commit, buf.buf);
        strbuf_release(&buf);
@@ -778,9 +817,6 @@ static int evaluate_result(void)
        int cnt = 0;
        struct rev_info rev;
 
-       if (read_cache() < 0)
-               die("failed to read the cache");
-
        /* Check how many files differ. */
        init_revisions(&rev, "");
        setup_revisions(0, NULL, &rev, NULL);
@@ -811,7 +847,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        struct commit_list **remotes = &remoteheads;
 
        setup_work_tree();
-       if (unmerged_cache())
+       if (read_cache_unmerged())
                die("You are in the middle of a conflicted merge.");
 
        /*
@@ -868,6 +904,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                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 (!allow_fast_forward)
+                       die("Non-fast-forward commit does not make sense into "
+                           "an empty head");
                remote_head = peel_to_type(argv[0], 0, NULL, OBJ_COMMIT);
                if (!remote_head)
                        die("%s - not something we can merge", argv[0]);
@@ -909,12 +950,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 
        for (i = 0; i < argc; i++) {
                struct object *o;
+               struct commit *commit;
 
                o = peel_to_type(argv[i], 0, NULL, OBJ_COMMIT);
                if (!o)
                        die("%s - not something we can merge", argv[i]);
-               remotes = &commit_list_insert(lookup_commit(o->sha1),
-                       remotes)->next;
+               commit = lookup_commit(o->sha1);
+               commit->util = (void *)argv[i];
+               remotes = &commit_list_insert(commit, remotes)->next;
 
                strbuf_addf(&buf, "GITHEAD_%s", sha1_to_hex(o->sha1));
                setenv(buf.buf, argv[i], 1);
@@ -972,7 +1015,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        hex,
                        find_unique_abbrev(remoteheads->item->object.sha1,
                        DEFAULT_ABBREV));
-               refresh_cache(REFRESH_QUIET);
                strbuf_init(&msg, 0);
                strbuf_addstr(&msg, "Fast forward");
                if (have_message)