Merge branch 'maint-1.7.6' into maint-1.7.7
[gitweb.git] / builtin / merge.c
index 24445f411b4823c92d5335491d03ed9df59970fd..b22a8422381e73fa410d0c27a70bb9ef6cdc9232 100644 (file)
@@ -50,7 +50,6 @@ static int fast_forward_only;
 static int allow_trivial = 1, have_message;
 static struct strbuf merge_msg;
 static struct commit_list *remoteheads;
-static unsigned char head[20], stash[20];
 static struct strategy **use_strategies;
 static size_t use_strategies_nr, use_strategies_alloc;
 static const char **xopts;
@@ -217,7 +216,7 @@ static void drop_save(void)
        unlink(git_path("MERGE_MODE"));
 }
 
-static void save_state(void)
+static int save_state(unsigned char *stash)
 {
        int len;
        struct child_process cp;
@@ -236,11 +235,12 @@ static void save_state(void)
 
        if (finish_command(&cp) || len < 0)
                die(_("stash failed"));
-       else if (!len)
-               return;
+       else if (!len)          /* no changes */
+               return -1;
        strbuf_setlen(&buffer, buffer.len-1);
        if (get_sha1(buffer.buf, stash))
                die(_("not a valid object: %s"), buffer.buf);
+       return 0;
 }
 
 static void read_empty(unsigned const char *sha1, int verbose)
@@ -278,7 +278,8 @@ static void reset_hard(unsigned const char *sha1, int verbose)
                die(_("read-tree failed"));
 }
 
-static void restore_state(void)
+static void restore_state(const unsigned char *head,
+                         const unsigned char *stash)
 {
        struct strbuf sb = STRBUF_INIT;
        const char *args[] = { "stash", "apply", NULL, NULL };
@@ -308,10 +309,9 @@ static void finish_up_to_date(const char *msg)
        drop_save();
 }
 
-static void squash_message(void)
+static void squash_message(struct commit *commit)
 {
        struct rev_info rev;
-       struct commit *commit;
        struct strbuf out = STRBUF_INIT;
        struct commit_list *j;
        int fd;
@@ -326,7 +326,6 @@ static void squash_message(void)
        rev.ignore_merges = 1;
        rev.commit_format = CMIT_FMT_MEDIUM;
 
-       commit = lookup_commit(head);
        commit->object.flags |= UNINTERESTING;
        add_pending_object(&rev, &commit->object, NULL);
 
@@ -339,13 +338,14 @@ static void squash_message(void)
 
        ctx.abbrev = rev.abbrev;
        ctx.date_mode = rev.date_mode;
+       ctx.fmt = rev.commit_format;
 
        strbuf_addstr(&out, "Squashed commit of the following:\n");
        while ((commit = get_revision(&rev)) != NULL) {
                strbuf_addch(&out, '\n');
                strbuf_addf(&out, "commit %s\n",
                        sha1_to_hex(commit->object.sha1));
-               pretty_print_commit(rev.commit_format, commit, &out, &ctx);
+               pretty_print_commit(&ctx, commit, &out);
        }
        if (write(fd, out.buf, out.len) < 0)
                die_errno(_("Writing SQUASH_MSG"));
@@ -354,9 +354,11 @@ static void squash_message(void)
        strbuf_release(&out);
 }
 
