Merge branch 'jc/merge-bases'
authorJunio C Hamano <gitster@pobox.com>
Tue, 11 Sep 2012 18:35:26 +0000 (11:35 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 11 Sep 2012 18:36:05 +0000 (11:36 -0700)
Optimise the "merge-base" computation a bit, and also update its
users that do not need the full merge-base information to call a
cheaper subset.

* jc/merge-bases:
reduce_heads(): reimplement on top of remove_redundant()
merge-base: "--is-ancestor A B"
get_merge_bases_many(): walk from many tips in parallel
in_merge_bases(): use paint_down_to_common()
merge_bases_many(): split out the logic to paint history
in_merge_bases(): omit unnecessary redundant common ancestor reduction
http-push: use in_merge_bases() for fast-forward check
receive-pack: use in_merge_bases() for fast-forward check
in_merge_bases(): support only one "other" commit

1  2 
builtin/branch.c
builtin/fetch.c
builtin/merge-base.c
builtin/receive-pack.c
commit.c
commit.h
contrib/examples/builtin-fetch--tool.c
fast-import.c
http-push.c
submodule.c
diff --combined builtin/branch.c
index e61b0ece2199f0d2b637cd2ce879105280c38d21,98fa5d628477ddcd02e557d5dd594f92b4a09c9e..5cb6d78f2c472cc6e579bf6618898f0e44e5ef03
  #include "branch.h"
  #include "diff.h"
  #include "revision.h"
 +#include "string-list.h"
 +#include "column.h"
 +#include "utf8.h"
  
  static const char * const builtin_branch_usage[] = {
 -      "git branch [options] [-r | -a] [--merged | --no-merged]",
 -      "git branch [options] [-l] [-f] <branchname> [<start-point>]",
 -      "git branch [options] [-r] (-d | -D) <branchname>...",
 -      "git branch [options] (-m | -M) [<oldbranch>] <newbranch>",
 +      N_("git branch [options] [-r | -a] [--merged | --no-merged]"),
 +      N_("git branch [options] [-l] [-f] <branchname> [<start-point>]"),
 +      N_("git branch [options] [-r] (-d | -D) <branchname>..."),
 +      N_("git branch [options] (-m | -M) [<oldbranch>] <newbranch>"),
        NULL
  };
  
@@@ -56,9 -53,6 +56,9 @@@ static enum merge_filter 
  } merge_filter;
  static unsigned char merge_filter_ref[20];
  
 +static struct string_list output = STRING_LIST_INIT_DUP;
 +static unsigned int colopts;
 +
  static int parse_branch_color_slot(const char *var, int ofs)
  {
        if (!strcasecmp(var+ofs, "plain"))
@@@ -76,8 -70,6 +76,8 @@@
  
  static int git_branch_config(const char *var, const char *value, void *cb)
  {
 +      if (!prefixcmp(var, "column."))
 +              return git_column_config(var, value, "branch", &colopts);
        if (!strcmp(var, "color.branch")) {
                branch_use_color = git_config_colorbool(var, value);
                return 0;
@@@ -130,7 -122,7 +130,7 @@@ static int branch_merged(int kind, cons
        if (!reference_rev)
                reference_rev = head_rev;
  
-       merged = in_merge_bases(rev, &reference_rev, 1);
+       merged = in_merge_bases(rev, reference_rev);
  
        /*
         * After the safety valve is fully redefined to "check with
         * a gentle reminder is in order.
         */
        if ((head_rev != reference_rev) &&
-           in_merge_bases(rev, &head_rev, 1) != merged) {
+           in_merge_bases(rev, head_rev) != merged) {
                if (merged)
                        warning(_("deleting branch '%s' that has been merged to\n"
                                "         '%s', but not yet merged to HEAD."),
        return merged;
  }
  
 -static int delete_branches(int argc, const char **argv, int force, int kinds)
 +static int delete_branches(int argc, const char **argv, int force, int kinds,
 +                         int quiet)
  {
        struct commit *rev, *head_rev = NULL;
        unsigned char sha1[20];
        char *name = NULL;
 -      const char *fmt, *remote;
 +      const char *fmt;
        int i;
        int ret = 0;
 +      int remote_branch = 0;
        struct strbuf bname = STRBUF_INIT;
  
        switch (kinds) {
        case REF_REMOTE_BRANCH:
                fmt = "refs/remotes/%s";
 -              /* TRANSLATORS: This is "remote " in "remote branch '%s' not found" */
 -              remote = _("remote ");
 +              /* For subsequent UI messages */
 +              remote_branch = 1;
 +
                force = 1;
                break;
        case REF_LOCAL_BRANCH:
                fmt = "refs/heads/%s";
 -              remote = "";
                break;
        default:
                die(_("cannot use -a with -d"));
  
                name = xstrdup(mkpath(fmt, bname.buf));
                if (read_ref(name, sha1)) {
 -                      error(_("%sbranch '%s' not found."),
 -                                      remote, bname.buf);
 +                      error(remote_branch
 +                            ? _("remote branch '%s' not found.")
 +                            : _("branch '%s' not found."), bname.buf);
                        ret = 1;
                        continue;
                }
                }
  
                if (delete_ref(name, sha1, 0)) {
 -                      error(_("Error deleting %sbranch '%s'"), remote,
 +                      error(remote_branch
 +                            ? _("Error deleting remote branch '%s'")
 +                            : _("Error deleting branch '%s'"),
                              bname.buf);
                        ret = 1;
                } else {
                        struct strbuf buf = STRBUF_INIT;
 -                      printf(_("Deleted %sbranch %s (was %s).\n"), remote,
 -                             bname.buf,
 -                             find_unique_abbrev(sha1, DEFAULT_ABBREV));
 +                      if (!quiet)
 +                              printf(remote_branch
 +                                     ? _("Deleted remote branch %s (was %s).\n")
 +                                     : _("Deleted branch %s (was %s).\n"),
 +                                     bname.buf,
 +                                     find_unique_abbrev(sha1, DEFAULT_ABBREV));
                        strbuf_addf(&buf, "branch.%s", bname.buf);
                        if (git_config_rename_section(buf.buf, NULL) < 0)
                                warning(_("Update of config-file failed"));
  struct ref_item {
        char *name;
        char *dest;
 -      unsigned int kind, len;
 +      unsigned int kind, width;
        struct commit *commit;
  };
  
@@@ -355,14 -339,14 +355,14 @@@ static int append_ref(const char *refna
        newitem->name = xstrdup(refname);
        newitem->kind = kind;
        newitem->commit = commit;
 -      newitem->len = strlen(refname);
 +      newitem->width = utf8_strwidth(refname);
        newitem->dest = resolve_symref(orig_refname, prefix);
        /* adjust for "remotes/" */
        if (newitem->kind == REF_REMOTE_BRANCH &&
            ref_list->kinds != REF_REMOTE_BRANCH)
 -              newitem->len += 8;
 -      if (newitem->len > ref_list->maxwidth)
 -              ref_list->maxwidth = newitem->len;
 +              newitem->width += 8;
 +      if (newitem->width > ref_list->maxwidth)
 +              ref_list->maxwidth = newitem->width;
  
        return 0;
  }
@@@ -392,7 -376,6 +392,7 @@@ static void fill_tracking_info(struct s
                int show_upstream_ref)
  {
        int ours, theirs;
 +      char *ref = NULL;
        struct branch *branch = branch_get(branch_name);
  
        if (!stat_tracking_info(branch, &ours, &theirs)) {
                return;
        }
  
 -      strbuf_addch(stat, '[');
        if (show_upstream_ref)
 -              strbuf_addf(stat, "%s: ",
 -                      shorten_unambiguous_ref(branch->merge[0]->dst, 0));
 -      if (!ours)
 -              strbuf_addf(stat, _("behind %d] "), theirs);
 -      else if (!theirs)
 -              strbuf_addf(stat, _("ahead %d] "), ours);
 -      else
 -              strbuf_addf(stat, _("ahead %d, behind %d] "), ours, theirs);
 +              ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
 +      if (!ours) {
 +              if (ref)
 +                      strbuf_addf(stat, _("[%s: behind %d]"), ref, theirs);
 +              else
 +                      strbuf_addf(stat, _("[behind %d]"), theirs);
 +
 +      } else if (!theirs) {
 +              if (ref)
 +                      strbuf_addf(stat, _("[%s: ahead %d]"), ref, ours);
 +              else
 +                      strbuf_addf(stat, _("[ahead %d]"), ours);
 +      } else {
 +              if (ref)
 +                      strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
 +                                  ref, ours, theirs);
 +              else
 +                      strbuf_addf(stat, _("[ahead %d, behind %d]"),
 +                                  ours, theirs);
 +      }
 +      strbuf_addch(stat, ' ');
 +      free(ref);
  }
  
  static int matches_merge_filter(struct commit *commit)
@@@ -491,12 -461,11 +491,12 @@@ static void print_ref_item(struct ref_i
        }
  
        strbuf_addf(&name, "%s%s", prefix, item->name);
 -      if (verbose)
 +      if (verbose) {
 +              int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);
                strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
 -                          maxwidth, name.buf,
 +                          maxwidth + utf8_compensation, name.buf,
                            branch_get_color(BRANCH_COLOR_RESET));
 -      else
 +      else
                strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
                            name.buf, branch_get_color(BRANCH_COLOR_RESET));
  
        else if (verbose)
                /* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
                add_verbose_info(&out, item, verbose, abbrev);
 -      printf("%s\n", out.buf);
 +      if (column_active(colopts)) {
 +              assert(!verbose && "--column and --verbose are incompatible");
 +              string_list_append(&output, out.buf);
 +      } else {
 +              printf("%s\n", out.buf);
 +      }
        strbuf_release(&name);
        strbuf_release(&out);
  }
@@@ -521,8 -485,8 +521,8 @@@ static int calc_maxwidth(struct ref_lis
        for (i = 0; i < refs->index; i++) {
                if (!matches_merge_filter(refs->list[i].commit))
                        continue;
 -              if (refs->list[i].len > w)
 -                      w = refs->list[i].len;
 +              if (refs->list[i].width > w)
 +                      w = refs->list[i].width;
        }
        return w;
  }
@@@ -535,12 -499,12 +535,12 @@@ static void show_detached(struct ref_li
        if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {
                struct ref_item item;
                item.name = xstrdup(_("(no branch)"));
 -              item.len = strlen(item.name);
 +              item.width = utf8_strwidth(item.name);
                item.kind = REF_LOCAL_BRANCH;
                item.dest = NULL;
                item.commit = head_commit;
 -              if (item.len > ref_list->maxwidth)
 -                      ref_list->maxwidth = item.len;
 +              if (item.width > ref_list->maxwidth)
 +                      ref_list->maxwidth = item.width;
                print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, "");
                free(item.name);
        }
@@@ -691,7 -655,7 +691,7 @@@ static int edit_branch_description(cons
        fp = fopen(git_path(edit_description), "w");
        if ((fwrite(buf.buf, 1, buf.len, fp) < buf.len) || fclose(fp)) {
                strbuf_release(&buf);
 -              return error(_("could not write branch description template: %s\n"),
 +              return error(_("could not write branch description template: %s"),
                             strerror(errno));
        }
        strbuf_reset(&buf);
@@@ -714,65 -678,59 +714,65 @@@ int cmd_branch(int argc, const char **a
        int delete = 0, rename = 0, force_create = 0, list = 0;
        int verbose = 0, abbrev = -1, detached = 0;
        int reflog = 0, edit_description = 0;
 +      int quiet = 0, unset_upstream = 0;
 +      const char *new_upstream = NULL;
        enum branch_track track;
        int kinds = REF_LOCAL_BRANCH;
        struct commit_list *with_commit = NULL;
  
        struct option options[] = {
 -              OPT_GROUP("Generic options"),
 +              OPT_GROUP(N_("Generic options")),
                OPT__VERBOSE(&verbose,
 -                      "show hash and subject, give twice for upstream branch"),
 -              OPT_SET_INT('t', "track",  &track, "set up tracking mode (see git-pull(1))",
 +                      N_("show hash and subject, give twice for upstream branch")),
 +              OPT__QUIET(&quiet, N_("suppress informational messages")),
 +              OPT_SET_INT('t', "track",  &track, N_("set up tracking mode (see git-pull(1))"),
                        BRANCH_TRACK_EXPLICIT),
 -              OPT_SET_INT( 0, "set-upstream",  &track, "change upstream info",
 +              OPT_SET_INT( 0, "set-upstream",  &track, N_("change upstream info"),
                        BRANCH_TRACK_OVERRIDE),
 -              OPT__COLOR(&branch_use_color, "use colored output"),
 -              OPT_SET_INT('r', "remotes",     &kinds, "act on remote-tracking branches",
 +              OPT_STRING('u', "set-upstream-to", &new_upstream, "upstream", "change the upstream info"),
 +              OPT_BOOLEAN(0, "unset-upstream", &unset_upstream, "Unset the upstream info"),
 +              OPT__COLOR(&branch_use_color, N_("use colored output")),
 +              OPT_SET_INT('r', "remotes",     &kinds, N_("act on remote-tracking branches"),
                        REF_REMOTE_BRANCH),
                {
 -                      OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
 -                      "print only branches that contain the commit",
 +                      OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
 +                      N_("print only branches that contain the commit"),
                        PARSE_OPT_LASTARG_DEFAULT,
                        parse_opt_with_commit, (intptr_t)"HEAD",
                },
                {
 -                      OPTION_CALLBACK, 0, "with", &with_commit, "commit",
 -                      "print only branches that contain the commit",
 +                      OPTION_CALLBACK, 0, "with", &with_commit, N_("commit"),
 +                      N_("print only branches that contain the commit"),
                        PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT,
                        parse_opt_with_commit, (intptr_t) "HEAD",
                },
                OPT__ABBREV(&abbrev),
  
 -              OPT_GROUP("Specific git-branch actions:"),
 -              OPT_SET_INT('a', "all", &kinds, "list both remote-tracking and local branches",
 +              OPT_GROUP(N_("Specific git-branch actions:")),
 +              OPT_SET_INT('a', "all", &kinds, N_("list both remote-tracking and local branches"),
                        REF_REMOTE_BRANCH | REF_LOCAL_BRANCH),
 -              OPT_BIT('d', "delete", &delete, "delete fully merged branch", 1),
 -              OPT_BIT('D', NULL, &delete, "delete branch (even if not merged)", 2),
 -              OPT_BIT('m', "move", &rename, "move/rename a branch and its reflog", 1),
 -              OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2),
 -              OPT_BOOLEAN(0, "list", &list, "list branch names"),
 -              OPT_BOOLEAN('l', "create-reflog", &reflog, "create the branch's reflog"),
 +              OPT_BIT('d', "delete", &delete, N_("delete fully merged branch"), 1),
 +              OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2),
 +              OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1),
 +              OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2),
 +              OPT_BOOLEAN(0, "list", &list, N_("list branch names")),
 +              OPT_BOOLEAN('l', "create-reflog", &reflog, N_("create the branch's reflog")),
                OPT_BOOLEAN(0, "edit-description", &edit_description,
 -                          "edit the description for the branch"),
 -              OPT__FORCE(&force_create, "force creation (when already exists)"),
 +                          N_("edit the description for the branch")),
 +              OPT__FORCE(&force_create, N_("force creation (when already exists)")),
                {
                        OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
 -                      "commit", "print only not merged branches",
 +                      N_("commit"), N_("print only not merged branches"),
                        PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
                        opt_parse_merge_filter, (intptr_t) "HEAD",
                },
                {
                        OPTION_CALLBACK, 0, "merged", &merge_filter_ref,
 -                      "commit", "print only merged branches",
 +                      N_("commit"), N_("print only merged branches"),
                        PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
                        opt_parse_merge_filter, (intptr_t) "HEAD",
                },
 +              OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
                OPT_END(),
        };
  
        }
        hashcpy(merge_filter_ref, head_sha1);
  
 +
        argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
                             0);
  
 -      if (!delete && !rename && !edit_description && argc == 0)
 +      if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)
                list = 1;
  
 -      if (!!delete + !!rename + !!force_create + !!list > 1)
 +      if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1)
                usage_with_options(builtin_branch_usage, options);
  
        if (abbrev == -1)
                abbrev = DEFAULT_ABBREV;
 +      finalize_colopts(&colopts, -1);
 +      if (verbose) {
 +              if (explicitly_enable_column(colopts))
 +                      die(_("--column and --verbose are incompatible"));
 +              colopts = 0;
 +      }
  
        if (delete)
 -              return delete_branches(argc, argv, delete > 1, kinds);
 -      else if (list)
 -              return print_ref_list(kinds, detached, verbose, abbrev,
 -                                    with_commit, argv);
 +              return delete_branches(argc, argv, delete > 1, kinds, quiet);
 +      else if (list) {
 +              int ret = print_ref_list(kinds, detached, verbose, abbrev,
 +                                       with_commit, argv);
 +              print_columns(&output, colopts, NULL);
 +              string_list_clear(&output, 0);
 +              return ret;
 +      }
        else if (edit_description) {
                const char *branch_name;
                struct strbuf branch_ref = STRBUF_INIT;
                        rename_branch(argv[0], argv[1], rename > 1);
                else
                        usage_with_options(builtin_branch_usage, options);
 +      } else if (new_upstream) {
 +              struct branch *branch = branch_get(argv[0]);
 +
 +              if (!ref_exists(branch->refname))
 +                      die(_("branch '%s' does not exist"), branch->name);
 +
 +              /*
 +               * create_branch takes care of setting up the tracking
 +               * info and making sure new_upstream is correct
 +               */
 +              create_branch(head, branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE);
 +      } else if (unset_upstream) {
 +              struct branch *branch = branch_get(argv[0]);
 +              struct strbuf buf = STRBUF_INIT;
 +
 +              if (!branch_has_merge_config(branch)) {
 +                      die(_("Branch '%s' has no upstream information"), branch->name);
 +              }
 +
 +              strbuf_addf(&buf, "branch.%s.remote", branch->name);
 +              git_config_set_multivar(buf.buf, NULL, NULL, 1);
 +              strbuf_reset(&buf);
 +              strbuf_addf(&buf, "branch.%s.merge", branch->name);
 +              git_config_set_multivar(buf.buf, NULL, NULL, 1);
 +              strbuf_release(&buf);
        } else if (argc > 0 && argc <= 2) {
 +              struct branch *branch = branch_get(argv[0]);
 +              int branch_existed = 0, remote_tracking = 0;
 +              struct strbuf buf = STRBUF_INIT;
 +
                if (kinds != REF_LOCAL_BRANCH)
                        die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
 +
 +              if (track == BRANCH_TRACK_OVERRIDE)
 +                      fprintf(stderr, _("The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to\n"));
 +
 +              strbuf_addf(&buf, "refs/remotes/%s", branch->name);
 +              remote_tracking = ref_exists(buf.buf);
 +              strbuf_release(&buf);
 +
 +              branch_existed = ref_exists(branch->refname);
                create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
 -                            force_create, reflog, 0, track);
 +                            force_create, reflog, 0, quiet, track);
 +
 +              /*
 +               * We only show the instructions if the user gave us
 +               * one branch which doesn't exist locally, but is the
 +               * name of a remote-tracking branch.
 +               */
 +              if (argc == 1 && track == BRANCH_TRACK_OVERRIDE &&
 +                  !branch_existed && remote_tracking) {
 +                      fprintf(stderr, _("\nIf you wanted to make '%s' track '%s', do this:\n\n"), head, branch->name);
 +                      fprintf(stderr, _("    git branch -d %s\n"), branch->name);
 +                      fprintf(stderr, _("    git branch --set-upstream-to %s\n"), branch->name);
 +              }
 +
        } else
                usage_with_options(builtin_branch_usage, options);
  
diff --combined builtin/fetch.c
index 3f2ad7727fbff9f12cb18c69d925e2717c2a768b,97327e6cc6f5e890c7e10174d7bea5c41d96b28e..97a849a9dc082555fe1cbe6d0216d03563c75951
  #include "connected.h"
  
  static const char * const builtin_fetch_usage[] = {
 -      "git fetch [<options>] [<repository> [<refspec>...]]",
 -      "git fetch [<options>] <group>",
 -      "git fetch --multiple [<options>] [(<repository> | <group>)...]",
 -      "git fetch --all [<options>]",
 +      N_("git fetch [<options>] [<repository> [<refspec>...]]"),
 +      N_("git fetch [<options>] <group>"),
 +      N_("git fetch --multiple [<options>] [(<repository> | <group>)...]"),
 +      N_("git fetch --all [<options>]"),
        NULL
  };
  
@@@ -56,36 -56,36 +56,36 @@@ static int option_parse_recurse_submodu
  static struct option builtin_fetch_options[] = {
        OPT__VERBOSITY(&verbosity),
        OPT_BOOLEAN(0, "all", &all,
 -                  "fetch from all remotes"),
 +                  N_("fetch from all remotes")),
        OPT_BOOLEAN('a', "append", &append,
 -                  "append to .git/FETCH_HEAD instead of overwriting"),
 -      OPT_STRING(0, "upload-pack", &upload_pack, "path",
 -                 "path to upload pack on remote end"),
 -      OPT__FORCE(&force, "force overwrite of local branch"),
 +                  N_("append to .git/FETCH_HEAD instead of overwriting")),
 +      OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
 +                 N_("path to upload pack on remote end")),
 +      OPT__FORCE(&force, N_("force overwrite of local branch")),
        OPT_BOOLEAN('m', "multiple", &multiple,
 -                  "fetch from multiple remotes"),
 +                  N_("fetch from multiple remotes")),
        OPT_SET_INT('t', "tags", &tags,
 -                  "fetch all tags and associated objects", TAGS_SET),
 +                  N_("fetch all tags and associated objects"), TAGS_SET),
        OPT_SET_INT('n', NULL, &tags,
 -                  "do not fetch all tags (--no-tags)", TAGS_UNSET),
 +                  N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
        OPT_BOOLEAN('p', "prune", &prune,
 -                  "prune remote-tracking branches no longer on remote"),
 -      { OPTION_CALLBACK, 0, "recurse-submodules", NULL, "on-demand",
 -                  "control recursive fetching of submodules",
 +                  N_("prune remote-tracking branches no longer on remote")),
 +      { OPTION_CALLBACK, 0, "recurse-submodules", NULL, N_("on-demand"),
 +                  N_("control recursive fetching of submodules"),
                    PARSE_OPT_OPTARG, option_parse_recurse_submodules },
        OPT_BOOLEAN(0, "dry-run", &dry_run,
 -                  "dry run"),
 -      OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
 +                  N_("dry run")),
 +      OPT_BOOLEAN('k', "keep", &keep, N_("keep downloaded pack")),
        OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
 -                  "allow updating of HEAD ref"),
 -      OPT_BOOL(0, "progress", &progress, "force progress reporting"),
 -      OPT_STRING(0, "depth", &depth, "depth",
 -                 "deepen history of shallow clone"),
 -      { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "dir",
 -                 "prepend this to submodule path output", PARSE_OPT_HIDDEN },
 +                  N_("allow updating of HEAD ref")),
 +      OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
 +      OPT_STRING(0, "depth", &depth, N_("depth"),
 +                 N_("deepen history of shallow clone")),
 +      { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
 +                 N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
        { OPTION_STRING, 0, "recurse-submodules-default",
                   &recurse_submodules_default, NULL,
 -                 "default mode for recursion", PARSE_OPT_HIDDEN },
 +                 N_("default mode for recursion"), PARSE_OPT_HIDDEN },
        OPT_END()
  };
  
