Merge branch 'nd/struct-pathspec'
authorJunio C Hamano <gitster@pobox.com>
Fri, 6 May 2011 17:50:06 +0000 (10:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 6 May 2011 17:50:06 +0000 (10:50 -0700)
* nd/struct-pathspec:
pathspec: rename per-item field has_wildcard to use_wildcard
Improve tree_entry_interesting() handling code
Convert read_tree{,_recursive} to support struct pathspec
Reimplement read_tree_recursive() using tree_entry_interesting()

1  2 
builtin/checkout.c
builtin/grep.c
builtin/log.c
cache.h
dir.c
list-objects.c
merge-recursive.c
tree-diff.c
diff --combined builtin/checkout.c
index 38632fc39805085e3b134e0574f3846931c150c6,f4d4db1ee2136c5a700a12e2489a54e70bd8e615..4761769512a8abcdd5652a93d39be18154e251dd
@@@ -30,7 -30,6 +30,7 @@@ struct checkout_opts 
        int quiet;
        int merge;
        int force;
 +      int force_detach;
        int writeout_stage;
        int writeout_error;
  
@@@ -79,7 -78,10 +79,10 @@@ static int update_some(const unsigned c
  
  static int read_tree_some(struct tree *tree, const char **pathspec)
  {
-       read_tree_recursive(tree, "", 0, 0, pathspec, update_some, NULL);
+       struct pathspec ps;
+       init_pathspec(&ps, pathspec);
+       read_tree_recursive(tree, "", 0, 0, &ps, update_some, NULL);
+       free_pathspec(&ps);
  
        /* update the index with the given tree's info
         * for all args, expanding wildcards, and exit
@@@ -104,10 -106,9 +107,10 @@@ static int check_stage(int stage, struc
                        return 0;
                pos++;
        }
 -      return error("path '%s' does not have %s version",
 -                   ce->name,
 -                   (stage == 2) ? "our" : "their");
 +      if (stage == 2)
 +              return error(_("path '%s' does not have our version"), ce->name);
 +      else
 +              return error(_("path '%s' does not have their version"), ce->name);
  }
  
  static int check_all_stages(struct cache_entry *ce, int pos)
            ce_stage(active_cache[pos+1]) != 2 ||
            strcmp(active_cache[pos+2]->name, ce->name) ||
            ce_stage(active_cache[pos+2]) != 3)
 -              return error("path '%s' does not have all three versions",
 +              return error(_("path '%s' does not have all three versions"),
                             ce->name);
        return 0;
  }
@@@ -132,10 -133,9 +135,10 @@@ static int checkout_stage(int stage, st
                        return checkout_entry(active_cache[pos], state, NULL);
                pos++;
        }
 -      return error("path '%s' does not have %s version",
 -                   ce->name,
 -                   (stage == 2) ? "our" : "their");
 +      if (stage == 2)
 +              return error(_("path '%s' does not have our version"), ce->name);
 +      else
 +              return error(_("path '%s' does not have their version"), ce->name);
  }
  
  static int checkout_merged(int pos, struct checkout *state)
            ce_stage(active_cache[pos+1]) != 2 ||
            strcmp(active_cache[pos+2]->name, path) ||
            ce_stage(active_cache[pos+2]) != 3)
 -              return error("path '%s' does not have all 3 versions", path);
 +              return error(_("path '%s' does not have all 3 versions"), path);
  
        read_mmblob(&ancestor, active_cache[pos]->sha1);
        read_mmblob(&ours, active_cache[pos+1]->sha1);
        free(theirs.ptr);
        if (status < 0 || !result_buf.ptr) {
                free(result_buf.ptr);
 -              return error("path '%s': cannot merge", path);
 +              return error(_("path '%s': cannot merge"), path);
        }
  
        /*
         */
        if (write_sha1_file(result_buf.ptr, result_buf.size,
                            blob_type, sha1))
 -              die("Unable to add merge result for '%s'", path);
 +              die(_("Unable to add merge result for '%s'"), path);
        ce = make_cache_entry(create_ce_mode(active_cache[pos+1]->ce_mode),
                              sha1,
                              path, 2, 0);
        if (!ce)
 -              die("make_cache_entry failed for path '%s'", path);
 +              die(_("make_cache_entry failed for path '%s'"), path);
        status = checkout_entry(ce, state, NULL);
        return status;
  }
@@@ -214,7 -214,7 +217,7 @@@ static int checkout_paths(struct tree *
  
        newfd = hold_locked_index(lock_file, 1);
        if (read_cache_preload(pathspec) < 0)
 -              return error("corrupt index file");
 +              return error(_("corrupt index file"));
  
        if (source_tree)
                read_tree_some(source_tree, pathspec);
                        if (!ce_stage(ce))
                                continue;
                        if (opts->force) {
 -                              warning("path '%s' is unmerged", ce->name);
 +                              warning(_("path '%s' is unmerged"), ce->name);
                        } else if (stage) {
                                errs |= check_stage(stage, ce, pos);
                        } else if (opts->merge) {
                                errs |= check_all_stages(ce, pos);
                        } else {
                                errs = 1;
 -                              error("path '%s' is unmerged", ce->name);
 +                              error(_("path '%s' is unmerged"), ce->name);
                        }
                        pos = skip_same_name(ce, pos) - 1;
                }
  
        if (write_cache(newfd, active_cache, active_nr) ||
            commit_locked_index(lock_file))
 -              die("unable to write new index file");
 +              die(_("unable to write new index file"));
  
        resolve_ref("HEAD", rev, 0, &flag);
        head = lookup_commit_reference_gently(rev, 1);
@@@ -295,12 -295,12 +298,12 @@@ static void show_local_changes(struct o
        rev.diffopt.flags = opts->flags;
        rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
        if (diff_setup_done(&rev.diffopt) < 0)
 -              die("diff_setup_done failed");
 +              die(_("diff_setup_done failed"));
        add_pending_object(&rev, head, NULL);
        run_diff_index(&rev, 0);
  }
  
 -static void describe_detached_head(char *msg, struct commit *commit)
 +static void describe_detached_head(const char *msg, struct commit *commit)
  {
        struct strbuf sb = STRBUF_INIT;
        struct pretty_print_context ctx = {0};
@@@ -369,7 -369,7 +372,7 @@@ static int merge_working_tree(struct ch
        int newfd = hold_locked_index(lock_file, 1);
  
        if (read_cache_preload(NULL) < 0)
 -              return error("corrupt index file");
 +              return error(_("corrupt index file"));
  
        resolve_undo_clear();
        if (opts->force) {
                refresh_cache(REFRESH_QUIET);
  
                if (unmerged_cache()) {
 -                      error("you need to resolve your current index first");
 +                      error(_("you need to resolve your current index first"));
                        return 1;
                }
  
                topts.dir->exclude_per_dir = ".gitignore";
                tree = parse_tree_indirect(old->commit ?
                                           old->commit->object.sha1 :
 -                                         (unsigned char *)EMPTY_TREE_SHA1_BIN);
 +                                         EMPTY_TREE_SHA1_BIN);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
                tree = parse_tree_indirect(new->commit->object.sha1);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
  
        if (write_cache(newfd, active_cache, active_nr) ||
            commit_locked_index(lock_file))
 -              die("unable to write new index file");
 +              die(_("unable to write new index file"));
  
        if (!opts->force && !opts->quiet)
                show_local_changes(&new->commit->object, &opts->diff_options);
@@@ -522,7 -522,7 +525,7 @@@ static void update_refs_for_switch(stru
                                temp = log_all_ref_updates;
                                log_all_ref_updates = 1;
                                if (log_ref_setup(ref_name, log_file, sizeof(log_file))) {
 -                                      fprintf(stderr, "Can not do reflog for '%s'\n",
 +                                      fprintf(stderr, _("Can not do reflog for '%s'\n"),
                                            opts->new_orphan_branch);
                                        log_all_ref_updates = temp;
                                        return;
        strbuf_addf(&msg, "checkout: moving from %s to %s",
                    old_desc ? old_desc : "(invalid)", new->name);
  
 -      if (new->path) {
 +      if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
 +              /* Nothing to do. */
 +      } else if (opts->force_detach || !new->path) {  /* No longer on any branch. */
 +              update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
 +                         REF_NODEREF, DIE_ON_ERR);
 +              if (!opts->quiet) {
 +                      if (old->path && advice_detached_head)
 +                              detach_advice(old->path, new->name);
 +                      describe_detached_head(_("HEAD is now at"), new->commit);
 +              }
 +      } else if (new->path) { /* Switch branches. */
                create_symref("HEAD", new->path, msg.buf);
                if (!opts->quiet) {
 -                      if (old->path && !strcmp(new->path, old->path))
 -                              fprintf(stderr, "Already on '%s'\n",
 -                                      new->name);
 -                      else if (opts->new_branch)
 -                              fprintf(stderr, "Switched to%s branch '%s'\n",
 -                                      opts->branch_exists ? " and reset" : " a new",
 +                      if (old->path && !strcmp(new->path, old->path)) {
 +                              fprintf(stderr, _("Already on '%s'\n"),
                                        new->name);
 -                      else
 -                              fprintf(stderr, "Switched to branch '%s'\n",
 +                      } else if (opts->new_branch) {
 +                              if (opts->branch_exists)
 +                                      fprintf(stderr, _("Switched to and reset branch '%s'\n"), new->name);
 +                              else
 +                                      fprintf(stderr, _("Switched to a new branch '%s'\n"), new->name);
 +                      } else {
 +                              fprintf(stderr, _("Switched to branch '%s'\n"),
                                        new->name);
 +                      }
                }
                if (old->path && old->name) {
                        char log_file[PATH_MAX], ref_file[PATH_MAX];
                        if (!file_exists(ref_file) && file_exists(log_file))
                                remove_path(log_file);
                }
 -      } else if (strcmp(new->name, "HEAD")) {
 -              update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
 -                         REF_NODEREF, DIE_ON_ERR);
 -              if (!opts->quiet) {
 -                      if (old->path && advice_detached_head)
 -                              detach_advice(old->path, new->name);
 -                      describe_detached_head("HEAD is now at", new->commit);
 -              }
        }
        remove_branch_state();
        strbuf_release(&msg);
 -      if (!opts->quiet && (new->path || !strcmp(new->name, "HEAD")))
 +      if (!opts->quiet &&
 +          (new->path || (!opts->force_detach && !strcmp(new->name, "HEAD"))))
                report_tracking(new);
  }
  
 +struct rev_list_args {
 +      int argc;
 +      int alloc;
 +      const char **argv;
 +};
 +
 +static void add_one_rev_list_arg(struct rev_list_args *args, const char *s)
 +{
 +      ALLOC_GROW(args->argv, args->argc + 1, args->alloc);
 +      args->argv[args->argc++] = s;
 +}
 +
 +static int add_one_ref_to_rev_list_arg(const char *refname,
 +                                     const unsigned char *sha1,
 +                                     int flags,
 +                                     void *cb_data)
 +{
 +      add_one_rev_list_arg(cb_data, refname);
 +      return 0;
 +}
 +
 +static int clear_commit_marks_from_one_ref(const char *refname,
 +                                    const unsigned char *sha1,
 +                                    int flags,
 +                                    void *cb_data)
 +{
 +      struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 +      if (commit)
 +              clear_commit_marks(commit, -1);
 +      return 0;
 +}
 +
 +static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
 +{
 +      struct pretty_print_context ctx = { 0 };
 +
 +      parse_commit(commit);
 +      strbuf_addstr(sb, "  ");
 +      strbuf_addstr(sb,
 +              find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
 +      strbuf_addch(sb, ' ');
 +      pretty_print_commit(CMIT_FMT_ONELINE, commit, sb, &ctx);
 +      strbuf_addch(sb, '\n');
 +}
 +
 +#define ORPHAN_CUTOFF 4
 +static void suggest_reattach(struct commit *commit, struct rev_info *revs)
 +{
 +      struct commit *c, *last = NULL;
 +      struct strbuf sb = STRBUF_INIT;
 +      int lost = 0;
 +      while ((c = get_revision(revs)) != NULL) {
 +              if (lost < ORPHAN_CUTOFF)
 +                      describe_one_orphan(&sb, c);
 +              last = c;
 +              lost++;
 +      }
 +      if (ORPHAN_CUTOFF < lost) {
 +              int more = lost - ORPHAN_CUTOFF;
 +              if (more == 1)
 +                      describe_one_orphan(&sb, last);
 +              else
 +                      strbuf_addf(&sb, _(" ... and %d more.\n"), more);
 +      }
 +
 +      fprintf(stderr,
 +              Q_(
 +              /* The singular version */
 +              "Warning: you are leaving %d commit behind, "
 +              "not connected to\n"
 +              "any of your branches:\n\n"
 +              "%s\n"
 +              "If you want to keep it by creating a new branch, "
 +              "this may be a good time\nto do so with:\n\n"
 +              " git branch new_branch_name %s\n\n",
 +              /* The plural version */
 +              "Warning: you are leaving %d commits behind, "
 +              "not connected to\n"
 +              "any of your branches:\n\n"
 +              "%s\n"
 +              "If you want to keep them by creating a new branch, "
 +              "this may be a good time\nto do so with:\n\n"
 +              " git branch new_branch_name %s\n\n",
 +              /* Give ngettext() the count */
 +              lost),
 +              lost,
 +              sb.buf,
 +              sha1_to_hex(commit->object.sha1));
 +      strbuf_release(&sb);
 +}
 +
 +/*
 + * We are about to leave commit that was at the tip of a detached
 + * HEAD.  If it is not reachable from any ref, this is the last chance
 + * for the user to do so without resorting to reflog.
 + */
 +static void orphaned_commit_warning(struct commit *commit)
 +{
 +      struct rev_list_args args = { 0, 0, NULL };
 +      struct rev_info revs;
 +
 +      add_one_rev_list_arg(&args, "(internal)");
 +      add_one_rev_list_arg(&args, sha1_to_hex(commit->object.sha1));
 +      add_one_rev_list_arg(&args, "--not");
 +      for_each_ref(add_one_ref_to_rev_list_arg, &args);
 +      add_one_rev_list_arg(&args, "--");
 +      add_one_rev_list_arg(&args, NULL);
 +
 +      init_revisions(&revs, NULL);
 +      if (setup_revisions(args.argc - 1, args.argv, &revs, NULL) != 1)
 +              die(_("internal error: only -- alone should have been left"));
 +      if (prepare_revision_walk(&revs))
 +              die(_("internal error in revision walk"));
 +      if (!(commit->object.flags & UNINTERESTING))
 +              suggest_reattach(commit, &revs);
 +      else
 +              describe_detached_head(_("Previous HEAD position was"), commit);
 +
 +      clear_commit_marks(commit, -1);
 +      for_each_ref(clear_commit_marks_from_one_ref, NULL);
 +}
 +
  static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
  {
        int ret = 0;
                new->name = "HEAD";
                new->commit = old.commit;
                if (!new->commit)
 -                      die("You are on a branch yet to be born");
 +                      die(_("You are on a branch yet to be born"));
                parse_commit(new->commit);
        }
  
        if (ret)
                return ret;
  
 -      /*
 -       * If we were on a detached HEAD, but have now moved to
 -       * a new commit, we want to mention the old commit once more
 -       * to remind the user that it might be lost.
 -       */
        if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
 -              describe_detached_head("Previous HEAD position was", old.commit);
 +              orphaned_commit_warning(old.commit);
  
        update_refs_for_switch(opts, &old, new);
  
@@@ -800,123 -678,11 +803,123 @@@ static const char *unique_tracking_name
        return NULL;
  }
  
 +static int parse_branchname_arg(int argc, const char **argv,
 +                              int dwim_new_local_branch_ok,
 +                              struct branch_info *new,
 +                              struct tree **source_tree,
 +                              unsigned char rev[20],
 +                              const char **new_branch)
 +{
 +      int argcount = 0;
 +      unsigned char branch_rev[20];
 +      const char *arg;
 +      int has_dash_dash;
 +
 +      /*
 +       * case 1: git checkout <ref> -- [<paths>]
 +       *
 +       *   <ref> must be a valid tree, everything after the '--' must be
 +       *   a path.
 +       *
 +       * case 2: git checkout -- [<paths>]
 +       *
 +       *   everything after the '--' must be paths.
 +       *
 +       * case 3: git checkout <something> [<paths>]
 +       *
 +       *   With no paths, if <something> is a commit, that is to
 +       *   switch to the branch or detach HEAD at it.  As a special case,
 +       *   if <something> is A...B (missing A or B means HEAD but you can
 +       *   omit at most one side), and if there is a unique merge base
 +       *   between A and B, A...B names that merge base.
 +       *
 +       *   With no paths, if <something> is _not_ a commit, no -t nor -b
 +       *   was given, and there is a tracking branch whose name is
 +       *   <something> in one and only one remote, then this is a short-hand
 +       *   to fork local <something> from that remote-tracking branch.
 +       *
 +       *   Otherwise <something> shall not be ambiguous.
 +       *   - If it's *only* a reference, treat it like case (1).
 +       *   - If it's only a path, treat it like case (2).
 +       *   - else: fail.
 +       *
 +       */
 +      if (!argc)
 +              return 0;
 +
 +      if (!strcmp(argv[0], "--"))     /* case (2) */
 +              return 1;
 +
 +      arg = argv[0];
 +      has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
 +
 +      if (!strcmp(arg, "-"))
 +              arg = "@{-1}";
 +
 +      if (get_sha1_mb(arg, rev)) {
 +              if (has_dash_dash)          /* case (1) */
 +                      die(_("invalid reference: %s"), arg);
 +              if (dwim_new_local_branch_ok &&
 +                  !check_filename(NULL, arg) &&
 +                  argc == 1) {
 +                      const char *remote = unique_tracking_name(arg);
 +                      if (!remote || get_sha1(remote, rev))
 +                              return argcount;
 +                      *new_branch = arg;
 +                      arg = remote;
 +                      /* DWIMmed to create local branch */
 +              } else {
 +                      return argcount;
 +              }
 +      }
 +
 +      /* we can't end up being in (2) anymore, eat the argument */
 +      argcount++;
 +      argv++;
 +      argc--;
 +
 +      new->name = arg;
 +      setup_branch_path(new);
 +
 +      if (check_ref_format(new->path) == CHECK_REF_FORMAT_OK &&
 +          resolve_ref(new->path, branch_rev, 1, NULL))
 +              hashcpy(rev, branch_rev);
 +      else
 +              new->path = NULL; /* not an existing branch */
 +
 +      new->commit = lookup_commit_reference_gently(rev, 1);
 +      if (!new->commit) {
 +              /* not a commit */
 +              *source_tree = parse_tree_indirect(rev);
 +      } else {
 +              parse_commit(new->commit);
 +              *source_tree = new->commit->tree;
 +      }
 +
 +      if (!*source_tree)                   /* case (1): want a tree */
 +              die(_("reference is not a tree: %s"), arg);
 +      if (!has_dash_dash) {/* case (3 -> 1) */
 +              /*
 +               * Do not complain the most common case
 +               *      git checkout branch
 +               * even if there happen to be a file called 'branch';
 +               * it would be extremely annoying.
 +               */
 +              if (argc)
 +                      verify_non_filename(NULL, arg);
 +      } else {
 +              argcount++;
 +              argv++;
 +              argc--;
 +      }
 +
 +      return argcount;
 +}
 +
  int cmd_checkout(int argc, const char **argv, const char *prefix)
  {
        struct checkout_opts opts;
        unsigned char rev[20];
 -      const char *arg;
        struct branch_info new;
        struct tree *source_tree = NULL;
        char *conflict_style = NULL;
                OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
                           "create/reset and checkout a branch"),
                OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"),
 +              OPT_BOOLEAN(0, "detach", &opts.force_detach, "detach the HEAD at named commit"),
                OPT_SET_INT('t', "track",  &opts.track, "set upstream info for new branch",
                        BRANCH_TRACK_EXPLICIT),
                OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
                  PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
                OPT_END(),
        };
 -      int has_dash_dash;
  
        memset(&opts, 0, sizeof(opts));
        memset(&new, 0, sizeof(new));
  
        /* we can assume from now on new_branch = !new_branch_force */
        if (opts.new_branch && opts.new_branch_force)
 -              die("-B cannot be used with -b");
 +              die(_("-B cannot be used with -b"));
  
        /* copy -B over to -b, so that we can just check the latter */
        if (opts.new_branch_force)
                opts.new_branch = opts.new_branch_force;
  
        if (patch_mode && (opts.track > 0 || opts.new_branch
 -                         || opts.new_branch_log || opts.merge || opts.force))
 -              die ("--patch is incompatible with all other options");
 +                         || opts.new_branch_log || opts.merge || opts.force
 +                         || opts.force_detach))
 +              die (_("--patch is incompatible with all other options"));
 +
 +      if (opts.force_detach && (opts.new_branch || opts.new_orphan_branch))
 +              die(_("--detach cannot be used with -b/-B/--orphan"));
 +      if (opts.force_detach && 0 < opts.track)
 +              die(_("--detach cannot be used with -t"));
  
        /* --track without -b should DWIM */
        if (0 < opts.track && !opts.new_branch) {
                const char *argv0 = argv[0];
                if (!argc || !strcmp(argv0, "--"))
 -                      die ("--track needs a branch name");
 +                      die (_("--track needs a branch name"));
                if (!prefixcmp(argv0, "refs/"))
                        argv0 += 5;
                if (!prefixcmp(argv0, "remotes/"))
                        argv0 += 8;
                argv0 = strchr(argv0, '/');
                if (!argv0 || !argv0[1])
 -                      die ("Missing branch name; try -b");
 +                      die (_("Missing branch name; try -b"));
                opts.new_branch = argv0 + 1;
        }
  
        if (opts.new_orphan_branch) {
                if (opts.new_branch)
 -                      die("--orphan and -b|-B are mutually exclusive");
 +                      die(_("--orphan and -b|-B are mutually exclusive"));
                if (opts.track > 0)
 -                      die("--orphan cannot be used with -t");
 +                      die(_("--orphan cannot be used with -t"));
                opts.new_branch = opts.new_orphan_branch;
        }
  
        }
  
        if (opts.force && opts.merge)
 -              die("git checkout: -f and -m are incompatible");
 +              die(_("git checkout: -f and -m are incompatible"));
  
        /*
 -       * case 1: git checkout <ref> -- [<paths>]
 +       * Extract branch name from command line arguments, so
 +       * all that is left is pathspecs.
         *
 -       *   <ref> must be a valid tree, everything after the '--' must be
 -       *   a path.
 -       *
 -       * case 2: git checkout -- [<paths>]
 -       *
 -       *   everything after the '--' must be paths.
 -       *
 -       * case 3: git checkout <something> [<paths>]
 -       *
 -       *   With no paths, if <something> is a commit, that is to
 -       *   switch to the branch or detach HEAD at it.  As a special case,
 -       *   if <something> is A...B (missing A or B means HEAD but you can
 -       *   omit at most one side), and if there is a unique merge base
 -       *   between A and B, A...B names that merge base.
 +       * Handle
         *
 -       *   With no paths, if <something> is _not_ a commit, no -t nor -b
 -       *   was given, and there is a remote-tracking branch whose name is
 -       *   <something> in one and only one remote, then this is a short-hand
 -       *   to fork local <something> from that remote-tracking branch.
 -       *
 -       *   Otherwise <something> shall not be ambiguous.
 -       *   - If it's *only* a reference, treat it like case (1).
 -       *   - If it's only a path, treat it like case (2).
 -       *   - else: fail.
 +       *  1) git checkout <tree> -- [<paths>]
 +       *  2) git checkout -- [<paths>]
 +       *  3) git checkout <something> [<paths>]
         *
 +       * including "last branch" syntax and DWIM-ery for names of
 +       * remote branches, erroring out for invalid or ambiguous cases.
         */
        if (argc) {
 -              if (!strcmp(argv[0], "--")) {       /* case (2) */
 -                      argv++;
 -                      argc--;
 -                      goto no_reference;
 -              }
 -
 -              arg = argv[0];
 -              has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
 -
 -              if (!strcmp(arg, "-"))
 -                      arg = "@{-1}";
 -
 -              if (get_sha1_mb(arg, rev)) {
 -                      if (has_dash_dash)          /* case (1) */
 -                              die("invalid reference: %s", arg);
 -                      if (!patch_mode &&
 -                          dwim_new_local_branch &&
 -                          opts.track == BRANCH_TRACK_UNSPECIFIED &&
 -                          !opts.new_branch &&
 -                          !check_filename(NULL, arg) &&
 -                          argc == 1) {
 -                              const char *remote = unique_tracking_name(arg);
 -                              if (!remote || get_sha1(remote, rev))
 -                                      goto no_reference;
 -                              opts.new_branch = arg;
 -                              arg = remote;
 -                              /* DWIMmed to create local branch */
 -                      }
 -                      else
 -                              goto no_reference;
 -              }
 -
 -              /* we can't end up being in (2) anymore, eat the argument */
 -              argv++;
 -              argc--;
 -
 -              new.name = arg;
 -              if ((new.commit = lookup_commit_reference_gently(rev, 1))) {
 -                      setup_branch_path(&new);
 -
 -                      if ((check_ref_format(new.path) == CHECK_REF_FORMAT_OK) &&
 -                          resolve_ref(new.path, rev, 1, NULL))
 -                              ;
 -                      else
 -                              new.path = NULL;
 -                      parse_commit(new.commit);
 -                      source_tree = new.commit->tree;
 -              } else
 -                      source_tree = parse_tree_indirect(rev);
 -
 -              if (!source_tree)                   /* case (1): want a tree */
 -                      die("reference is not a tree: %s", arg);
 -              if (!has_dash_dash) {/* case (3 -> 1) */
 -                      /*
 -                       * Do not complain the most common case
 -                       *      git checkout branch
 -                       * even if there happen to be a file called 'branch';
 -                       * it would be extremely annoying.
 -                       */
 -                      if (argc)
 -                              verify_non_filename(NULL, arg);
 -              }
 -              else {
 -                      argv++;
 -                      argc--;
 -              }
 +              int dwim_ok =
 +                      !patch_mode &&
 +                      dwim_new_local_branch &&
 +                      opts.track == BRANCH_TRACK_UNSPECIFIED &&
 +                      !opts.new_branch;
 +              int n = parse_branchname_arg(argc, argv, dwim_ok,
 +                              &new, &source_tree, rev, &opts.new_branch);
 +              argv += n;
 +              argc -= n;
        }
  
 -no_reference:
 -
        if (opts.track == BRANCH_TRACK_UNSPECIFIED)
                opts.track = git_branch_track;
  
                const char **pathspec = get_pathspec(prefix, argv);
  
                if (!pathspec)
 -                      die("invalid path specification");
 +                      die(_("invalid path specification"));
  
                if (patch_mode)
                        return interactive_checkout(new.name, pathspec, &opts);
                /* Checkout paths */
                if (opts.new_branch) {
                        if (argc == 1) {
 -                              die("git checkout: updating paths is incompatible with switching branches.\nDid you intend to checkout '%s' which can not be resolved as commit?", argv[0]);
 +                              die(_("git checkout: updating paths is incompatible with switching branches.\nDid you intend to checkout '%s' which can not be resolved as commit?"), argv[0]);
                        } else {
 -                              die("git checkout: updating paths is incompatible with switching branches.");
 +                              die(_("git checkout: updating paths is incompatible with switching branches."));
                        }
                }
  
 +              if (opts.force_detach)
 +                      die(_("git checkout: --detach does not take a path argument"));
 +
                if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge)
 -                      die("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index.");
 +                      die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index."));
  
                return checkout_paths(source_tree, pathspec, &opts);
        }
        if (opts.new_branch) {
                struct strbuf buf = STRBUF_INIT;
                if (strbuf_check_branch_ref(&buf, opts.new_branch))
 -                      die("git checkout: we do not like '%s' as a branch name.",
 +                      die(_("git checkout: we do not like '%s' as a branch name."),
                            opts.new_branch);
                if (!get_sha1(buf.buf, rev)) {
                        opts.branch_exists = 1;
                        if (!opts.new_branch_force)
 -                              die("git checkout: branch %s already exists",
 +                              die(_("git checkout: branch %s already exists"),
                                    opts.new_branch);
                }
                strbuf_release(&buf);
        }
  
        if (new.name && !new.commit) {
 -              die("Cannot switch branch to a non-commit.");
 +              die(_("Cannot switch branch to a non-commit."));
        }
        if (opts.writeout_stage)
 -              die("--ours/--theirs is incompatible with switching branches.");
 +              die(_("--ours/--theirs is incompatible with switching branches."));
  
        return switch_branches(&opts, &new);
  }
diff --combined builtin/grep.c
index 10a1f65310f28f2014bab3f3295205abf6dc59ad,73b962f8329c6045fc98f49913045a8f6f5af52d..3ee2ec51def59695813ee14f104d142a62d530b6
@@@ -40,7 -40,8 +40,7 @@@ enum work_type {WORK_SHA1, WORK_FILE}
   * threads. The producer adds struct work_items to 'todo' and the
   * consumers pick work items from the same array.
   */
 -struct work_item
 -{
 +struct work_item {
        enum work_type type;
        char *name;
  
@@@ -244,7 -245,7 +244,7 @@@ static void start_threads(struct grep_o
                err = pthread_create(&threads[i], NULL, run, o);
  
                if (err)
 -                      die("grep: failed to create thread: %s",
 +                      die(_("grep: failed to create thread: %s"),
                            strerror(err));
        }
  }
@@@ -302,19 -303,6 +302,19 @@@ static int grep_config(const char *var
        default: return 0;
        }
  
 +      if (!strcmp(var, "grep.extendedregexp")) {
 +              if (git_config_bool(var, value))
 +                      opt->regflags |= REG_EXTENDED;
 +              else
 +                      opt->regflags &= ~REG_EXTENDED;
 +              return 0;
 +      }
 +
 +      if (!strcmp(var, "grep.linenumber")) {
 +              opt->linenum = git_config_bool(var, value);
 +              return 0;
 +      }
 +
        if (!strcmp(var, "color.grep"))
                opt->color = git_config_colorbool(var, value, -1);
        else if (!strcmp(var, "color.grep.context"))
@@@ -362,7 -350,7 +362,7 @@@ static void *load_sha1(const unsigned c
        void *data = lock_and_read_sha1_file(sha1, &type, size);
  
        if (!data)
 -              error("'%s': unable to read %s", name, sha1_to_hex(sha1));
 +              error(_("'%s': unable to read %s"), name, sha1_to_hex(sha1));
  
        return data;
  }
@@@ -413,21 -401,21 +413,21 @@@ static void *load_file(const char *file
        if (lstat(filename, &st) < 0) {
        err_ret:
                if (errno != ENOENT)
 -                      error("'%s': %s", filename, strerror(errno));
 -              return 0;
 +                      error(_("'%s': %s"), filename, strerror(errno));
 +              return NULL;
        }
        if (!S_ISREG(st.st_mode))
 -              return 0;
 +              return NULL;
        *sz = xsize_t(st.st_size);
        i = open(filename, O_RDONLY);
        if (i < 0)
                goto err_ret;
        data = xmalloc(*sz + 1);
        if (st.st_size != read_in_full(i, data, *sz)) {
 -              error("'%s': short read %s", filename, strerror(errno));
 +              error(_("'%s': short read %s"), filename, strerror(errno));
                close(i);
                free(data);
 -              return 0;
 +              return NULL;
        }
        close(i);
        data[*sz] = 0;
@@@ -486,7 -474,7 +486,7 @@@ static void run_pager(struct grep_opt *
        argv[path_list->nr] = NULL;
  
        if (prefix && chdir(prefix))
 -              die("Failed to chdir: %s", prefix);
 +              die(_("Failed to chdir: %s"), prefix);
        status = run_command_v_opt(argv, RUN_USING_SHELL);
        if (status)
                exit(status);
@@@ -533,18 -521,18 +533,18 @@@ static int grep_cache(struct grep_opt *
  static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                     struct tree_desc *tree, struct strbuf *base, int tn_len)
  {
-       int hit = 0, matched = 0;
+       int hit = 0, match = 0;
        struct name_entry entry;
        int old_baselen = base->len;
  
        while (tree_entry(tree, &entry)) {
                int te_len = tree_entry_len(entry.path, entry.sha1);
  
-               if (matched != 2) {
-                       matched = tree_entry_interesting(&entry, base, tn_len, pathspec);
-                       if (matched == -1)
-                               break; /* no more matches */
-                       if (!matched)
+               if (match != 2) {
+                       match = tree_entry_interesting(&entry, base, tn_len, pathspec);
+                       if (match < 0)
+                               break;
+                       if (match == 0)
                                continue;
                }
  
  
                        data = lock_and_read_sha1_file(entry.sha1, &type, &size);
                        if (!data)
 -                              die("unable to read tree (%s)",
 +                              die(_("unable to read tree (%s)"),
                                    sha1_to_hex(entry.sha1));
  
                        strbuf_addch(base, '/');
@@@ -592,7 -580,7 +592,7 @@@ static int grep_object(struct grep_opt 
                data = read_object_with_reference(obj->sha1, tree_type,
                                                  &size, NULL);
                if (!data)
 -                      die("unable to read tree (%s)", sha1_to_hex(obj->sha1));
 +                      die(_("unable to read tree (%s)"), sha1_to_hex(obj->sha1));
  
                len = name ? strlen(name) : 0;
                strbuf_init(&base, PATH_MAX + len + 1);
                free(data);
                return hit;
        }
 -      die("unable to grep from object of type %s", typename(obj->type));
 +      die(_("unable to grep from object of type %s"), typename(obj->type));
  }
  
  static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
@@@ -638,10 -626,6 +638,10 @@@ static int grep_directory(struct grep_o
  
        fill_directory(&dir, pathspec->raw);
        for (i = 0; i < dir.nr; i++) {
 +              const char *name = dir.entries[i]->name;
 +              int namelen = strlen(name);
 +              if (!match_pathspec_depth(pathspec, name, namelen, 0, NULL))
 +                      continue;
                hit |= grep_file(opt, dir.entries[i]->name);
                if (hit && opt->status_only)
                        break;
@@@ -662,7 -646,7 +662,7 @@@ static int context_callback(const struc
        }
        value = strtol(arg, (char **)&endp, 10);
        if (*endp) {
 -              return error("switch `%c' expects a numerical value",
 +              return error(_("switch `%c' expects a numerical value"),
                             opt->short_name);
        }
        grep_opt->pre_context = grep_opt->post_context = value;
  static int file_callback(const struct option *opt, const char *arg, int unset)
  {
        struct grep_opt *grep_opt = opt->value;
 +      int from_stdin = !strcmp(arg, "-");
        FILE *patterns;
        int lno = 0;
        struct strbuf sb = STRBUF_INIT;
  
 -      patterns = fopen(arg, "r");
 +      patterns = from_stdin ? stdin : fopen(arg, "r");
        if (!patterns)
 -              die_errno("cannot open '%s'", arg);
 +              die_errno(_("cannot open '%s'"), arg);
        while (strbuf_getline(&sb, patterns, '\n') == 0) {
                char *s;
                size_t len;
                s = strbuf_detach(&sb, &len);
                append_grep_pat(grep_opt, s, len, arg, ++lno, GREP_PATTERN);
        }
 -      fclose(patterns);
 +      if (!from_stdin)
 +              fclose(patterns);
        strbuf_release(&sb);
        return 0;
  }
@@@ -782,7 -764,7 +782,7 @@@ int cmd_grep(int argc, const char **arg
                OPT_BOOLEAN('F', "fixed-strings", &opt.fixed,
                        "interpret patterns as fixed strings"),
                OPT_GROUP(""),
 -              OPT_BOOLEAN('n', NULL, &opt.linenum, "show line numbers"),
 +              OPT_BOOLEAN('n', "line-number", &opt.linenum, "show line numbers"),
                OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
                OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
                OPT_NEGBIT(0, "full-name", &opt.relative,
        }
  
        if (!opt.pattern_list)
 -              die("no pattern given.");
 +              die(_("no pattern given."));
        if (!opt.fixed && opt.ignore_case)
                opt.regflags |= REG_ICASE;
        if ((opt.regflags != REG_NEWLINE) && opt.fixed)
 -              die("cannot mix --fixed-strings and regexp");
 +              die(_("cannot mix --fixed-strings and regexp"));
  
  #ifndef NO_PTHREADS
        if (online_cpus() == 1 || !grep_threads_ok(&opt))
                if (!get_sha1(arg, sha1)) {
                        struct object *object = parse_object(sha1);
                        if (!object)
 -                              die("bad object %s", arg);
 +                              die(_("bad object %s"), arg);
                        add_object_array(object, arg, &list);
                        continue;
                }
        pathspec.recursive = 1;
  
        if (show_in_pager && (cached || list.nr))
 -              die("--open-files-in-pager only works on the worktree");
 +              die(_("--open-files-in-pager only works on the worktree"));
  
        if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) {
                const char *pager = path_list.items[0].string;
  
        if (!use_index) {
                if (cached)
 -                      die("--cached cannot be used with --no-index.");
 +                      die(_("--cached cannot be used with --no-index."));
                if (list.nr)
 -                      die("--no-index cannot be used with revs.");
 +                      die(_("--no-index cannot be used with revs."));
                hit = grep_directory(&opt, &pathspec);
        } else if (!list.nr) {
                if (!cached)
                hit = grep_cache(&opt, &pathspec, cached);
        } else {
                if (cached)
 -                      die("both --cached and trees are given.");
 +                      die(_("both --cached and trees are given."));
                hit = grep_objects(&opt, &pathspec, &list);
        }
  
diff --combined builtin/log.c
index 55abe07610bce0a959b1878be128e09906f8fea4,e6bbcecda2b25b0f06f01bf2ec5d83479225353c..d43ad3a6172b4e083a6c066ab15dfce5bdb0ad3c
@@@ -49,8 -49,13 +49,8 @@@ static int parse_decoration_style(cons
        return -1;
  }
  
 -static void cmd_log_init(int argc, const char **argv, const char *prefix,
 -                       struct rev_info *rev, struct setup_revision_opt *opt)
 +static void cmd_log_init_defaults(struct rev_info *rev)
  {
 -      int i;
 -      int decoration_given = 0;
 -      struct userformat_want w;
 -
        rev->abbrev = DEFAULT_ABBREV;
        rev->commit_format = CMIT_FMT_DEFAULT;
        if (fmt_pretty)
  
        if (default_date_mode)
                rev->date_mode = parse_date_format(default_date_mode);
 +}
  
 +static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
 +                       struct rev_info *rev, struct setup_revision_opt *opt)
 +{
 +      int i;
 +      int decoration_given = 0;
 +      struct userformat_want w;
        /*
         * Check for -h before setup_revisions(), or "git log -h" will
         * fail when run without a git directory.
                        const char *v = skip_prefix(arg, "--decorate=");
                        decoration_style = parse_decoration_style(arg, v);
                        if (decoration_style < 0)
 -                              die("invalid --decorate option: %s", arg);
 +                              die(_("invalid --decorate option: %s"), arg);
                        decoration_given = 1;
                } else if (!strcmp(arg, "--no-decorate")) {
                        decoration_style = 0;
                } else if (!strcmp(arg, "-h")) {
                        usage(builtin_log_usage);
                } else
 -                      die("unrecognized argument: %s", arg);
 +                      die(_("unrecognized argument: %s"), arg);
        }
  
        /*
        setup_pager();
  }
  
 +static void cmd_log_init(int argc, const char **argv, const char *prefix,
 +                       struct rev_info *rev, struct setup_revision_opt *opt)
 +{
 +      cmd_log_init_defaults(rev);
 +      cmd_log_init_finish(argc, argv, prefix, rev, opt);
 +}
 +
  /*
   * This gives a rough estimate for how many commits we
   * will print out in the list.
@@@ -162,7 -153,7 +162,7 @@@ static void show_early_header(struct re
                if (rev->commit_format != CMIT_FMT_ONELINE)
                        putchar(rev->diffopt.line_termination);
        }
 -      printf("Final output: %d %s\n", nr, stage);
 +      printf(_("Final output: %d %s\n"), nr, stage);
  }
  
  static struct itimerval early_output_timer;
@@@ -256,14 -247,12 +256,14 @@@ static void finish_early_output(struct 
  static int cmd_log_walk(struct rev_info *rev)
  {
        struct commit *commit;
 +      int saved_nrl = 0;
 +      int saved_dcctc = 0;
  
        if (rev->early_output)
                setup_early_output(rev);
  
        if (prepare_revision_walk(rev))
 -              die("revision walk setup failed");
 +              die(_("revision walk setup failed"));
  
        if (rev->early_output)
                finish_early_output(rev);
         * retain that state information if replacing rev->diffopt in this loop
         */
        while ((commit = get_revision(rev)) != NULL) {
 -              log_tree_commit(rev, commit);
 +              if (!log_tree_commit(rev, commit) &&
 +                  rev->max_count >= 0)
 +                      /*
 +                       * We decremented max_count in get_revision,
 +                       * but we didn't actually show the commit.
 +                       */
 +                      rev->max_count++;
                if (!rev->reflog_info) {
                        /* we allow cycles in reflog ancestry */
                        free(commit->buffer);
                }
                free_commit_list(commit->parents);
                commit->parents = NULL;
 +              if (saved_nrl < rev->diffopt.needed_rename_limit)
 +                      saved_nrl = rev->diffopt.needed_rename_limit;
 +              if (rev->diffopt.degraded_cc_to_c)
 +                      saved_dcctc = 1;
        }
 +      rev->diffopt.degraded_cc_to_c = saved_dcctc;
 +      rev->diffopt.needed_rename_limit = saved_nrl;
 +
        if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
            DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) {
                return 02;
@@@ -367,7 -343,7 +367,7 @@@ static int show_object(const unsigned c
        int offset = 0;
  
        if (!buf)
 -              return error("Could not read object %s", sha1_to_hex(sha1));
 +              return error(_("Could not read object %s"), sha1_to_hex(sha1));
  
        if (show_tag_object)
                while (offset < size && buf[offset] != '\n') {
@@@ -414,6 -390,7 +414,7 @@@ int cmd_show(int argc, const char **arg
        struct rev_info rev;
        struct object_array_entry *objects;
        struct setup_revision_opt opt;
+       struct pathspec match_all;
        int i, count, ret = 0;
  
        git_config(git_log_config, NULL);
        if (diff_use_color_default == -1)
                diff_use_color_default = git_use_color_default;
  
+       init_pathspec(&match_all, NULL);
        init_revisions(&rev, prefix);
        rev.diff = 1;
        rev.always_show_header = 1;
                                break;
                        o = parse_object(t->tagged->sha1);
                        if (!o)
 -                              ret = error("Could not read object %s",
 +                              ret = error(_("Could not read object %s"),
                                            sha1_to_hex(t->tagged->sha1));
                        objects[i].item = o;
                        i--;
                                        diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
                                        name,
                                        diff_get_color_opt(&rev.diffopt, DIFF_RESET));
-                       read_tree_recursive((struct tree *)o, "", 0, 0, NULL,
+                       read_tree_recursive((struct tree *)o, "", 0, 0, &match_all,
                                        show_tree_object, NULL);
                        rev.shown_one = 1;
                        break;
                        ret = cmd_log_walk(&rev);
                        break;
                default:
 -                      ret = error("Unknown type: %d", o->type);
 +                      ret = error(_("Unknown type: %d"), o->type);
                }
        }
        free(objects);
@@@ -504,11 -482,16 +506,11 @@@ int cmd_log_reflog(int argc, const cha
        rev.verbose_header = 1;
        memset(&opt, 0, sizeof(opt));
        opt.def = "HEAD";
 -      cmd_log_init(argc, argv, prefix, &rev, &opt);
 -
 -      /*
 -       * This means that we override whatever commit format the user gave
 -       * on the cmd line.  Sad, but cmd_log_init() currently doesn't
 -       * allow us to set a different default.
 -       */
 +      cmd_log_init_defaults(&rev);
        rev.commit_format = CMIT_FMT_ONELINE;
        rev.use_terminator = 1;
        rev.always_show_header = 1;
 +      cmd_log_init_finish(argc, argv, prefix, &rev, &opt);
  
        return cmd_log_walk(&rev);
  }
@@@ -573,7 -556,7 +575,7 @@@ static int git_format_config(const cha
  {
        if (!strcmp(var, "format.headers")) {
                if (!value)
 -                      die("format.headers without value");
 +                      die(_("format.headers without value"));
                add_header(value);
                return 0;
        }
@@@ -636,7 -619,7 +638,7 @@@ static FILE *realstdout = NULL
  static const char *output_directory = NULL;
  static int outdir_offset;
  
 -static int reopen_stdout(struct commit *commit, struct rev_info *rev)
 +static int reopen_stdout(struct commit *commit, struct rev_info *rev, int quiet)
  {
        struct strbuf filename = STRBUF_INIT;
        int suffix_len = strlen(fmt_patch_suffix) + 1;
                strbuf_addstr(&filename, output_directory);
                if (filename.len >=
                    PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len)
 -                      return error("name of output directory is too long");
 +                      return error(_("name of output directory is too long"));
                if (filename.buf[filename.len - 1] != '/')
                        strbuf_addch(&filename, '/');
        }
  
        get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename);
  
 -      if (!DIFF_OPT_TST(&rev->diffopt, QUICK))
 +      if (!quiet)
                fprintf(realstdout, "%s\n", filename.buf + outdir_offset);
  
        if (freopen(filename.buf, "w", stdout) == NULL)
 -              return error("Cannot open patch file %s", filename.buf);
 +              return error(_("Cannot open patch file %s"), filename.buf);
  
        strbuf_release(&filename);
        return 0;
@@@ -670,7 -653,7 +672,7 @@@ static void get_patch_ids(struct rev_in
        unsigned flags1, flags2;
  
        if (rev->pending.nr != 2)
 -              die("Need exactly one range.");
 +              die(_("Need exactly one range."));
  
        o1 = rev->pending.objects[0].item;
        flags1 = o1->flags;
        flags2 = o2->flags;
  
        if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
 -              die("Not a range.");
 +              die(_("Not a range."));
  
        init_patch_ids(ids);
  
        add_pending_object(&check_rev, o1, "o1");
        add_pending_object(&check_rev, o2, "o2");
        if (prepare_revision_walk(&check_rev))
 -              die("revision walk setup failed");
 +              die(_("revision walk setup failed"));
  
        while ((commit = get_revision(&check_rev)) != NULL) {
                /* ignore merges */
@@@ -715,7 -698,7 +717,7 @@@ static void gen_message_id(struct rev_i
        const char *email_end = strrchr(committer, '>');
        struct strbuf buf = STRBUF_INIT;
        if (!email_start || !email_end || email_start > email_end - 1)
 -              die("Could not extract email from committer identity.");
 +              die(_("Could not extract email from committer identity."));
        strbuf_addf(&buf, "%s.%lu.git.%.*s", base,
                    (unsigned long) time(NULL),
                    (int)(email_end - email_start - 1), email_start + 1);
@@@ -731,8 -714,7 +733,8 @@@ static void print_signature(void
  static void make_cover_letter(struct rev_info *rev, int use_stdout,
                              int numbered, int numbered_files,
                              struct commit *origin,
 -                            int nr, struct commit **list, struct commit *head)
 +                            int nr, struct commit **list, struct commit *head,
 +                            int quiet)
  {
        const char *committer;
        const char *subject_start = NULL;
        struct commit *commit = NULL;
  
        if (rev->commit_format != CMIT_FMT_EMAIL)
 -              die("Cover letter needs email format");
 +              die(_("Cover letter needs email format"));
  
        committer = git_committer_info(0);
  
                        sha1_to_hex(head->object.sha1), committer, committer);
        }
  
 -      if (!use_stdout && reopen_stdout(commit, rev))
 +      if (!use_stdout && reopen_stdout(commit, rev, quiet))
                return;
  
        if (commit) {
@@@ -841,7 -823,7 +843,7 @@@ static const char *clean_message_id(con
                m++;
        }
        if (!z)
 -              die("insane in-reply-to: %s", msg_id);
 +              die(_("insane in-reply-to: %s"), msg_id);
        if (++z == m)
                return a;
        return xmemdupz(a, z - a);
@@@ -914,7 -896,7 +916,7 @@@ static int output_directory_callback(co
  {
        const char **dir = (const char **)opt->value;
        if (*dir)
 -              die("Two output directories?");
 +              die(_("Two output directories?"));
        *dir = arg;
        return 0;
  }
@@@ -1009,7 -991,6 +1011,7 @@@ int cmd_format_patch(int argc, const ch
        char *add_signoff = NULL;
        struct strbuf buf = STRBUF_INIT;
        int use_patch_format = 0;
 +      int quiet = 0;
        const struct option builtin_format_patch_options[] = {
                { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
                            "use [PATCH n/m] even with a single patch",
                            PARSE_OPT_OPTARG, thread_callback },
                OPT_STRING(0, "signature", &signature, "signature",
                            "add a signature"),
 +              OPT_BOOLEAN(0, "quiet", &quiet,
 +                          "don't print the patch filenames"),
                OPT_END()
        };
  
        rev.commit_format = CMIT_FMT_EMAIL;
        rev.verbose_header = 1;
        rev.diff = 1;
 -      rev.no_merges = 1;
 +      rev.max_parents = 1;
        DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
        rev.subject_prefix = fmt_patch_subject_prefix;
        memset(&s_r_opt, 0, sizeof(s_r_opt));
                committer = git_committer_info(IDENT_ERROR_ON_NO_NAME);
                endpos = strchr(committer, '>');
                if (!endpos)
 -                      die("bogus committer info %s", committer);
 +                      die(_("bogus committer info %s"), committer);
                add_signoff = xmemdupz(committer, endpos - committer + 1);
        }
  
                numbered = 0;
  
        if (numbered && keep_subject)
 -              die ("-n and -k are mutually exclusive.");
 +              die (_("-n and -k are mutually exclusive."));
        if (keep_subject && subject_prefix)
 -              die ("--subject-prefix and -k are mutually exclusive.");
 +              die (_("--subject-prefix and -k are mutually exclusive."));
  
        argc = setup_revisions(argc, argv, &rev, &s_r_opt);
        if (argc > 1)
 -              die ("unrecognized argument: %s", argv[1]);
 +              die (_("unrecognized argument: %s"), argv[1]);
  
        if (rev.diffopt.output_format & DIFF_FORMAT_NAME)
 -              die("--name-only does not make sense");
 +              die(_("--name-only does not make sense"));
        if (rev.diffopt.output_format & DIFF_FORMAT_NAME_STATUS)
 -              die("--name-status does not make sense");
 +              die(_("--name-status does not make sense"));
        if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
 -              die("--check does not make sense");
 +              die(_("--check does not make sense"));
  
        if (!use_patch_format &&
                (!rev.diffopt.output_format ||
  
        if (output_directory) {
                if (use_stdout)
 -                      die("standard output, or directory, which one?");
 +                      die(_("standard output, or directory, which one?"));
                if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
 -                      die_errno("Could not create directory '%s'",
 +                      die_errno(_("Could not create directory '%s'"),
                                  output_directory);
        }
  
                realstdout = xfdopen(xdup(1), "w");
  
        if (prepare_revision_walk(&rev))
 -              die("revision walk setup failed");
 +              die(_("revision walk setup failed"));
        rev.boundary = 1;
        while ((commit = get_revision(&rev)) != NULL) {
                if (commit->object.flags & BOUNDARY) {
                if (thread)
                        gen_message_id(&rev, "cover");
                make_cover_letter(&rev, use_stdout, numbered, numbered_files,
 -                                origin, nr, list, head);
 +                                origin, nr, list, head, quiet);
                total++;
                start_number--;
        }
                }
  
                if (!use_stdout && reopen_stdout(numbered_files ? NULL : commit,
 -                                               &rev))
 -                      die("Failed to create output files");
 +                                               &rev, quiet))
 +                      die(_("Failed to create output files"));
                shown = log_tree_commit(&rev, commit);
                free(commit->buffer);
                commit->buffer = NULL;
@@@ -1375,23 -1354,6 +1377,23 @@@ static const char * const cherry_usage[
        NULL
  };
  
 +static void print_commit(char sign, struct commit *commit, int verbose,
 +                       int abbrev)
 +{
 +      if (!verbose) {
 +              printf("%c %s\n", sign,
 +                     find_unique_abbrev(commit->object.sha1, abbrev));
 +      } else {
 +              struct strbuf buf = STRBUF_INIT;
 +              struct pretty_print_context ctx = {0};
 +              pretty_print_commit(CMIT_FMT_ONELINE, commit, &buf, &ctx);
 +              printf("%c %s %s\n", sign,
 +                     find_unique_abbrev(commit->object.sha1, abbrev),
 +                     buf.buf);
 +              strbuf_release(&buf);
 +      }
 +}
 +
  int cmd_cherry(int argc, const char **argv, const char *prefix)
  {
        struct rev_info revs;
                if (!current_branch || !current_branch->merge
                                        || !current_branch->merge[0]
                                        || !current_branch->merge[0]->dst) {
 -                      fprintf(stderr, "Could not find a tracked"
 +                      fprintf(stderr, _("Could not find a tracked"
                                        " remote branch, please"
 -                                      " specify <upstream> manually.\n");
 +                                      " specify <upstream> manually.\n"));
                        usage_with_options(cherry_usage, options);
                }
  
        DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
  
        if (add_pending_commit(head, &revs, 0))
 -              die("Unknown commit %s", head);
 +              die(_("Unknown commit %s"), head);
        if (add_pending_commit(upstream, &revs, UNINTERESTING))
 -              die("Unknown commit %s", upstream);
 +              die(_("Unknown commit %s"), upstream);
  
        /* Don't say anything if head and upstream are the same. */
        if (revs.pending.nr == 2) {
        get_patch_ids(&revs, &ids, prefix);
  
        if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
 -              die("Unknown commit %s", limit);
 +              die(_("Unknown commit %s"), limit);
  
        /* reverse the list of commits */
        if (prepare_revision_walk(&revs))
 -              die("revision walk setup failed");
 +              die(_("revision walk setup failed"));
        while ((commit = get_revision(&revs)) != NULL) {
                /* ignore merges */
                if (commit->parents && commit->parents->next)
                commit = list->item;
                if (has_commit_patch_id(commit, &ids))
                        sign = '-';
 -
 -              if (verbose) {
 -                      struct strbuf buf = STRBUF_INIT;
 -                      struct pretty_print_context ctx = {0};
 -                      pretty_print_commit(CMIT_FMT_ONELINE, commit,
 -                                          &buf, &ctx);
 -                      printf("%c %s %s\n", sign,
 -                             find_unique_abbrev(commit->object.sha1, abbrev),
 -                             buf.buf);
 -                      strbuf_release(&buf);
 -              }
 -              else {
 -                      printf("%c %s\n", sign,
 -                             find_unique_abbrev(commit->object.sha1, abbrev));
 -              }
 -
 +              print_commit(sign, commit, verbose, abbrev);
                list = list->next;
        }
  
diff --combined cache.h
index 28899b7b7881474eed4a6f3b6fda8db79d5cbc9c,43d719d71f233c7b433f7097864a147010267e18..5b896d9845bca12c2c1486618e653491f08617c3
+++ b/cache.h
@@@ -5,7 -5,6 +5,7 @@@
  #include "strbuf.h"
  #include "hash.h"
  #include "advice.h"
 +#include "gettext.h"
  
  #include SHA1_HEADER
  #ifndef git_SHA_CTX
@@@ -437,7 -436,6 +437,7 @@@ extern void verify_non_filename(const c
  
  #define INIT_DB_QUIET 0x0001
  
 +extern int set_git_dir_init(const char *git_dir, const char *real_git_dir, int);
  extern int init_db(const char *template_dir, unsigned int flags);
  
  #define alloc_nr(x) (((x)+16)*3/2)
@@@ -511,14 -509,14 +511,14 @@@ struct pathspec 
        struct pathspec_item {
                const char *match;
                int len;
-               unsigned int has_wildcard:1;
+               unsigned int use_wildcard:1;
        } *items;
  };
  
  extern int init_pathspec(struct pathspec *, const char **);
  extern void free_pathspec(struct pathspec *);
  extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
 -extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
 +extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path, int format_check);
  extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
  extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
  
  #define REFRESH_IGNORE_MISSING        0x0008  /* ignore non-existent */
  #define REFRESH_IGNORE_SUBMODULES     0x0010  /* ignore submodules */
  #define REFRESH_IN_PORCELAIN  0x0020  /* user friendly output, not "needs update" */
 -extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, char *header_msg);
 +extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, const char *header_msg);
  
  struct lock_file {
        struct lock_file *next;
@@@ -544,7 -542,6 +544,7 @@@ extern NORETURN void unable_to_lock_ind
  extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
  extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
  extern int commit_lock_file(struct lock_file *);
 +extern void update_index_if_able(struct index_state *, struct lock_file *);
  
  extern int hold_locked_index(struct lock_file *, int);
  extern int commit_locked_index(struct lock_file *);
@@@ -558,12 -555,12 +558,12 @@@ extern int trust_executable_bit
  extern int trust_ctime;
  extern int quote_path_fully;
  extern int has_symlinks;
 +extern int minimum_abbrev, default_abbrev;
  extern int ignore_case;
  extern int assume_unchanged;
  extern int prefer_symlink_refs;
  extern int log_all_ref_updates;
  extern int warn_ambiguous_refs;
 -extern int unique_abbrev_extra_length;
  extern int shared_repository;
  extern const char *apply_default_whitespace;
  extern const char *apply_default_ignorewhitespace;
@@@ -573,7 -570,6 +573,7 @@@ extern int core_compression_seen
  extern size_t packed_git_window_size;
  extern size_t packed_git_limit;
  extern size_t delta_base_cache_limit;
 +extern unsigned long big_file_threshold;
  extern int read_replace_refs;
  extern int fsync_object_files;
  extern int core_preload_index;
@@@ -590,7 -586,7 +590,7 @@@ extern enum safe_crlf safe_crlf
  enum auto_crlf {
        AUTO_CRLF_FALSE = 0,
        AUTO_CRLF_TRUE = 1,
 -      AUTO_CRLF_INPUT = -1,
 +      AUTO_CRLF_INPUT = -1
  };
  
  extern enum auto_crlf auto_crlf;
@@@ -627,7 -623,7 +627,7 @@@ enum rebase_setup_type 
  enum push_default_type {
        PUSH_DEFAULT_NOTHING = 0,
        PUSH_DEFAULT_MATCHING,
 -      PUSH_DEFAULT_TRACKING,
 +      PUSH_DEFAULT_UPSTREAM,
        PUSH_DEFAULT_CURRENT
  };
  
@@@ -695,11 -691,9 +695,11 @@@ static inline void hashclr(unsigned cha
  
  #define EMPTY_TREE_SHA1_HEX \
        "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
 -#define EMPTY_TREE_SHA1_BIN \
 +#define EMPTY_TREE_SHA1_BIN_LITERAL \
         "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
         "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
 +#define EMPTY_TREE_SHA1_BIN \
 +       ((const unsigned char *) EMPTY_TREE_SHA1_BIN_LITERAL)
  
  int git_mkstemp(char *path, size_t n, const char *template);
  
@@@ -729,7 -723,6 +729,7 @@@ int set_shared_perm(const char *path, i
  #define adjust_shared_perm(path) set_shared_perm((path), 0)
  int safe_create_leading_directories(char *path);
  int safe_create_leading_directories_const(const char *path);
 +int mkdir_in_gitdir(const char *path);
  extern char *expand_user_path(const char *path);
  char *enter_repo(char *path, int strict);
  static inline int is_absolute_path(const char *path)
        return path[0] == '/' || has_dos_drive_prefix(path);
  }
  int is_directory(const char *);
 -const char *make_absolute_path(const char *path);
 -const char *make_nonrelative_path(const char *path);
 -const char *make_relative_path(const char *abs, const char *base);
 +const char *real_path(const char *path);
 +const char *absolute_path(const char *path);
 +const char *relative_path(const char *abs, const char *base);
  int normalize_path_copy(char *dst, const char *src);
  int longest_ancestor_length(const char *path, const char *prefix_list);
  char *strip_path_suffix(const char *path, const char *suffix);
@@@ -780,8 -773,8 +780,8 @@@ static inline unsigned int hexval(unsig
  }
  
  /* Convert to/from hex/sha1 representation */
 -#define MINIMUM_ABBREV 4
 -#define DEFAULT_ABBREV 7
 +#define MINIMUM_ABBREV minimum_abbrev
 +#define DEFAULT_ABBREV default_abbrev
  
  struct object_context {
        unsigned char tree[20];
@@@ -919,8 -912,7 +919,8 @@@ extern struct packed_git 
        time_t mtime;
        int pack_fd;
        unsigned pack_local:1,
 -               pack_keep:1;
 +               pack_keep:1,
 +               do_not_close:1;
        unsigned char sha1[20];
        /* something like ".git/objects/pack/xxxxx.pack" */
        char pack_name[FLEX_ARRAY]; /* more */
@@@ -1020,13 -1012,13 +1020,13 @@@ extern int git_config_maybe_bool(const 
  extern int git_config_string(const char **, const char *, const char *);
  extern int git_config_pathname(const char **, const char *, const char *);
  extern int git_config_set(const char *, const char *);
 +extern int git_config_parse_key(const char *, char **, int *);
  extern int git_config_set_multivar(const char *, const char *, const char *, int);
  extern int git_config_rename_section(const char *, const char *);
  extern const char *git_etc_gitconfig(void);
  extern int check_repository_format_version(const char *var, const char *value, void *cb);
  extern int git_env_bool(const char *, int);
  extern int git_config_system(void);
 -extern int git_config_global(void);
  extern int config_error_nonbool(const char *);
  extern const char *get_log_output_encoding(void);
  extern const char *get_commit_output_encoding(void);
@@@ -1088,14 -1080,9 +1088,14 @@@ extern void alloc_report(void)
  /* trace.c */
  __attribute__((format (printf, 1, 2)))
  extern void trace_printf(const char *format, ...);
 +extern void trace_vprintf(const char *key, const char *format, va_list ap);
  __attribute__((format (printf, 2, 3)))
  extern void trace_argv_printf(const char **argv, const char *format, ...);
  extern void trace_repo_setup(const char *prefix);
 +extern int trace_want(const char *key);
 +extern void trace_strbuf(const char *key, const struct strbuf *buf);
 +
 +void packet_trace_identity(const char *prog);
  
  /* convert.c */
  /* returns 1 if *dst was used */
diff --combined dir.c
index 9789bd204ef33c0623e6576c5afd533786fcd406,91f1502ac6827a2f4392561d0314f41898dcfb5d..08281d2ef74ea7790913e71f08d00299a1825765
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -230,7 -230,7 +230,7 @@@ static int match_pathspec_item(const st
                        return MATCHED_RECURSIVELY;
        }
  
-       if (item->has_wildcard && !fnmatch(match, name, 0))
+       if (item->use_wildcard && !fnmatch(match, name, 0))
                return MATCHED_FNMATCH;
  
        return 0;
@@@ -1105,45 -1105,57 +1105,45 @@@ int file_exists(const char *f
  }
  
  /*
 - * get_relative_cwd() gets the prefix of the current working directory
 - * relative to 'dir'.  If we are not inside 'dir', it returns NULL.
 - *
 - * As a convenience, it also returns NULL if 'dir' is already NULL.  The
 - * reason for this behaviour is that it is natural for functions returning
 - * directory names to return NULL to say "this directory does not exist"
 - * or "this directory is invalid".  These cases are usually handled the
 - * same as if the cwd is not inside 'dir' at all, so get_relative_cwd()
 - * returns NULL for both of them.
 - *
 - * Most notably, get_relative_cwd(buffer, size, get_git_work_tree())
 - * unifies the handling of "outside work tree" with "no work tree at all".
 + * Given two normalized paths (a trailing slash is ok), if subdir is
 + * outside dir, return -1.  Otherwise return the offset in subdir that
 + * can be used as relative path to dir.
   */
 -char *get_relative_cwd(char *buffer, int size, const char *dir)
 +int dir_inside_of(const char *subdir, const char *dir)
  {
 -      char *cwd = buffer;
 -
 -      if (!dir)
 -              return NULL;
 -      if (!getcwd(buffer, size))
 -              die_errno("can't find the current directory");
 +      int offset = 0;
  
 -      if (!is_absolute_path(dir))
 -              dir = make_absolute_path(dir);
 +      assert(dir && subdir && *dir && *subdir);
  
 -      while (*dir && *dir == *cwd) {
 +      while (*dir && *subdir && *dir == *subdir) {
                dir++;
 -              cwd++;
 -      }
 -      if (*dir)
 -              return NULL;
 -      switch (*cwd) {
 -      case '\0':
 -              return cwd;
 -      case '/':
 -              return cwd + 1;
 -      default:
 -              /*
 -               * dir can end with a path separator when it's root
 -               * directory. Return proper prefix in that case.
 -               */
 -              if (dir[-1] == '/')
 -                      return cwd;
 -              return NULL;
 +              subdir++;
 +              offset++;
        }
 +
 +      /* hel[p]/me vs hel[l]/yeah */
 +      if (*dir && *subdir)
 +              return -1;
 +
 +      if (!*subdir)
 +              return !*dir ? offset : -1; /* same dir */
 +
 +      /* foo/[b]ar vs foo/[] */
 +      if (is_dir_sep(dir[-1]))
 +              return is_dir_sep(subdir[-1]) ? offset : -1;
 +
 +      /* foo[/]bar vs foo[] */
 +      return is_dir_sep(*subdir) ? offset + 1 : -1;
  }
  
  int is_inside_dir(const char *dir)
  {
 -      char buffer[PATH_MAX];
 -      return get_relative_cwd(buffer, sizeof(buffer), dir) != NULL;
 +      char cwd[PATH_MAX];
 +      if (!dir)
 +              return 0;
 +      if (!getcwd(cwd, sizeof(cwd)))
 +              die_errno("can't find the current directory");
 +      return dir_inside_of(cwd, dir) >= 0;
  }
  
  int is_empty_dir(const char *path)
@@@ -1180,7 -1192,7 +1180,7 @@@ int remove_dir_recursively(struct strbu
  
        dir = opendir(path->buf);
        if (!dir)
 -              return -1;
 +              return rmdir(path->buf);
        if (path->buf[original_len - 1] != '/')
                strbuf_addch(path, '/');
  
@@@ -1274,8 -1286,8 +1274,8 @@@ int init_pathspec(struct pathspec *path
  
                item->match = path;
                item->len = strlen(path);
-               item->has_wildcard = !no_wildcard(path);
-               if (item->has_wildcard)
+               item->use_wildcard = !no_wildcard(path);
+               if (item->use_wildcard)
                        pathspec->has_wildcard = 1;
        }
  
diff --combined list-objects.c
index 838b6a732e4758265432cbc9c8e8fc81568a2b50,cf9dbe23e468948992db8d163f5b9395246ea5b8..0fb44e7ed7e8d7a98b8609778191715148f56c8d
@@@ -68,7 -68,7 +68,7 @@@ static void process_tree(struct rev_inf
        struct tree_desc desc;
        struct name_entry entry;
        struct name_path me;
-       int all_interesting = (revs->diffopt.pathspec.nr == 0);
+       int match = revs->diffopt.pathspec.nr == 0 ? 2 : 0;
        int baselen = base->len;
  
        if (!revs->tree_objects)
@@@ -85,7 -85,7 +85,7 @@@
        me.elem = name;
        me.elem_len = strlen(name);
  
-       if (!all_interesting) {
+       if (!match) {
                strbuf_addstr(base, name);
                if (base->len)
                        strbuf_addch(base, '/');
        init_tree_desc(&desc, tree->buffer, tree->size);
  
        while (tree_entry(&desc, &entry)) {
-               if (!all_interesting) {
-                       int showit = tree_entry_interesting(&entry,
-                                                           base, 0,
-                                                           &revs->diffopt.pathspec);
-                       if (showit < 0)
+               if (match != 2) {
+                       match = tree_entry_interesting(&entry, base, 0,
+                                                      &revs->diffopt.pathspec);
+                       if (match < 0)
                                break;
-                       else if (!showit)
+                       if (match == 0)
                                continue;
-                       else if (showit == 2)
-                               all_interesting = 1;
                }
  
                if (S_ISDIR(entry.mode))
@@@ -173,12 -169,7 +169,12 @@@ void traverse_commit_list(struct rev_in
  
        strbuf_init(&base, PATH_MAX);
        while ((commit = get_revision(revs)) != NULL) {
 -              add_pending_tree(revs, commit->tree);
 +              /*
 +               * an uninteresting boundary commit may not have its tree
 +               * parsed yet, but we are not going to show them anyway
 +               */
 +              if (commit->tree)
 +                      add_pending_tree(revs, commit->tree);
                show_commit(commit, data);
        }
        for (i = 0; i < revs->pending.nr; i++) {
diff --combined merge-recursive.c
index fb3c874ff47c949dc8df89edb320accf90bc8ac9,0645138ae5424ff2652f464c0f6fb9a6965d80e5..ecb1806cad19bcc69c6dbf8528561eefffab15b2
@@@ -83,8 -83,10 +83,8 @@@ struct rename_df_conflict_info 
   * Since we want to write the index eventually, we cannot reuse the index
   * for these (temporary) data.
   */
 -struct stage_data
 -{
 -      struct
 -      {
 +struct stage_data {
 +      struct {
                unsigned mode;
                unsigned char sha[20];
        } stages[4];
@@@ -135,6 -137,7 +135,6 @@@ static void flush_output(struct merge_o
  __attribute__((format (printf, 3, 4)))
  static void output(struct merge_options *o, int v, const char *fmt, ...)
  {
 -      int len;
        va_list ap;
  
        if (!show(o, v))
        strbuf_setlen(&o->obuf, o->obuf.len + o->call_depth * 2);
  
        va_start(ap, fmt);
 -      len = vsnprintf(o->obuf.buf + o->obuf.len, strbuf_avail(&o->obuf), fmt, ap);
 +      strbuf_vaddf(&o->obuf, fmt, ap);
        va_end(ap);
  
 -      if (len < 0)
 -              len = 0;
 -      if (len >= strbuf_avail(&o->obuf)) {
 -              strbuf_grow(&o->obuf, len + 2);
 -              va_start(ap, fmt);
 -              len = vsnprintf(o->obuf.buf + o->obuf.len, strbuf_avail(&o->obuf), fmt, ap);
 -              va_end(ap);
 -              if (len >= strbuf_avail(&o->obuf)) {
 -                      die("this should not happen, your snprintf is broken");
 -              }
 -      }
 -      strbuf_setlen(&o->obuf, o->obuf.len + len);
        strbuf_add(&o->obuf, "\n", 1);
        if (!o->buffer_output)
                flush_output(o);
@@@ -273,7 -288,9 +273,9 @@@ static int save_files_dirs(const unsign
  static int get_files_dirs(struct merge_options *o, struct tree *tree)
  {
        int n;
-       if (read_tree_recursive(tree, "", 0, 0, NULL, save_files_dirs, o))
+       struct pathspec match_all;
+       init_pathspec(&match_all, NULL);
+       if (read_tree_recursive(tree, "", 0, 0, &match_all, save_files_dirs, o))
                return 0;
        n = o->current_file_set.nr + o->current_directory_set.nr;
        return n;
@@@ -339,11 -356,10 +341,11 @@@ static void make_room_for_directories_o
         * make room for the corresponding directory.  Such paths will
         * later be processed in process_df_entry() at the end.  If
         * the corresponding directory ends up being removed by the
 -       * merge, then the file will be reinstated at that time;
 -       * otherwise, if the file is not supposed to be removed by the
 -       * merge, the contents of the file will be placed in another
 -       * unique filename.
 +       * merge, then the file will be reinstated at that time
 +       * (albeit with a different timestamp!); otherwise, if the
 +       * file is not supposed to be removed by the merge, the
 +       * contents of the file will be placed in another unique
 +       * filename.
         *
         * NOTE: This function relies on the fact that entries for a
         * D/F conflict will appear adjacent in the index, with the
         */
        const char *last_file = NULL;
        int last_len = 0;
 -      struct stage_data *last_e;
        int i;
  
 +      /*
 +       * Do not do any of this crazyness during the recursive; we don't
 +       * even write anything to the working tree!
 +       */
 +      if (o->call_depth)
 +              return;
 +
        for (i = 0; i < entries->nr; i++) {
                const char *path = entries->items[i].string;
                int len = strlen(path);
                if (S_ISREG(e->stages[2].mode) || S_ISLNK(e->stages[2].mode)) {
                        last_file = path;
                        last_len = len;
 -                      last_e = e;
                } else {
                        last_file = NULL;
                }
        }
  }
  
 -struct rename
 -{
 +struct rename {
        struct diff_filepair *pair;
        struct stage_data *src_entry;
        struct stage_data *dst_entry;
@@@ -424,16 -436,14 +426,16 @@@ static struct string_list *get_renames(
        opts.detect_rename = DIFF_DETECT_RENAME;
        opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
                            o->diff_rename_limit >= 0 ? o->diff_rename_limit :
 -                          500;
 +                          1000;
        opts.rename_score = o->rename_score;
 -      opts.warn_on_too_large_rename = 1;
 +      opts.show_rename_progress = o->show_rename_progress;
        opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        if (diff_setup_done(&opts) < 0)
                die("diff setup failed");
        diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts);
        diffcore_std(&opts);
 +      if (opts.needed_rename_limit > o->needed_rename_limit)
 +              o->needed_rename_limit = opts.needed_rename_limit;
        for (i = 0; i < diff_queued_diff.nr; ++i) {
                struct string_list_item *item;
                struct rename *re;
@@@ -709,7 -719,8 +711,7 @@@ static void update_file(struct merge_op
  
  /* Low level file merging, update and removal */
  
 -struct merge_file_info
 -{
 +struct merge_file_info {
        unsigned char sha[20];
        unsigned mode;
        unsigned clean:1,
@@@ -962,6 -973,7 +964,6 @@@ static int process_renames(struct merge
        }
  
        for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) {
 -              char *src;
                struct string_list *renames1, *renames2Dst;
                struct rename *ren1 = NULL, *ren2 = NULL;
                const char *branch1, *branch2;
                        ren2 = ren1;
                        ren1 = tmp;
                }
 -              src = ren1->pair->one->path;
  
                ren1->dst_entry->processed = 1;
                ren1->src_entry->processed = 1;
@@@ -1263,13 -1276,9 +1265,13 @@@ static int merge_content(struct merge_o
        }
  
        if (mfi.clean && !df_conflict_remains &&
 -          sha_eq(mfi.sha, a_sha) && mfi.mode == a.mode)
 +          sha_eq(mfi.sha, a_sha) && mfi.mode == a.mode &&
 +          !o->call_depth && !lstat(path, &st)) {
                output(o, 3, "Skipped %s (merged same as existing)", path);
 -      else
 +              add_cacheinfo(mfi.mode, mfi.sha, path,
 +                            0 /*stage*/, 1 /*refresh*/, 0 /*options*/);
 +              return mfi.clean;
 +      } else
                output(o, 2, "Auto-merging %s", path);
  
        if (!mfi.clean) {
@@@ -1659,9 -1668,6 +1661,9 @@@ int merge_recursive(struct merge_option
                commit_list_insert(h2, &(*result)->parents->next);
        }
        flush_output(o);
 +      if (show(o, 2))
 +              diff_warn_rename_limit("merge.renamelimit",
 +                                     o->needed_rename_limit, 0);
        return clean;
  }
  
diff --combined tree-diff.c
index 76f83fcc27e50b12ddbc8f72badd8d29f5b4230d,f291069bc3ab64158064a46fb25633e6347121e7..3f4072525b9489a86b2231748abe13c611e05274
@@@ -17,6 -17,7 +17,6 @@@ static int compare_tree_entry(struct tr
        const unsigned char *sha1, *sha2;
        int cmp, pathlen1, pathlen2;
        int old_baselen = base->len;
 -      int retval = 0;
  
        sha1 = tree_entry_extract(t1, &path1, &mode1);
        sha2 = tree_entry_extract(t2, &path2, &mode2);
@@@ -52,7 -53,7 +52,7 @@@
                                    sha1, sha2, base->buf, 0, 0);
                }
                strbuf_addch(base, '/');
 -              retval = diff_tree_sha1(sha1, sha2, base->buf, opt);
 +              diff_tree_sha1(sha1, sha2, base->buf, opt);
        } else {
                opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0);
        }
  static void show_tree(struct diff_options *opt, const char *prefix,
                      struct tree_desc *desc, struct strbuf *base)
  {
-       int all_interesting = 0;
-       while (desc->size) {
-               int show;
-               if (all_interesting)
-                       show = 1;
-               else {
-                       show = tree_entry_interesting(&desc->entry, base, 0,
-                                                     &opt->pathspec);
-                       if (show == 2)
-                               all_interesting = 1;
+       int match = 0;
+       for (; desc->size; update_tree_entry(desc)) {
+               if (match != 2) {
+                       match = tree_entry_interesting(&desc->entry, base, 0,
+                                                      &opt->pathspec);
+                       if (match < 0)
+                               break;
+                       if (match == 0)
+                               continue;
                }
-               if (show < 0)
-                       break;
-               if (show)
-                       show_entry(opt, prefix, desc, base);
-               update_tree_entry(desc);
+               show_entry(opt, prefix, desc, base);
        }
  }
  
@@@ -120,20 -115,16 +114,16 @@@ static void show_entry(struct diff_opti
  }
  
  static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
-                              struct diff_options *opt, int *all_interesting)
+                              struct diff_options *opt, int *match)
  {
        while (t->size) {
-               int show = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);
-               if (show == 2)
-                       *all_interesting = 1;
-               if (!show) {
-                       update_tree_entry(t);
-                       continue;
+               *match = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);
+               if (*match) {
+                       if (*match < 0)
+                               t->size = 0;
+                       break;
                }
-               /* Skip it all? */
-               if (show < 0)
-                       t->size = 0;
-               return;
+               update_tree_entry(t);
        }
  }
  
@@@ -142,8 -133,7 +132,7 @@@ int diff_tree(struct tree_desc *t1, str
  {
        struct strbuf base;
        int baselen = strlen(base_str);
-       int all_t1_interesting = 0;
-       int all_t2_interesting = 0;
+       int t1_match = 0, t2_match = 0;
  
        /* Enable recursion indefinitely */
        opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
                    DIFF_OPT_TST(opt, HAS_CHANGES))
                        break;
                if (opt->pathspec.nr) {
-                       if (!all_t1_interesting)
-                               skip_uninteresting(t1, &base, opt, &all_t1_interesting);
-                       if (!all_t2_interesting)
-                               skip_uninteresting(t2, &base, opt, &all_t2_interesting);
+                       skip_uninteresting(t1, &base, opt, &t1_match);
+                       skip_uninteresting(t2, &base, opt, &t2_match);
                }
                if (!t1->size) {
                        if (!t2->size)