-static void finish(const unsigned char *new_head, const char *msg)
+static void finish(struct commit *head_commit,
+                  const unsigned char *new_head, const char *msg)
 {
        struct strbuf reflog_message = STRBUF_INIT;
+       const unsigned char *head = head_commit->object.sha1;
 
        if (!msg)
                strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION"));
@@ -367,7 +369,7 @@ static void finish(const unsigned char *new_head, const char *msg)
                        getenv("GIT_REFLOG_ACTION"), msg);
        }
        if (squash) {
-               squash_message();
+               squash_message(head_commit);
        } else {
                if (verbosity >= 0 && !merge_msg.len)
                        printf(_("No merge message -- not updating HEAD\n"));
@@ -389,8 +391,6 @@ static void finish(const unsigned char *new_head, const char *msg)
                opts.output_format |=
                        DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
                opts.detect_rename = DIFF_DETECT_RENAME;
-               if (diff_use_color_default > 0)
-                       DIFF_OPT_SET(&opts, COLOR_DIFF);
                if (diff_setup_done(&opts) < 0)
                        die(_("diff_setup_done failed"));
                diff_tree_sha1(head, new_head, "", &opts);
@@ -550,6 +550,15 @@ static int git_merge_config(const char *k, const char *v, void *cb)
                if (is_bool && shortlog_len)
                        shortlog_len = DEFAULT_MERGE_LOG_LEN;
                return 0;
+       } else if (!strcmp(k, "merge.ff")) {
+               int boolval = git_config_maybe_bool(k, v);
+               if (0 <= boolval) {
+                       allow_fast_forward = boolval;
+               } else if (v && !strcmp(v, "only")) {
+                       allow_fast_forward = 1;
+                       fast_forward_only = 1;
+               } /* do not barf on values from future versions of git */
+               return 0;
        } else if (!strcmp(k, "merge.defaulttoupstream")) {
                default_to_upstream = git_config_bool(k, v);
                return 0;
@@ -653,7 +662,7 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 }
 
 static int try_merge_strategy(const char *strategy, struct commit_list *common,
-                             const char *head_arg)
+                             struct commit *head, const char *head_arg)
 {
        int index_fd;
        struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
@@ -699,7 +708,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                        commit_list_insert(j->item, &reversed);
 
                index_fd = hold_locked_index(lock, 1);
-               clean = merge_recursive(&o, lookup_commit(head),
+               clean = merge_recursive(&o, head,
                                remoteheads->item, reversed, &result);
                if (active_cache_changed &&
                                (write_cache(index_fd, active_cache, active_nr) ||
@@ -750,7 +759,7 @@ int checkout_fast_forward(const unsigned char *head, const unsigned char *remote
        memset(&t, 0, sizeof(t));
        memset(&dir, 0, sizeof(dir));
        dir.flags |= DIR_SHOW_IGNORED;
-       dir.exclude_per_dir = ".gitignore";
+       setup_standard_excludes(&dir);
        opts.dir = &dir;
 
        opts.head_idx = 1;
@@ -850,25 +859,26 @@ static void run_prepare_commit_msg(void)
        read_merge_msg();
 }
 
-static int merge_trivial(void)
+static int merge_trivial(struct commit *head)
 {
        unsigned char result_tree[20], result_commit[20];
        struct commit_list *parent = xmalloc(sizeof(*parent));
 
        write_tree_trivial(result_tree);
        printf(_("Wonderful.\n"));
-       parent->item = lookup_commit(head);
+       parent->item = head;
        parent->next = xmalloc(sizeof(*parent->next));
        parent->next->item = remoteheads->item;
        parent->next->next = NULL;
        run_prepare_commit_msg();
        commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
-       finish(result_commit, "In-index merge");
+       finish(head, result_commit, "In-index merge");
        drop_save();
        return 0;
 }
 
-static int finish_automerge(struct commit_list *common,
+static int finish_automerge(struct commit *head,
+                           struct commit_list *common,
                            unsigned char *result_tree,
                            const char *wt_strategy)
 {
@@ -879,12 +889,12 @@ static int finish_automerge(struct commit_list *common,
        free_commit_list(common);
        if (allow_fast_forward) {
                parents = remoteheads;
-               commit_list_insert(lookup_commit(head), &parents);
+               commit_list_insert(head, &parents);
                parents = reduce_heads(parents);
        } else {
                struct commit_list **pptr = &parents;
 
-               pptr = &commit_list_insert(lookup_commit(head),
+               pptr = &commit_list_insert(head,
                                pptr)->next;
                for (j = remoteheads; j; j = j->next)
                        pptr = &commit_list_insert(j->item, pptr)->next;
@@ -893,8 +903,8 @@ static int finish_automerge(struct commit_list *common,
        strbuf_addch(&merge_msg, '\n');
        run_prepare_commit_msg();
        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_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
+       finish(head, result_commit, buf.buf);
        strbuf_release(&buf);
        drop_save();
        return 0;
@@ -928,7 +938,8 @@ static int suggest_conflicts(int renormalizing)
        return 1;
 }
 
-static struct commit *is_old_style_invocation(int argc, const char **argv)
+static struct commit *is_old_style_invocation(int argc, const char **argv,
+                                             const unsigned char *head)
 {
        struct commit *second_token = NULL;
        if (argc > 2) {
@@ -1000,9 +1011,12 @@ static int setup_with_upstream(const char ***argv)
 int cmd_merge(int argc, const char **argv, const char *prefix)
 {
        unsigned char result_tree[20];
+       unsigned char stash[20];
+       unsigned char head_sha1[20];
+       struct commit *head_commit;
        struct strbuf buf = STRBUF_INIT;
        const char *head_arg;
-       int flag, head_invalid = 0, i;
+       int flag, i;
        int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
        struct commit_list *common = NULL;
        const char *best_strategy = NULL, *wt_strategy = NULL;
@@ -1015,18 +1029,16 @@ 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 = resolve_ref("HEAD", head, 0, &flag);
+       branch = resolve_ref("HEAD", head_sha1, 0, &flag);
        if (branch && !prefixcmp(branch, "refs/heads/"))
                branch += 11;
-       if (is_null_sha1(head))
-               head_invalid = 1;
+       if (!branch || is_null_sha1(head_sha1))
+               head_commit = NULL;
+       else
+               head_commit = lookup_commit_or_die(head_sha1, "HEAD");
 
        git_config(git_merge_config, NULL);
 
-       /* for color.ui */
-       if (diff_use_color_default == -1)
-               diff_use_color_default = git_use_color_default;
-
        if (branch_mergeoptions)
                parse_branch_merge_options(branch_mergeoptions);
        argc = parse_options(argc, argv, prefix, builtin_merge_options,
@@ -1081,9 +1093,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        if (!allow_fast_forward && fast_forward_only)
                die(_("You cannot combine --no-ff with --ff-only."));
 
-       if (!argc && !abort_current_merge && default_to_upstream)
-               argc = setup_with_upstream(&argv);
-
+       if (!abort_current_merge) {
+               if (!argc && default_to_upstream)
+                       argc = setup_with_upstream(&argv);
+               else if (argc == 1 && !strcmp(argv[0], "-"))
+                       argv[0] = "@{-1}";
+       }
        if (!argc)
                usage_with_options(builtin_merge_usage,
                        builtin_merge_options);
@@ -1097,12 +1112,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * additional safety measure to check for it.
         */
 
-       if (!have_message && is_old_style_invocation(argc, argv)) {
+       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;
-       } else if (head_invalid) {
+       } else if (!head_commit) {
                struct object *remote_head;
                /*
                 * If the merged head is a valid one there is no reason
@@ -1149,7 +1165,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                }
        }
 
-       if (head_invalid || !argc)
+       if (!head_commit || !argc)
                usage_with_options(builtin_merge_usage,
                        builtin_merge_options);
 
@@ -1190,17 +1206,16 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        }
 
        if (!remoteheads->next)
-               common = get_merge_bases(lookup_commit(head),
-                               remoteheads->item, 1);
+               common = get_merge_bases(head_commit, remoteheads->item, 1);
        else {
                struct commit_list *list = remoteheads;
-               commit_list_insert(lookup_commit(head), &list);
+               commit_list_insert(head_commit, &list);
                common = get_octopus_merge_bases(list);
                free(list);
        }
 
-       update_ref("updating ORIG_HEAD", "ORIG_HEAD", head, NULL, 0,
-               DIE_ON_ERR);
+       update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.sha1,
+                  NULL, 0, DIE_ON_ERR);
 
        if (!common)
                ; /* No common ancestors found. We need a real merge. */
@@ -1214,13 +1229,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                return 0;
        } else if (allow_fast_forward && !remoteheads->next &&
                        !common->next &&
-                       !hashcmp(common->item->object.sha1, head)) {
+                       !hashcmp(common->item->object.sha1, head_commit->object.sha1)) {
                /* Again the most common case of merging one remote. */
                struct strbuf msg = STRBUF_INIT;
                struct object *o;
                char hex[41];
 
-               strcpy(hex, find_unique_abbrev(head, DEFAULT_ABBREV));
+               strcpy(hex, find_unique_abbrev(head_commit->object.sha1, DEFAULT_ABBREV));
 
                if (verbosity >= 0)
                        printf(_("Updating %s..%s\n"),
@@ -1236,10 +1251,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                if (!o)
                        return 1;
 
-               if (checkout_fast_forward(head, remoteheads->item->object.sha1))
+               if (checkout_fast_forward(head_commit->object.sha1, remoteheads->item->object.sha1))
                        return 1;
 
-               finish(o->sha1, msg.buf);
+               finish(head_commit, o->sha1, msg.buf);
                drop_save();
                return 0;
        } else if (!remoteheads->next && common->next)
@@ -1259,8 +1274,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        git_committer_info(IDENT_ERROR_ON_NO_NAME);
                        printf(_("Trying really trivial in-index merge...\n"));
                        if (!read_tree_trivial(common->item->object.sha1,
-                                       head, remoteheads->item->object.sha1))
-                               return merge_trivial();
+                                       head_commit->object.sha1, remoteheads->item->object.sha1))
+                               return merge_trivial(head_commit);
                        printf(_("Nope.\n"));
                }
        } else {
@@ -1279,8 +1294,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(lookup_commit(head),
-                               j->item, 1);
+                       common_one = get_merge_bases(head_commit, j->item, 1);
                        if (hashcmp(common_one->item->object.sha1,
                                j->item->object.sha1)) {
                                up_to_date = 0;
@@ -1307,21 +1321,18 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * sync with the head commit.  The strategies are responsible
         * to ensure this.
         */
-       if (use_strategies_nr != 1) {
-               /*
-                * Stash away the local changes so that we can try more
-                * than one.
-                */
-               save_state();
-       } else {
-               memcpy(stash, null_sha1, 20);
-       }
+       if (use_strategies_nr == 1 ||
+           /*
+            * Stash away the local changes so that we can try more than one.
+            */
+           save_state(stash))
+               hashcpy(stash, null_sha1);
 
        for (i = 0; i < use_strategies_nr; i++) {
                int ret;
                if (i) {
                        printf(_("Rewinding the tree to pristine...\n"));
-                       restore_state();
+                       restore_state(head_commit->object.sha1, stash);
                }
                if (use_strategies_nr != 1)
                        printf(_("Trying merge strategy %s...\n"),
@@ -1333,7 +1344,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                wt_strategy = use_strategies[i]->name;
 
                ret = try_merge_strategy(use_strategies[i]->name,
-                       common, head_arg);
+                                        common, head_commit, head_arg);
                if (!option_commit && !ret) {
                        merge_was_ok = 1;
                        /*
@@ -1375,14 +1386,15 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * auto resolved the merge cleanly.
         */
        if (automerge_was_ok)
-               return finish_automerge(common, result_tree, wt_strategy);
+               return finish_automerge(head_commit, common, result_tree,
+                                       wt_strategy);
 
        /*
         * Pick the result from the best strategy and have the user fix
         * it up.
         */
        if (!best_strategy) {
-               restore_state();
+               restore_state(head_commit->object.sha1, stash);
                if (use_strategies_nr > 1)
                        fprintf(stderr,
                                _("No merge strategy handled the merge.\n"));
@@ -1394,14 +1406,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                ; /* We already have its result in the working tree. */
        else {
                printf(_("Rewinding the tree to pristine...\n"));
-               restore_state();
+               restore_state(head_commit->object.sha1, stash);
                printf(_("Using the %s to prepare resolving by hand.\n"),
                        best_strategy);
-               try_merge_strategy(best_strategy, common, head_arg);
+               try_merge_strategy(best_strategy, common, head_commit, head_arg);
        }
 
        if (squash)
-               finish(NULL, NULL);
+               finish(head_commit, NULL, NULL);
        else {
                int fd;
                struct commit_list *j;