@@@ -240,7 -240,6 +240,7 @@@ static int s_update_ref(const char *act
  
  static int update_local_ref(struct ref *ref,
                            const char *remote,
 +                          const struct ref *remote_ref,
                            struct strbuf *display)
  {
        struct commit *current = NULL, *updated;
                const char *msg;
                const char *what;
                int r;
 -              if (!strncmp(ref->name, "refs/tags/", 10)) {
 +              /*
 +               * Nicely describe the new ref we're fetching.
 +               * Base this on the remote's ref name, as it's
 +               * more likely to follow a standard layout.
 +               */
 +              const char *name = remote_ref ? remote_ref->name : "";
 +              if (!prefixcmp(name, "refs/tags/")) {
                        msg = "storing tag";
                        what = _("[new tag]");
 -              }
 -              else {
 +              } else if (!prefixcmp(name, "refs/heads/")) {
                        msg = "storing head";
                        what = _("[new branch]");
 -                      if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
 -                          (recurse_submodules != RECURSE_SUBMODULES_ON))
 -                              check_for_new_submodule_commits(ref->new_sha1);
 +              } else {
 +                      msg = "storing ref";
 +                      what = _("[new ref]");
                }
  
 +              if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
 +                  (recurse_submodules != RECURSE_SUBMODULES_ON))
 +                      check_for_new_submodule_commits(ref->new_sha1);
                r = s_update_ref(msg, ref, 0);
                strbuf_addf(display, "%c %-*s %-*s -> %s%s",
                            r ? '!' : '*',
                return r;
        }
  
-       if (in_merge_bases(current, &updated, 1)) {
+       if (in_merge_bases(current, updated)) {
                char quickref[83];
                int r;
                strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
@@@ -475,7 -466,7 +475,7 @@@ static int store_updated_refs(const cha
  
                        strbuf_reset(&note);
                        if (ref) {
 -                              rc |= update_local_ref(ref, what, &note);
 +                              rc |= update_local_ref(ref, what, rm, &note);
                                free(ref);
                        } else
                                strbuf_addf(&note, "* %-*s %-*s -> FETCH_HEAD",
@@@ -546,8 -537,8 +546,8 @@@ static int prune_refs(struct refspec *r
        int result = 0;
        struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
        const char *dangling_msg = dry_run
 -              ? _("   (%s will become dangling)\n")
 -              : _("   (%s has become dangling)\n");
 +              ? _("   (%s will become dangling)")
 +              : _("   (%s has become dangling)");
  
        for (ref = stale_refs; ref; ref = ref->next) {
                if (!dry_run)
@@@ -594,7 -585,7 +594,7 @@@ static void find_non_local_tags(struct 
  
        for_each_ref(add_existing, &existing_refs);
        for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) {
 -              if (prefixcmp(ref->name, "refs/tags"))
 +              if (prefixcmp(ref->name, "refs/tags/"))
                        continue;
  
                /*
diff --combined builtin/merge-base.c
index 2f223a66462c5e6014c8608cd3c50ef243e8668a,0568b07e1d010c0a39fe5a9868ac87c0e0f1a593..1bc79910481e6ee04b470620da5609c1c6fbcac4
@@@ -23,9 -23,10 +23,10 @@@ static int show_merge_base(struct commi
  }
  
  static const char * const merge_base_usage[] = {
 -      "git merge-base [-a|--all] <commit> <commit>...",
 -      "git merge-base [-a|--all] --octopus <commit>...",
 -      "git merge-base --independent <commit>...",
 -      "git merge-base --is-ancestor <commit> <commit>",
 +      N_("git merge-base [-a|--all] <commit> <commit>..."),
 +      N_("git merge-base [-a|--all] --octopus <commit>..."),
 +      N_("git merge-base --independent <commit>..."),
++      N_("git merge-base --is-ancestor <commit> <commit>"),
        NULL
  };
  
@@@ -70,6 -71,20 +71,20 @@@ static int handle_octopus(int count, co
        return 0;
  }
  
+ static int handle_is_ancestor(int argc, const char **argv)
+ {
+       struct commit *one, *two;
+       if (argc != 2)
+               die("--is-ancestor takes exactly two commits");
+       one = get_commit_reference(argv[0]);
+       two = get_commit_reference(argv[1]);
+       if (in_merge_bases(one, two))
+               return 0;
+       else
+               return 1;
+ }
  int cmd_merge_base(int argc, const char **argv, const char *prefix)
  {
        struct commit **rev;
        int show_all = 0;
        int octopus = 0;
        int reduce = 0;
+       int is_ancestor = 0;
  
        struct option options[] = {
 -              OPT_BOOLEAN('a', "all", &show_all, "output all common ancestors"),
 -              OPT_BOOLEAN(0, "octopus", &octopus, "find ancestors for a single n-way merge"),
 -              OPT_BOOLEAN(0, "independent", &reduce, "list revs not reachable from others"),
 +              OPT_BOOLEAN('a', "all", &show_all, N_("output all common ancestors")),
 +              OPT_BOOLEAN(0, "octopus", &octopus, N_("find ancestors for a single n-way merge")),
 +              OPT_BOOLEAN(0, "independent", &reduce, N_("list revs not reachable from others")),
+               OPT_BOOLEAN(0, "is-ancestor", &is_ancestor,
 -                          "is the first one ancestor of the other?"),
++                          N_("is the first one ancestor of the other?")),
                OPT_END()
        };
  
        argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
        if (!octopus && !reduce && argc < 2)
                usage_with_options(merge_base_usage, options);
+       if (is_ancestor && (show_all | octopus | reduce))
+               die("--is-ancestor cannot be used with other options");
+       if (is_ancestor)
+               return handle_is_ancestor(argc, argv);
        if (reduce && (show_all || octopus))
                die("--independent cannot be used with other options");
  
diff --combined builtin/receive-pack.c
index 2cb854feb4b3a701201ef683c6644aaa852d50b5,58f3a37a39afbe3b7737fa3a0d9b90f57cec2b75..9145f1a5950fcd363a5e65e817df5c61bd769c01
@@@ -12,7 -12,6 +12,7 @@@
  #include "string-list.h"
  #include "sha1-array.h"
  #include "connected.h"
 +#include "version.h"
  
  static const char receive_pack_usage[] = "git receive-pack <git-dir>";
  
@@@ -122,11 -121,10 +122,11 @@@ static void show_ref(const char *path, 
        if (sent_capabilities)
                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
        else
 -              packet_write(1, "%s %s%c%s%s\n",
 +              packet_write(1, "%s %s%c%s%s agent=%s\n",
                             sha1_to_hex(sha1), path, 0,
                             " report-status delete-refs side-band-64k quiet",
 -                           prefer_ofs_delta ? " ofs-delta" : "");
 +                           prefer_ofs_delta ? " ofs-delta" : "",
 +                           git_user_agent_sanitized());
        sent_capabilities = 1;
  }
  
@@@ -480,7 -478,6 +480,6 @@@ static const char *update(struct comman
            !prefixcmp(name, "refs/heads/")) {
                struct object *old_object, *new_object;
                struct commit *old_commit, *new_commit;
-               struct commit_list *bases, *ent;
  
                old_object = parse_object(old_sha1);
                new_object = parse_object(new_sha1);
                }
                old_commit = (struct commit *)old_object;
                new_commit = (struct commit *)new_object;
-               bases = get_merge_bases(old_commit, new_commit, 1);
-               for (ent = bases; ent; ent = ent->next)
-                       if (!hashcmp(old_sha1, ent->item->object.sha1))
-                               break;
-               free_commit_list(bases);
-               if (!ent) {
+               if (!in_merge_bases(old_commit, new_commit)) {
                        rp_error("denying non-fast-forward %s"
                                 " (you should pull first)", name);
                        return "non-fast-forward";
@@@ -979,8 -971,7 +973,8 @@@ int cmd_receive_pack(int argc, const ch
                        const char *argv_gc_auto[] = {
                                "gc", "--auto", "--quiet", NULL,
                        };
 -                      run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
 +                      int opt = RUN_GIT_CMD | RUN_COMMAND_STDOUT_TO_STDERR;
 +                      run_command_v_opt(argv_gc_auto, opt);
                }
                if (auto_update_server_info)
                        update_server_info(0);
diff --combined commit.c
index 87268682f98f0cd0f18221b3647ad30dbcbc560e,69af37014fd07d30408c959f40357493ca21e7d4..0ea441d13b1430231f30d9524aed88b9719290b6
+++ b/commit.c
@@@ -7,7 -7,6 +7,7 @@@
  #include "revision.h"
  #include "notes.h"
  #include "gpg-interface.h"
 +#include "mergesort.h"
  
  int save_commit_buffer = 1;
  
@@@ -68,7 -67,7 +68,7 @@@ struct commit *lookup_commit_reference_
        unsigned char sha1[20];
        struct commit *commit;
  
 -      if (get_sha1(name, sha1))
 +      if (get_sha1_committish(name, sha1))
                return NULL;
        commit = lookup_commit_reference(sha1);
        if (!commit || parse_commit(commit))
@@@ -391,31 -390,15 +391,31 @@@ struct commit_list * commit_list_insert
        return commit_list_insert(item, pp);
  }
  
 +static int commit_list_compare_by_date(const void *a, const void *b)
 +{
 +      unsigned long a_date = ((const struct commit_list *)a)->item->date;
 +      unsigned long b_date = ((const struct commit_list *)b)->item->date;
 +      if (a_date < b_date)
 +              return 1;
 +      if (a_date > b_date)
 +              return -1;
 +      return 0;
 +}
 +
 +static void *commit_list_get_next(const void *a)
 +{
 +      return ((const struct commit_list *)a)->next;
 +}
 +
 +static void commit_list_set_next(void *a, void *next)
 +{
 +      ((struct commit_list *)a)->next = next;
 +}
  
  void commit_list_sort_by_date(struct commit_list **list)
  {
 -      struct commit_list *ret = NULL;
 -      while (*list) {
 -              commit_list_insert_by_date((*list)->item, &ret);
 -              *list = (*list)->next;
 -      }
 -      *list = ret;
 +      *list = llist_mergesort(*list, commit_list_get_next, commit_list_set_next,
 +                              commit_list_compare_by_date);
  }
  
  struct commit *pop_most_recent_commit(struct commit_list **list,
        return ret;
  }
  
 -void clear_commit_marks(struct commit *commit, unsigned int mark)
 +static void clear_commit_marks_1(struct commit_list **plist,
 +                               struct commit *commit, unsigned int mark)
  {
        while (commit) {
                struct commit_list *parents;
                        return;
  
                while ((parents = parents->next))
 -                      clear_commit_marks(parents->item, mark);
 +                      commit_list_insert(parents->item, plist);
  
                commit = commit->parents->item;
        }
  }
  
 +void clear_commit_marks(struct commit *commit, unsigned int mark)
 +{
 +      struct commit_list *list = NULL;
 +      commit_list_insert(commit, &list);
 +      while (list)
 +              clear_commit_marks_1(&list, pop_commit(&list), mark);
 +}
 +
  void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark)
  {
        struct object *object;
@@@ -607,28 -581,12 +607,12 @@@ static struct commit *interesting(struc
        return NULL;
  }
  
- static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
+ static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
  {
        struct commit_list *list = NULL;
        struct commit_list *result = NULL;
        int i;
  
-       for (i = 0; i < n; i++) {
-               if (one == twos[i])
-                       /*
-                        * We do not mark this even with RESULT so we do not
-                        * have to clean it up.
-                        */
-                       return commit_list_insert(one, &result);
-       }
-       if (parse_commit(one))
-               return NULL;
-       for (i = 0; i < n; i++) {
-               if (parse_commit(twos[i]))
-                       return NULL;
-       }
        one->object.flags |= PARENT1;
        commit_list_insert_by_date(one, &list);
        for (i = 0; i < n; i++) {
                }
        }
  
-       /* Clean up the result to remove stale ones */
        free_commit_list(list);
-       list = result; result = NULL;
+       return result;
+ }
+ static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
+ {
+       struct commit_list *list = NULL;
+       struct commit_list *result = NULL;
+       int i;
+       for (i = 0; i < n; i++) {
+               if (one == twos[i])
+                       /*
+                        * We do not mark this even with RESULT so we do not
+                        * have to clean it up.
+                        */
+                       return commit_list_insert(one, &result);
+       }
+       if (parse_commit(one))
+               return NULL;
+       for (i = 0; i < n; i++) {
+               if (parse_commit(twos[i]))
+                       return NULL;
+       }
+       list = paint_down_to_common(one, n, twos);
        while (list) {
                struct commit_list *next = list->next;
                if (!(list->item->object.flags & STALE))
@@@ -709,6 -692,60 +718,60 @@@ struct commit_list *get_octopus_merge_b
        return ret;
  }
  
+ static int remove_redundant(struct commit **array, int cnt)
+ {
+       /*
+        * Some commit in the array may be an ancestor of
+        * another commit.  Move such commit to the end of
+        * the array, and return the number of commits that
+        * are independent from each other.
+        */
+       struct commit **work;
+       unsigned char *redundant;
+       int *filled_index;
+       int i, j, filled;
+       work = xcalloc(cnt, sizeof(*work));
+       redundant = xcalloc(cnt, 1);
+       filled_index = xmalloc(sizeof(*filled_index) * (cnt - 1));
+       for (i = 0; i < cnt; i++) {
+               struct commit_list *common;
+               if (redundant[i])
+                       continue;
+               for (j = filled = 0; j < cnt; j++) {
+                       if (i == j || redundant[j])
+                               continue;
+                       filled_index[filled] = j;
+                       work[filled++] = array[j];
+               }
+               common = paint_down_to_common(array[i], filled, work);
+               if (array[i]->object.flags & PARENT2)
+                       redundant[i] = 1;
+               for (j = 0; j < filled; j++)
+                       if (work[j]->object.flags & PARENT1)
+                               redundant[filled_index[j]] = 1;
+               clear_commit_marks(array[i], all_flags);
+               for (j = 0; j < filled; j++)
+                       clear_commit_marks(work[j], all_flags);
+               free_commit_list(common);
+       }
+       /* Now collect the result */
+       memcpy(work, array, sizeof(*array) * cnt);
+       for (i = filled = 0; i < cnt; i++)
+               if (!redundant[i])
+                       array[filled++] = work[i];
+       for (j = filled, i = 0; i < cnt; i++)
+               if (redundant[i])
+                       array[j++] = work[i];
+       free(work);
+       free(redundant);
+       free(filled_index);
+       return filled;
+ }
  struct commit_list *get_merge_bases_many(struct commit *one,
                                         int n,
                                         struct commit **twos,
        struct commit_list *list;
        struct commit **rslt;
        struct commit_list *result;
-       int cnt, i, j;
+       int cnt, i;
  
        result = merge_bases_many(one, n, twos);
        for (i = 0; i < n; i++) {
        clear_commit_marks(one, all_flags);
        for (i = 0; i < n; i++)
                clear_commit_marks(twos[i], all_flags);
-       for (i = 0; i < cnt - 1; i++) {
-               for (j = i+1; j < cnt; j++) {
-                       if (!rslt[i] || !rslt[j])
-                               continue;
-                       result = merge_bases_many(rslt[i], 1, &rslt[j]);
-                       clear_commit_marks(rslt[i], all_flags);
-                       clear_commit_marks(rslt[j], all_flags);
-                       for (list = result; list; list = list->next) {
-                               if (rslt[i] == list->item)
-                                       rslt[i] = NULL;
-                               if (rslt[j] == list->item)
-                                       rslt[j] = NULL;
-                       }
-               }
-       }
  
-       /* Surviving ones in rslt[] are the independent results */
+       cnt = remove_redundant(rslt, cnt);
        result = NULL;
-       for (i = 0; i < cnt; i++) {
-               if (rslt[i])
-                       commit_list_insert_by_date(rslt[i], &result);
-       }
+       for (i = 0; i < cnt; i++)
+               commit_list_insert_by_date(rslt[i], &result);
        free(rslt);
        return result;
  }
@@@ -780,6 -800,9 +826,9 @@@ struct commit_list *get_merge_bases(str
        return get_merge_bases_many(one, 1, &two, cleanup);
  }
  
+ /*
+  * Is "commit" a decendant of one of the elements on the "with_commit" list?
+  */
  int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
  {
        if (!with_commit)
  
                other = with_commit->item;
                with_commit = with_commit->next;
-               if (in_merge_bases(other, &commit, 1))
+               if (in_merge_bases(other, commit))
                        return 1;
        }
        return 0;
  }
  
- int in_merge_bases(struct commit *commit, struct commit **reference, int num)
+ /*
+  * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
+  */
+ int in_merge_bases(struct commit *commit, struct commit *reference)
  {
-       struct commit_list *bases, *b;
+       struct commit_list *bases;
        int ret = 0;
  
-       if (num == 1)
-               bases = get_merge_bases(commit, *reference, 1);
-       else
-               die("not yet");
-       for (b = bases; b; b = b->next) {
-               if (!hashcmp(commit->object.sha1, b->item->object.sha1)) {
-                       ret = 1;
-                       break;
-               }
-       }
+       if (parse_commit(commit) || parse_commit(reference))
+               return ret;
  
+       bases = paint_down_to_common(commit, 1, &reference);
+       if (commit->object.flags & PARENT2)
+               ret = 1;
+       clear_commit_marks(commit, all_flags);
+       clear_commit_marks(reference, all_flags);
        free_commit_list(bases);
        return ret;
  }
@@@ -819,51 -842,31 +868,31 @@@ struct commit_list *reduce_heads(struc
  {
        struct commit_list *p;
        struct commit_list *result = NULL, **tail = &result;
-       struct commit **other;
-       size_t num_head, num_other;
+       struct commit **array;
+       int num_head, i;
  
        if (!heads)
                return NULL;
  
-       /* Avoid unnecessary reallocations */
-       for (p = heads, num_head = 0; p; p = p->next)
-               num_head++;
-       other = xcalloc(sizeof(*other), num_head);
-       /* For each commit, see if it can be reached by others */
-       for (p = heads; p; p = p->next) {
-               struct commit_list *q, *base;
-               /* Do we already have this in the result? */
-               for (q = result; q; q = q->next)
-                       if (p->item == q->item)
-                               break;
-               if (q)
+       /* Uniquify */
+       for (p = heads; p; p = p->next)
+               p->item->object.flags &= ~STALE;
+       for (p = heads, num_head = 0; p; p = p->next) {
+               if (p->item->object.flags & STALE)
                        continue;
-               num_other = 0;
-               for (q = heads; q; q = q->next) {
-                       if (p->item == q->item)
-                               continue;
-                       other[num_other++] = q->item;
+               p->item->object.flags |= STALE;
+               num_head++;
+       }
+       array = xcalloc(sizeof(*array), num_head);
+       for (p = heads, i = 0; p; p = p->next) {
+               if (p->item->object.flags & STALE) {
+                       array[i++] = p->item;
+                       p->item->object.flags &= ~STALE;
                }
-               if (num_other)
-                       base = get_merge_bases_many(p->item, num_other, other, 1);
-               else
-                       base = NULL;
-               /*
-                * If p->item does not have anything common with other
-                * commits, there won't be any merge base.  If it is
-                * reachable from some of the others, p->item will be
-                * the merge base.  If its history is connected with
-                * others, but p->item is not reachable by others, we
-                * will get something other than p->item back.
-                */
-               if (!base || (base->item != p->item))
-                       tail = &(commit_list_insert(p->item, tail)->next);
-               free_commit_list(base);
        }
-       free(other);
+       num_head = remove_redundant(array, num_head);
+       for (i = 0; i < num_head; i++)
+               tail = &commit_list_insert(array[i], tail)->next;
        return result;
  }
  
@@@ -1112,92 -1115,8 +1141,92 @@@ int commit_tree(const struct strbuf *ms
        return result;
  }
  
 +static int find_invalid_utf8(const char *buf, int len)
 +{
 +      int offset = 0;
 +
 +      while (len) {
 +              unsigned char c = *buf++;
 +              int bytes, bad_offset;
 +
 +              len--;
 +              offset++;
 +
 +              /* Simple US-ASCII? No worries. */
 +              if (c < 0x80)
 +                      continue;
 +
 +              bad_offset = offset-1;
 +
 +              /*
 +               * Count how many more high bits set: that's how
 +               * many more bytes this sequence should have.
 +               */
 +              bytes = 0;
 +              while (c & 0x40) {
 +                      c <<= 1;
 +                      bytes++;
 +              }
 +
 +              /* Must be between 1 and 5 more bytes */
 +              if (bytes < 1 || bytes > 5)
 +                      return bad_offset;
 +
 +              /* Do we *have* that many bytes? */
 +              if (len < bytes)
 +                      return bad_offset;
 +
 +              offset += bytes;
 +              len -= bytes;
 +
 +              /* And verify that they are good continuation bytes */
 +              do {
 +                      if ((*buf++ & 0xc0) != 0x80)
 +                              return bad_offset;
 +              } while (--bytes);
 +
 +              /* We could/should check the value and length here too */
 +      }
 +      return -1;
 +}
 +
 +/*
 + * This verifies that the buffer is in proper utf8 format.
 + *
 + * If it isn't, it assumes any non-utf8 characters are Latin1,
 + * and does the conversion.
 + *
 + * Fixme: we should probably also disallow overlong forms and
 + * invalid characters. But we don't do that currently.
 + */
 +static int verify_utf8(struct strbuf *buf)
 +{
 +      int ok = 1;
 +      long pos = 0;
 +
 +      for (;;) {
 +              int bad;
 +              unsigned char c;
 +              unsigned char replace[2];
 +
 +              bad = find_invalid_utf8(buf->buf + pos, buf->len - pos);
 +              if (bad < 0)
 +                      return ok;
 +              pos += bad;
 +              ok = 0;
 +              c = buf->buf[pos];
 +              strbuf_remove(buf, pos, 1);
 +
 +              /* We know 'c' must be in the range 128-255 */
 +              replace[0] = 0xc0 + (c >> 6);
 +              replace[1] = 0x80 + (c & 0x3f);
 +              strbuf_insert(buf, pos, replace, 2);
 +              pos += 2;
 +      }
 +}
 +
  static const char commit_utf8_warn[] =
 -"Warning: commit message does not conform to UTF-8.\n"
 +"Warning: commit message did not conform to UTF-8.\n"
  "You may want to amend it after fixing the message, or set the config\n"
  "variable i18n.commitencoding to the encoding your project uses.\n";
  
@@@ -1238,9 -1157,9 +1267,9 @@@ int commit_tree_extended(const struct s
  
        /* Person/date information */
        if (!author)
 -              author = git_author_info(IDENT_ERROR_ON_NO_NAME);
 +              author = git_author_info(IDENT_STRICT);
        strbuf_addf(&buffer, "author %s\n", author);
 -      strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME));
 +      strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_STRICT));
        if (!encoding_is_utf8)
                strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
  
        strbuf_addbuf(&buffer, msg);
  
        /* And check the encoding */
 -      if (encoding_is_utf8 && !is_utf8(buffer.buf))
 +      if (encoding_is_utf8 && !verify_utf8(&buffer))
                fprintf(stderr, commit_utf8_warn);
  
        if (sign_commit && do_sign_commit(&buffer, sign_commit))
@@@ -1283,30 -1202,3 +1312,30 @@@ struct commit *get_merge_parent(const c
        }
        return commit;
  }
 +
 +/*
 + * Append a commit to the end of the commit_list.
 + *
 + * next starts by pointing to the variable that holds the head of an
 + * empty commit_list, and is updated to point to the "next" field of
 + * the last item on the list as new commits are appended.
 + *
 + * Usage example:
 + *
 + *     struct commit_list *list;
 + *     struct commit_list **next = &list;
 + *
 + *     next = commit_list_append(c1, next);
 + *     next = commit_list_append(c2, next);
 + *     assert(commit_list_count(list) == 2);
 + *     return list;
 + */
 +struct commit_list **commit_list_append(struct commit *commit,
 +                                      struct commit_list **next)
 +{
 +      struct commit_list *new = xmalloc(sizeof(struct commit_list));
 +      new->item = commit;
 +      *next = new;
 +      new->next = NULL;
 +      return &new->next;
 +}
diff --combined commit.h
index d617fa3f28d9fecf0bbf8e87c373f8701c286227,5bb8a884bd892489745af2308f6c9e1fe256d450..6edce876739672b4fde2b6970e7ff55b8a921743
+++ b/commit.h
@@@ -53,8 -53,6 +53,8 @@@ int find_commit_subject(const char *com
  
  struct commit_list *commit_list_insert(struct commit *item,
                                        struct commit_list **list);
 +struct commit_list **commit_list_append(struct commit *commit,
 +                                      struct commit_list **next);
  unsigned commit_list_count(const struct commit_list *l);
  struct commit_list *commit_list_insert_by_date(struct commit *item,
                                    struct commit_list **list);
@@@ -84,7 -82,6 +84,7 @@@ struct pretty_print_context 
        const char *after_subject;
        int preserve_subject;
        enum date_mode date_mode;
 +      unsigned date_mode_explicit:1;
        int need_8bit_cte;
        int show_notes;
        struct reflog_walk_info *reflog_info;
@@@ -171,7 -168,7 +171,7 @@@ extern struct commit_list *get_shallow_
                int depth, int shallow_flag, int not_shallow_flag);
  
  int is_descendant_of(struct commit *, struct commit_list *);
- int in_merge_bases(struct commit *, struct commit **, int);
+ int in_merge_bases(struct commit *, struct commit *);
  
  extern int interactive_add(int argc, const char **argv, const char *prefix, int patch);
  extern int run_add_interactive(const char *revision, const char *patch_mode,
index 0d54aa7061e780dd0000b8c2a48e266ad5b8ce53,3038c390977092bcf105d8c237b965e618118662..8bc8c7533a8678e2a43d3ddd49bc9aa8d670897d
@@@ -96,7 -96,7 +96,7 @@@ static int update_local_ref(const char 
        strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
        strcpy(newh, find_unique_abbrev(sha1_new, DEFAULT_ABBREV));
  
-       if (in_merge_bases(current, &updated, 1)) {
+       if (in_merge_bases(current, updated)) {
                fprintf(stderr, "* %s: fast-forward to %s\n",
                        name, note);
                fprintf(stderr, "  old..new: %s..%s\n", oldh, newh);
@@@ -518,7 -518,7 +518,7 @@@ int cmd_fetch__tool(int argc, const cha
                filename = git_path("FETCH_HEAD");
                fp = fopen(filename, "a");
                if (!fp)
 -                      return error("cannot open %s: %s\n", filename, strerror(errno));
 +                      return error("cannot open %s: %s", filename, strerror(errno));
                result = append_fetch_head(fp, argv[2], argv[3],
                                           argv[4], argv[5],
                                           argv[6], !!argv[7][0],
                filename = git_path("FETCH_HEAD");
                fp = fopen(filename, "a");
                if (!fp)
 -                      return error("cannot open %s: %s\n", filename, strerror(errno));
 +                      return error("cannot open %s: %s", filename, strerror(errno));
                result = fetch_native_store(fp, argv[2], argv[3], argv[4],
                                            verbose, force);
                fclose(fp);
diff --combined fast-import.c
index eed97c8fa9f3e1624f69443e28f76d995e589b34,e6f61fc7cb404248c7d742346573874b3ec22226..c2a814ec660862937e495c0a7efb6375dc7718ac
@@@ -1691,7 -1691,7 +1691,7 @@@ static int update_branch(struct branch 
                        return error("Branch %s is missing commits.", b->name);
                }
  
-               if (!in_merge_bases(old_cmit, &new_cmit, 1)) {
+               if (!in_merge_bases(old_cmit, new_cmit)) {
                        unlock_ref(lock);
                        warning("Not updating %s"
                                " (new tip %s does not contain %s)",
@@@ -2207,59 -2207,6 +2207,59 @@@ static uintmax_t change_note_fanout(str
        return do_change_note_fanout(root, root, hex_sha1, 0, path, 0, fanout);
  }
  
 +/*
 + * Given a pointer into a string, parse a mark reference:
 + *
 + *   idnum ::= ':' bigint;
 + *
 + * Return the first character after the value in *endptr.
 + *
 + * Complain if the following character is not what is expected,
 + * either a space or end of the string.
 + */
 +static uintmax_t parse_mark_ref(const char *p, char **endptr)
 +{
 +      uintmax_t mark;
 +
 +      assert(*p == ':');
 +      p++;
 +      mark = strtoumax(p, endptr, 10);
 +      if (*endptr == p)
 +              die("No value after ':' in mark: %s", command_buf.buf);
 +      return mark;
 +}
 +
 +/*
 + * Parse the mark reference, and complain if this is not the end of
 + * the string.
 + */
 +static uintmax_t parse_mark_ref_eol(const char *p)
 +{
 +      char *end;
 +      uintmax_t mark;
 +
 +      mark = parse_mark_ref(p, &end);
 +      if (*end != '\0')
 +              die("Garbage after mark: %s", command_buf.buf);
 +      return mark;
 +}
 +
 +/*
 + * Parse the mark reference, demanding a trailing space.  Return a
 + * pointer to the space.
 + */
 +static uintmax_t parse_mark_ref_space(const char **p)
 +{
 +      uintmax_t mark;
 +      char *end;
 +
 +      mark = parse_mark_ref(*p, &end);
 +      if (*end != ' ')
 +              die("Missing space after mark: %s", command_buf.buf);
 +      *p = end;
 +      return mark;
 +}
 +
  static void file_change_m(struct branch *b)
  {
        const char *p = command_buf.buf + 2;
        }
  
        if (*p == ':') {
 -              char *x;
 -              oe = find_mark(strtoumax(p + 1, &x, 10));
 +              oe = find_mark(parse_mark_ref_space(&p));
                hashcpy(sha1, oe->idx.sha1);
 -              p = x;
 -      } else if (!prefixcmp(p, "inline")) {
 +      } else if (!prefixcmp(p, "inline ")) {
                inline_data = 1;
 -              p += 6;
 +              p += strlen("inline");  /* advance to space */
        } else {
                if (get_sha1_hex(p, sha1))
 -                      die("Invalid SHA1: %s", command_buf.buf);
 +                      die("Invalid dataref: %s", command_buf.buf);
                oe = find_object(sha1);
                p += 40;
 +              if (*p != ' ')
 +                      die("Missing space after SHA1: %s", command_buf.buf);
        }
 -      if (*p++ != ' ')
 -              die("Missing space after SHA1: %s", command_buf.buf);
 +      assert(*p == ' ');
 +      p++;  /* skip space */
  
        strbuf_reset(&uq);
        if (!unquote_c_style(&uq, p, &endp)) {
@@@ -2460,21 -2407,21 +2460,21 @@@ static void note_change_n(struct branc
        /* Now parse the notemodify command. */
        /* <dataref> or 'inline' */
        if (*p == ':') {
 -              char *x;
 -              oe = find_mark(strtoumax(p + 1, &x, 10));
 +              oe = find_mark(parse_mark_ref_space(&p));
                hashcpy(sha1, oe->idx.sha1);
 -              p = x;
 -      } else if (!prefixcmp(p, "inline")) {
 +      } else if (!prefixcmp(p, "inline ")) {
                inline_data = 1;
 -              p += 6;
 +              p += strlen("inline");  /* advance to space */
        } else {
                if (get_sha1_hex(p, sha1))
 -                      die("Invalid SHA1: %s", command_buf.buf);
 +                      die("Invalid dataref: %s", command_buf.buf);
                oe = find_object(sha1);
                p += 40;
 +              if (*p != ' ')
 +                      die("Missing space after SHA1: %s", command_buf.buf);
        }
 -      if (*p++ != ' ')
 -              die("Missing space after SHA1: %s", command_buf.buf);
 +      assert(*p == ' ');
 +      p++;  /* skip space */
  
        /* <committish> */
        s = lookup_branch(p);
                        die("Can't add a note on empty branch.");
                hashcpy(commit_sha1, s->sha1);
        } else if (*p == ':') {
 -              uintmax_t commit_mark = strtoumax(p + 1, NULL, 10);
 +              uintmax_t commit_mark = parse_mark_ref_eol(p);
                struct object_entry *commit_oe = find_mark(commit_mark);
                if (commit_oe->type != OBJ_COMMIT)
                        die("Mark :%" PRIuMAX " not a commit", commit_mark);
@@@ -2590,7 -2537,7 +2590,7 @@@ static int parse_from(struct branch *b
                hashcpy(b->branch_tree.versions[0].sha1, t);
                hashcpy(b->branch_tree.versions[1].sha1, t);
        } else if (*from == ':') {
 -              uintmax_t idnum = strtoumax(from + 1, NULL, 10);
 +              uintmax_t idnum = parse_mark_ref_eol(from);
                struct object_entry *oe = find_mark(idnum);
                if (oe->type != OBJ_COMMIT)
                        die("Mark :%" PRIuMAX " not a commit", idnum);
@@@ -2625,7 -2572,7 +2625,7 @@@ static struct hash_list *parse_merge(un
                if (s)
                        hashcpy(n->sha1, s->sha1);
                else if (*from == ':') {
 -                      uintmax_t idnum = strtoumax(from + 1, NULL, 10);
 +                      uintmax_t idnum = parse_mark_ref_eol(from);
                        struct object_entry *oe = find_mark(idnum);
                        if (oe->type != OBJ_COMMIT)
                                die("Mark :%" PRIuMAX " not a commit", idnum);
@@@ -2788,7 -2735,7 +2788,7 @@@ static void parse_new_tag(void
                type = OBJ_COMMIT;
        } else if (*from == ':') {
                struct object_entry *oe;
 -              from_mark = strtoumax(from + 1, NULL, 10);
 +              from_mark = parse_mark_ref_eol(from);
                oe = find_mark(from_mark);
                type = oe->type;
                hashcpy(sha1, oe->idx.sha1);
@@@ -2920,13 -2867,18 +2920,13 @@@ static void parse_cat_blob(void
        /* cat-blob SP <object> LF */
        p = command_buf.buf + strlen("cat-blob ");
        if (*p == ':') {
 -              char *x;
 -              oe = find_mark(strtoumax(p + 1, &x, 10));
 -              if (x == p + 1)
 -                      die("Invalid mark: %s", command_buf.buf);
 +              oe = find_mark(parse_mark_ref_eol(p));
                if (!oe)
                        die("Unknown mark: %s", command_buf.buf);
 -              if (*x)
 -                      die("Garbage after mark: %s", command_buf.buf);
                hashcpy(sha1, oe->idx.sha1);
        } else {
                if (get_sha1_hex(p, sha1))
 -                      die("Invalid SHA1: %s", command_buf.buf);
 +                      die("Invalid dataref: %s", command_buf.buf);
                if (p[40])
                        die("Garbage after SHA1: %s", command_buf.buf);
                oe = find_object(sha1);
@@@ -2992,13 -2944,17 +2992,13 @@@ static struct object_entry *parse_treei
        struct object_entry *e;
  
        if (**p == ':') {       /* <mark> */
 -              char *endptr;
 -              e = find_mark(strtoumax(*p + 1, &endptr, 10));
 -              if (endptr == *p + 1)
 -                      die("Invalid mark: %s", command_buf.buf);
 +              e = find_mark(parse_mark_ref_space(p));
                if (!e)
                        die("Unknown mark: %s", command_buf.buf);
 -              *p = endptr;
                hashcpy(sha1, e->idx.sha1);
        } else {        /* <sha1> */
                if (get_sha1_hex(*p, sha1))
 -                      die("Invalid SHA1: %s", command_buf.buf);
 +                      die("Invalid dataref: %s", command_buf.buf);
                e = find_object(sha1);
                *p += 40;
        }
diff --combined http-push.c
index a832ca77a31245e8ef9c71adcc0d7110fcda1e5c,555c056d64aa2a87f5d9ec305c43ef65bc896176..8701c1215d21cd0413c1d69be91b309984cf6b1f
@@@ -904,7 -904,7 +904,7 @@@ static struct remote_lock *lock_remote(
                ep = strchr(ep + 1, '/');
        }
  
 -      escaped = xml_entities(git_default_email);
 +      escaped = xml_entities(ident_default_email());
        strbuf_addf(&out_buffer.buf, LOCK_REQUEST, escaped);
        free(escaped);
  
@@@ -1108,7 -1108,7 +1108,7 @@@ static void handle_remote_ls_ctx(struc
                                if (repo->path)
                                        url = repo->path;
                                if (strncmp(path, url, repo->path_len))
 -                                      error("Parsed path '%s' does not match url: '%s'\n",
 +                                      error("Parsed path '%s' does not match url: '%s'",
                                              path, url);
                                else {
                                        path += repo->path_len;
@@@ -1610,9 -1610,8 +1610,8 @@@ static int verify_merge_base(unsigned c
  {
        struct commit *head = lookup_commit_or_die(head_sha1, "HEAD");
        struct commit *branch = lookup_commit_or_die(remote->old_sha1, remote->name);
-       struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
  
-       return (merge_bases && !merge_bases->next && merge_bases->item == branch);
+       return in_merge_bases(branch, head);
  }
  
  static int delete_remote_branch(const char *pattern, int force)
                run_active_slot(slot);
                free(url);
                if (results.curl_result != CURLE_OK)
 -                      return error("DELETE request failed (%d/%ld)\n",
 +                      return error("DELETE request failed (%d/%ld)",
                                     results.curl_result, results.http_code);
        } else {
                free(url);
diff --combined submodule.c
index 19dc6a6c0d5cf7d9a4c80c61e160290b4462665d,8fc974d1cbb8901f6653335f046d33c944d48d2c..d133796c9ca6ef1018b23d7b0379d7ed71e846ee
@@@ -63,9 -63,6 +63,9 @@@ static int add_submodule_odb(const cha
        alt_odb->name[40] = '\0';
        alt_odb->name[41] = '\0';
        alt_odb_list = alt_odb;
 +
 +      /* add possible alternates from the submodule */
 +      read_info_alternates(objects_directory.buf, 0);
        prepare_alt_odb();
  done:
        strbuf_release(&objects_directory);
@@@ -360,19 -357,21 +360,19 @@@ static void collect_submodules_from_dif
                                         void *data)
  {
        int i;
 -      int *needs_pushing = data;
 +      struct string_list *needs_pushing = data;
  
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
                if (!S_ISGITLINK(p->two->mode))
                        continue;
 -              if (submodule_needs_pushing(p->two->path, p->two->sha1)) {
 -                      *needs_pushing = 1;
 -                      break;
 -              }
 +              if (submodule_needs_pushing(p->two->path, p->two->sha1))
 +                      string_list_insert(needs_pushing, p->two->path);
        }
  }
  
 -
 -static void commit_need_pushing(struct commit *commit, int *needs_pushing)
 +static void find_unpushed_submodule_commits(struct commit *commit,
 +              struct string_list *needs_pushing)
  {
        struct rev_info rev;
  
        diff_tree_combined_merge(commit, 1, &rev);
  }
  
 -int check_submodule_needs_pushing(unsigned char new_sha1[20], const char *remotes_name)
 +int find_unpushed_submodules(unsigned char new_sha1[20],
 +              const char *remotes_name, struct string_list *needs_pushing)
  {
        struct rev_info rev;
        struct commit *commit;
        const char *argv[] = {NULL, NULL, "--not", "NULL", NULL};
        int argc = ARRAY_SIZE(argv) - 1;
        char *sha1_copy;
 -      int needs_pushing = 0;
 +
        struct strbuf remotes_arg = STRBUF_INIT;
  
        strbuf_addf(&remotes_arg, "--remotes=%s", remotes_name);
        if (prepare_revision_walk(&rev))
                die("revision walk setup failed");
  
 -      while ((commit = get_revision(&rev)) && !needs_pushing)
 -              commit_need_pushing(commit, &needs_pushing);
 +      while ((commit = get_revision(&rev)) != NULL)
 +              find_unpushed_submodule_commits(commit, needs_pushing);
  
 +      reset_revision_walk();
        free(sha1_copy);
        strbuf_release(&remotes_arg);
  
 -      return needs_pushing;
 +      return needs_pushing->nr;
 +}
 +
 +static int push_submodule(const char *path)
 +{
 +      if (add_submodule_odb(path))
 +              return 1;
 +
 +      if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) {
 +              struct child_process cp;
 +              const char *argv[] = {"push", NULL};
 +
 +              memset(&cp, 0, sizeof(cp));
 +              cp.argv = argv;
 +              cp.env = local_repo_env;
 +              cp.git_cmd = 1;
 +              cp.no_stdin = 1;
 +              cp.dir = path;
 +              if (run_command(&cp))
 +                      return 0;
 +              close(cp.out);
 +      }
 +
 +      return 1;
 +}
 +
 +int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name)
 +{
 +      int i, ret = 1;
 +      struct string_list needs_pushing;
 +
 +      memset(&needs_pushing, 0, sizeof(struct string_list));
 +      needs_pushing.strdup_strings = 1;
 +
 +      if (!find_unpushed_submodules(new_sha1, remotes_name, &needs_pushing))
 +              return 1;
 +
 +      for (i = 0; i < needs_pushing.nr; i++) {
 +              const char *path = needs_pushing.items[i].string;
 +              fprintf(stderr, "Pushing submodule '%s'\n", path);
 +              if (!push_submodule(path)) {
 +                      fprintf(stderr, "Unable to push submodule '%s'\n", path);
 +                      ret = 0;
 +              }
 +      }
 +
 +      string_list_clear(&needs_pushing, 0);
 +
 +      return ret;
  }
  
  static int is_submodule_commit_present(const char *path, unsigned char sha1[20])
@@@ -574,7 -523,8 +574,7 @@@ static void calculate_changed_submodule
                        DIFF_OPT_SET(&diff_opts, RECURSIVE);
                        diff_opts.output_format |= DIFF_FORMAT_CALLBACK;
                        diff_opts.format_callback = submodule_collect_changed_cb;
 -                      if (diff_setup_done(&diff_opts) < 0)
 -                              die("diff_setup_done failed");
 +                      diff_setup_done(&diff_opts);
                        diff_tree_sha1(parent->item->object.sha1, commit->object.sha1, "", &diff_opts);
                        diffcore_std(&diff_opts);
                        diff_flush(&diff_opts);
@@@ -788,10 -738,9 +788,10 @@@ static int find_first_merges(struct obj
                die("revision walk setup failed");
        while ((commit = get_revision(&revs)) != NULL) {
                struct object *o = &(commit->object);
-               if (in_merge_bases(b, &commit, 1))
+               if (in_merge_bases(b, commit))
                        add_object_array(o, NULL, &merges);
        }
 +      reset_revision_walk();
  
        /* Now we've got all merges that contain a and b. Prune all
         * merges that contain another found merge and save them in
                contains_another = 0;
                for (j = 0; j < merges.nr; j++) {
                        struct commit *m2 = (struct commit *) merges.objects[j].item;
-                       if (i != j && in_merge_bases(m2, &m1, 1)) {
+                       if (i != j && in_merge_bases(m2, m1)) {
                                contains_another = 1;
                                break;
                        }
@@@ -865,18 -814,18 +865,18 @@@ int merge_submodule(unsigned char resul
        }
  
        /* check whether both changes are forward */
-       if (!in_merge_bases(commit_base, &commit_a, 1) ||
-           !in_merge_bases(commit_base, &commit_b, 1)) {
+       if (!in_merge_bases(commit_base, commit_a) ||
+           !in_merge_bases(commit_base, commit_b)) {
                MERGE_WARNING(path, "commits don't follow merge-base");
                return 0;
        }
  
        /* Case #1: a is contained in b or vice versa */
-       if (in_merge_bases(commit_a, &commit_b, 1)) {
+       if (in_merge_bases(commit_a, commit_b)) {
                hashcpy(result, b);
                return 1;
        }
-       if (in_merge_bases(commit_b, &commit_a, 1)) {
+       if (in_merge_bases(commit_b, commit_a)) {
                hashcpy(result, a);
                return 1;
        }