Merge branch 'nd/i18n'
authorJunio C Hamano <gitster@pobox.com>
Wed, 15 Aug 2018 22:08:23 +0000 (15:08 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 15 Aug 2018 22:08:23 +0000 (15:08 -0700)
Many more strings are prepared for l10n.

* nd/i18n: (23 commits)
transport-helper.c: mark more strings for translation
transport.c: mark more strings for translation
sha1-file.c: mark more strings for translation
sequencer.c: mark more strings for translation
replace-object.c: mark more strings for translation
refspec.c: mark more strings for translation
refs.c: mark more strings for translation
pkt-line.c: mark more strings for translation
object.c: mark more strings for translation
exec-cmd.c: mark more strings for translation
environment.c: mark more strings for translation
dir.c: mark more strings for translation
convert.c: mark more strings for translation
connect.c: mark more strings for translation
config.c: mark more strings for translation
commit-graph.c: mark more strings for translation
builtin/replace.c: mark more strings for translation
builtin/pack-objects.c: mark more strings for translation
builtin/grep.c: mark strings for translation
builtin/config.c: mark more strings for translation
...

33 files changed:
1  2 
archive-tar.c
archive-zip.c
builtin/blame.c
builtin/checkout.c
builtin/commit.c
builtin/config.c
builtin/fast-export.c
builtin/fmt-merge-msg.c
builtin/grep.c
builtin/log.c
builtin/merge.c
builtin/pack-objects.c
builtin/replace.c
commit-graph.c
config.c
convert.c
diff.c
dir.c
environment.c
object.c
reflog-walk.c
refs.c
replace-object.c
sequencer.c
sha1-file.c
t/t0021-conversion.sh
t/t3210-pack-refs.sh
t/t5500-fetch-pack.sh
t/t5505-remote.sh
t/t5801-remote-helpers.sh
t/t7400-submodule-basic.sh
transport-helper.c
transport.c
diff --combined archive-tar.c
index 7df85652463c6cee150398a00e93e03905861b96,68e72d91765c64a98646bc503b17ead64ef61692..0bc50f6e8944243c4f66659786beb63d6df48df6
@@@ -5,7 -5,6 +5,7 @@@
  #include "config.h"
  #include "tar.h"
  #include "archive.h"
 +#include "object-store.h"
  #include "streaming.h"
  #include "run-command.h"
  
@@@ -122,7 -121,7 +122,7 @@@ static int stream_blocked(const struct 
  
        st = open_istream(oid, &type, &sz, NULL);
        if (!st)
-               return error("cannot stream blob %s", oid_to_hex(oid));
+               return error(_("cannot stream blob %s"), oid_to_hex(oid));
        for (;;) {
                readlen = read_istream(st, buf, sizeof(buf));
                if (readlen <= 0)
@@@ -257,7 -256,7 +257,7 @@@ static int write_tar_entry(struct archi
                *header.typeflag = TYPEFLAG_REG;
                mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;
        } else {
-               return error("unsupported file mode: 0%o (SHA1: %s)",
+               return error(_("unsupported file mode: 0%o (SHA1: %s)"),
                             mode, oid_to_hex(oid));
        }
        if (pathlen > sizeof(header.name)) {
                enum object_type type;
                buffer = object_file_to_archive(args, path, oid, old_mode, &type, &size);
                if (!buffer)
-                       return error("cannot read %s", oid_to_hex(oid));
+                       return error(_("cannot read %s"), oid_to_hex(oid));
        } else {
                buffer = NULL;
                size = 0;
@@@ -455,17 -454,17 +455,17 @@@ static int write_tar_filter_archive(con
        filter.in = -1;
  
        if (start_command(&filter) < 0)
-               die_errno("unable to start '%s' filter", argv[0]);
+               die_errno(_("unable to start '%s' filter"), argv[0]);
        close(1);
        if (dup2(filter.in, 1) < 0)
-               die_errno("unable to redirect descriptor");
+               die_errno(_("unable to redirect descriptor"));
        close(filter.in);
  
        r = write_tar_archive(ar, args);
  
        close(1);
        if (finish_command(&filter) != 0)
-               die("'%s' filter reported error", argv[0]);
+               die(_("'%s' filter reported error"), argv[0]);
  
        strbuf_release(&cmd);
        return r;
diff --combined archive-zip.c
index abc556e5a7506cd0fe8e1e66a83c3781bfc04104,7ad46d8854d2d3d8c9681ff4933b348616b8f774..024267ff0f771a73d4e80dec32934a8e5b8455f5
@@@ -6,7 -6,6 +6,7 @@@
  #include "archive.h"
  #include "streaming.h"
  #include "utf8.h"
 +#include "object-store.h"
  #include "userdiff.h"
  #include "xdiff-interface.h"
  
@@@ -310,11 -309,11 +310,11 @@@ static int write_zip_entry(struct archi
                if (is_utf8(path))
                        flags |= ZIP_UTF8;
                else
-                       warning("Path is not valid UTF-8: %s", path);
+                       warning(_("path is not valid UTF-8: %s"), path);
        }
  
        if (pathlen > 0xffff) {
-               return error("path too long (%d chars, SHA1: %s): %s",
+               return error(_("path too long (%d chars, SHA1: %s): %s"),
                                (int)pathlen, oid_to_hex(oid), path);
        }
  
                    size > big_file_threshold) {
                        stream = open_istream(oid, &type, &size, NULL);
                        if (!stream)
-                               return error("cannot stream blob %s",
+                               return error(_("cannot stream blob %s"),
                                             oid_to_hex(oid));
                        flags |= ZIP_STREAM;
                        out = buffer = NULL;
                        buffer = object_file_to_archive(args, path, oid, mode,
                                                        &type, &size);
                        if (!buffer)
-                               return error("cannot read %s",
+                               return error(_("cannot read %s"),
                                             oid_to_hex(oid));
                        crc = crc32(crc, buffer, size);
                        is_binary = entry_is_binary(path_without_prefix,
                }
                compressed_size = (method == 0) ? size : 0;
        } else {
-               return error("unsupported file mode: 0%o (SHA1: %s)", mode,
+               return error(_("unsupported file mode: 0%o (SHA1: %s)"), mode,
                                oid_to_hex(oid));
        }
  
                        zstream.avail_in = readlen;
                        result = git_deflate(&zstream, 0);
                        if (result != Z_OK)
-                               die("deflate error (%d)", result);
+                               die(_("deflate error (%d)"), result);
                        out_len = zstream.next_out - compressed;
  
                        if (out_len > 0) {
@@@ -602,7 -601,7 +602,7 @@@ static void dos_time(timestamp_t *times
        struct tm *t;
  
        if (date_overflows(*timestamp))
-               die("timestamp too large for this system: %"PRItime,
+               die(_("timestamp too large for this system: %"PRItime),
                    *timestamp);
        time = (time_t)*timestamp;
        t = localtime(&time);
diff --combined builtin/blame.c
index 5c93d169dd431b666b25086ac4bb5303e8b26309,b77ba6ae82c6bfa6dfe87bfccad6d2fa2bc09b86..97f6ecaf370dfdda1f0a9e5a1fe824a034fdbf61
@@@ -9,7 -9,6 +9,7 @@@
  #include "config.h"
  #include "color.h"
  #include "builtin.h"
 +#include "repository.h"
  #include "commit.h"
  #include "diff.h"
  #include "revision.h"
@@@ -24,7 -23,6 +24,7 @@@
  #include "line-log.h"
  #include "dir.h"
  #include "progress.h"
 +#include "object-store.h"
  #include "blame.h"
  #include "string-list.h"
  
@@@ -410,7 -408,7 +410,7 @@@ static void parse_color_fields(const ch
        }
  
        if (next == EXPECT_COLOR)
-               die (_("must end with a color"));
+               die(_("must end with a color"));
  
        colorfield[colorfield_nr].hop = TIME_MAX;
        string_list_clear(&l, 0);
@@@ -578,7 -576,7 +578,7 @@@ static int read_ancestry(const char *gr
                /* The format is just "Commit Parent1 Parent2 ...\n" */
                struct commit_graft *graft = read_graft_line(&buf);
                if (graft)
 -                      register_commit_graft(graft, 0);
 +                      register_commit_graft(the_repository, graft, 0);
        }
        fclose(fp);
        strbuf_release(&buf);
@@@ -1002,13 -1000,13 +1002,13 @@@ parse_done
                                    nth_line_cb, &sb, lno, anchor,
                                    &bottom, &top, sb.path))
                        usage(blame_usage);
 -              if (lno < top || ((lno || bottom) && lno < bottom))
 +              if ((!lno && (top || bottom)) || lno < bottom)
                        die(Q_("file %s has only %lu line",
                               "file %s has only %lu lines",
                               lno), path, lno);
                if (bottom < 1)
                        bottom = 1;
 -              if (top < 1)
 +              if (top < 1 || lno < top)
                        top = lno;
                bottom--;
                range_set_append_unsafe(&ranges, bottom, top);
                find_alignment(&sb, &output_option);
                if (!*repeated_meta_color &&
                    (output_option & OUTPUT_COLOR_LINE))
 -                      strcpy(repeated_meta_color, GIT_COLOR_CYAN);
 +                      xsnprintf(repeated_meta_color,
 +                                sizeof(repeated_meta_color),
 +                                "%s", GIT_COLOR_CYAN);
        }
        if (output_option & OUTPUT_ANNOTATE_COMPAT)
                output_option &= ~(OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR);
diff --combined builtin/checkout.c
index 516136a23a3d6962703186ca825e416cb653e677,626868637a612b4865e4dc89873932edd18e6fc3..cb6bb76312a00cbcf997ef44e43128964777e86e
@@@ -4,7 -4,6 +4,7 @@@
  #include "lockfile.h"
  #include "parse-options.h"
  #include "refs.h"
 +#include "object-store.h"
  #include "commit.h"
  #include "tree.h"
  #include "tree-walk.h"
@@@ -23,7 -22,6 +23,7 @@@
  #include "resolve-undo.h"
  #include "submodule-config.h"
  #include "submodule.h"
 +#include "advice.h"
  
  static const char * const checkout_usage[] = {
        N_("git checkout [<options>] <branch>"),
@@@ -79,7 -77,7 +79,7 @@@ static int update_some(const struct obj
                return READ_TREE_RECURSIVE;
  
        len = base->len + strlen(pathname);
 -      ce = xcalloc(1, cache_entry_size(len));
 +      ce = make_empty_cache_entry(&the_index, len);
        oidcpy(&ce->oid, oid);
        memcpy(ce->name, base->buf, base->len);
        memcpy(ce->name + base->len, pathname, len - base->len);
@@@ -98,7 -96,7 +98,7 @@@
                if (ce->ce_mode == old->ce_mode &&
                    !oidcmp(&ce->oid, &old->oid)) {
                        old->ce_flags |= CE_UPDATE;
 -                      free(ce);
 +                      discard_cache_entry(ce);
                        return 0;
                }
        }
@@@ -232,11 -230,11 +232,11 @@@ static int checkout_merged(int pos, con
        if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))
                die(_("Unable to add merge result for '%s'"), path);
        free(result_buf.ptr);
 -      ce = make_cache_entry(mode, oid.hash, path, 2, 0);
 +      ce = make_transient_cache_entry(mode, &oid, path, 2);
        if (!ce)
                die(_("make_cache_entry failed for path '%s'"), path);
        status = checkout_entry(ce, state, NULL);
 -      free(ce);
 +      discard_cache_entry(ce);
        return status;
  }
  
@@@ -380,7 -378,7 +380,7 @@@ static int checkout_paths(const struct 
                die(_("unable to write new index file"));
  
        read_ref_full("HEAD", 0, &rev, NULL);
 -      head = lookup_commit_reference_gently(&rev, 1);
 +      head = lookup_commit_reference_gently(the_repository, &rev, 1);
  
        errs |= post_checkout_hook(head, head, 0);
        return errs;
@@@ -831,7 -829,7 +831,7 @@@ static int switch_branches(const struc
        memset(&old_branch_info, 0, sizeof(old_branch_info));
        old_branch_info.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
        if (old_branch_info.path)
 -              old_branch_info.commit = lookup_commit_reference_gently(&rev, 1);
 +              old_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1);
        if (!(flag & REF_ISSYMREF))
                old_branch_info.path = NULL;
  
@@@ -880,8 -878,7 +880,8 @@@ static int parse_branchname_arg(int arg
                                int dwim_new_local_branch_ok,
                                struct branch_info *new_branch_info,
                                struct checkout_opts *opts,
 -                              struct object_id *rev)
 +                              struct object_id *rev,
 +                              int *dwim_remotes_matched)
  {
        struct tree **source_tree = &opts->source_tree;
        const char **new_branch = &opts->new_branch;
         *   (b) If <something> is _not_ a commit, either "--" is present
         *       or <something> is not a path, no -t or -b was given, and
         *       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.
 +       *       in one and only one remote (or if the branch exists on the
 +       *       remote named in checkout.defaultRemote), then this is a
 +       *       short-hand to fork local <something> from that
 +       *       remote-tracking branch.
         *
         *   (c) Otherwise, if "--" is present, treat it like case (1).
         *
                        recover_with_dwim = 0;
  
                if (recover_with_dwim) {
 -                      const char *remote = unique_tracking_name(arg, rev);
 +                      const char *remote = unique_tracking_name(arg, rev,
 +                                                                dwim_remotes_matched);
                        if (remote) {
                                *new_branch = arg;
                                arg = remote;
        else
                new_branch_info->path = NULL; /* not an existing branch */
  
 -      new_branch_info->commit = lookup_commit_reference_gently(rev, 1);
 +      new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1);
        if (!new_branch_info->commit) {
                /* not a commit */
                *source_tree = parse_tree_indirect(rev);
@@@ -1115,7 -1109,6 +1115,7 @@@ int cmd_checkout(int argc, const char *
        struct branch_info new_branch_info;
        char *conflict_style = NULL;
        int dwim_new_local_branch = 1;
 +      int dwim_remotes_matched = 0;
        struct option options[] = {
                OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
                OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
        if (opts.track != BRANCH_TRACK_UNSPECIFIED && !opts.new_branch) {
                const char *argv0 = argv[0];
                if (!argc || !strcmp(argv0, "--"))
-                       die (_("--track needs a branch name"));
+                       die(_("--track needs a branch name"));
                skip_prefix(argv0, "refs/", &argv0);
                skip_prefix(argv0, "remotes/", &argv0);
                argv0 = strchr(argv0, '/');
                if (!argv0 || !argv0[1])
-                       die (_("Missing branch name; try -b"));
+                       die(_("missing branch name; try -b"));
                opts.new_branch = argv0 + 1;
        }
  
                        opts.track == BRANCH_TRACK_UNSPECIFIED &&
                        !opts.new_branch;
                int n = parse_branchname_arg(argc, argv, dwim_ok,
 -                                           &new_branch_info, &opts, &rev);
 +                                           &new_branch_info, &opts, &rev,
 +                                           &dwim_remotes_matched);
                argv += n;
                argc -= n;
        }
        }
  
        UNLEAK(opts);
 -      if (opts.patch_mode || opts.pathspec.nr)
 -              return checkout_paths(&opts, new_branch_info.name);
 -      else
 +      if (opts.patch_mode || opts.pathspec.nr) {
 +              int ret = checkout_paths(&opts, new_branch_info.name);
 +              if (ret && dwim_remotes_matched > 1 &&
 +                  advice_checkout_ambiguous_remote_branch_name)
 +                      advise(_("'%s' matched more than one remote tracking branch.\n"
 +                               "We found %d remotes with a reference that matched. So we fell back\n"
 +                               "on trying to resolve the argument as a path, but failed there too!\n"
 +                               "\n"
 +                               "If you meant to check out a remote tracking branch on, e.g. 'origin',\n"
 +                               "you can do so by fully qualifying the name with the --track option:\n"
 +                               "\n"
 +                               "    git checkout --track origin/<name>\n"
 +                               "\n"
 +                               "If you'd like to always have checkouts of an ambiguous <name> prefer\n"
 +                               "one remote, e.g. the 'origin' remote, consider setting\n"
 +                               "checkout.defaultRemote=origin in your config."),
 +                             argv[0],
 +                             dwim_remotes_matched);
 +              return ret;
 +      } else {
                return checkout_branch(&opts, &new_branch_info);
 +      }
  }
diff --combined builtin/commit.c
index 158e3f843afbf889e26328f29cb2894f17da4ee1,d3276a10b2a09426f99cde3a43f07fc22136c72c..213fca2d8ecdf726661e6b31b7ec6cb004acb2f7
@@@ -168,9 -168,9 +168,9 @@@ static int opt_parse_rename_score(cons
  
  static void determine_whence(struct wt_status *s)
  {
 -      if (file_exists(git_path_merge_head()))
 +      if (file_exists(git_path_merge_head(the_repository)))
                whence = FROM_MERGE;
 -      else if (file_exists(git_path_cherry_pick_head())) {
 +      else if (file_exists(git_path_cherry_pick_head(the_repository))) {
                whence = FROM_CHERRY_PICK;
                if (file_exists(git_path_seq_dir()))
                        sequencer_in_use = 1;
@@@ -718,21 -718,21 +718,21 @@@ static int prepare_to_commit(const cha
                if (have_option_m)
                        strbuf_addbuf(&sb, &message);
                hook_arg1 = "message";
 -      } else if (!stat(git_path_merge_msg(), &statbuf)) {
 +      } else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
                /*
                 * prepend SQUASH_MSG here if it exists and a
                 * "merge --squash" was originally performed
                 */
 -              if (!stat(git_path_squash_msg(), &statbuf)) {
 -                      if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
 +              if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
 +                      if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
                                die_errno(_("could not read SQUASH_MSG"));
                        hook_arg1 = "squash";
                } else
                        hook_arg1 = "merge";
 -              if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0)
 +              if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
                        die_errno(_("could not read MERGE_MSG"));
 -      } else if (!stat(git_path_squash_msg(), &statbuf)) {
 -              if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
 +      } else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
 +              if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
                        die_errno(_("could not read SQUASH_MSG"));
                hook_arg1 = "squash";
        } else if (template_file) {
                                        "       %s\n"
                                        "and try again.\n"),
                                whence == FROM_MERGE ?
 -                                      git_path_merge_head() :
 -                                      git_path_cherry_pick_head());
 +                                      git_path_merge_head(the_repository) :
 +                                      git_path_cherry_pick_head(the_repository));
                }
  
                fprintf(s->fp, "\n");
@@@ -1564,7 -1564,7 +1564,7 @@@ int cmd_commit(int argc, const char **a
                if (!reflog_msg)
                        reflog_msg = "commit (merge)";
                pptr = commit_list_append(current_head, pptr);
 -              fp = xfopen(git_path_merge_head(), "r");
 +              fp = xfopen(git_path_merge_head(the_repository), "r");
                while (strbuf_getline_lf(&m, fp) != EOF) {
                        struct commit *parent;
  
                }
                fclose(fp);
                strbuf_release(&m);
 -              if (!stat(git_path_merge_mode(), &statbuf)) {
 -                      if (strbuf_read_file(&sb, git_path_merge_mode(), 0) < 0)
 +              if (!stat(git_path_merge_mode(the_repository), &statbuf)) {
 +                      if (strbuf_read_file(&sb, git_path_merge_mode(the_repository), 0) < 0)
                                die_errno(_("could not read MERGE_MODE"));
                        if (!strcmp(sb.buf, "no-ff"))
                                allow_fast_forward = 0;
                die("%s", err.buf);
        }
  
 -      unlink(git_path_cherry_pick_head());
 -      unlink(git_path_revert_head());
 -      unlink(git_path_merge_head());
 -      unlink(git_path_merge_msg());
 -      unlink(git_path_merge_mode());
 -      unlink(git_path_squash_msg());
 +      unlink(git_path_cherry_pick_head(the_repository));
 +      unlink(git_path_revert_head(the_repository));
 +      unlink(git_path_merge_head(the_repository));
 +      unlink(git_path_merge_msg(the_repository));
 +      unlink(git_path_merge_mode(the_repository));
 +      unlink(git_path_squash_msg(the_repository));
  
        if (commit_index_files())
-               die (_("Repository has been updated, but unable to write\n"
-                    "new_index file. Check that disk is not full and quota is\n"
-                    "not exceeded, and then \"git reset HEAD\" to recover."));
+               die(_("repository has been updated, but unable to write\n"
+                     "new_index file. Check that disk is not full and quota is\n"
+                     "not exceeded, and then \"git reset HEAD\" to recover."));
  
        rerere(0);
        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
diff --combined builtin/config.c
index 2c93a289a7255c69260a806cc064f00170453531,5761a2c4ac25d3f90938f9830d4c9d7eebaa9a92..97b58c4aeac4a390148192578d92191407ec7e13
@@@ -67,7 -67,7 +67,7 @@@ static int show_origin
        { OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \
        PARSE_OPT_NONEG, option_parse_type, (i) }
  
 -static struct option builtin_config_options[];
 +static NORETURN void usage_builtin_config(void);
  
  static int option_parse_type(const struct option *opt, const char *arg,
                             int unset)
                 * --int' and '--type=bool
                 * --type=int'.
                 */
-               error("only one type at a time.");
+               error(_("only one type at a time"));
 -              usage_with_options(builtin_config_usage,
 -                      builtin_config_options);
 +              usage_builtin_config();
        }
        *to_type = new_type;
  
@@@ -156,16 -157,15 +156,20 @@@ static struct option builtin_config_opt
        OPT_END(),
  };
  
 +static NORETURN void usage_builtin_config(void)
 +{
 +      usage_with_options(builtin_config_usage, builtin_config_options);
 +}
 +
  static void check_argc(int argc, int min, int max) {
        if (argc >= min && argc <= max)
                return;
-       error("wrong number of arguments");
+       if (min == max)
+               error(_("wrong number of arguments, should be %d"), min);
+       else
+               error(_("wrong number of arguments, should be from %d to %d"),
+                     min, max);
 -      usage_with_options(builtin_config_usage, builtin_config_options);
 +      usage_builtin_config();
  }
  
  static void show_config_origin(struct strbuf *buf)
@@@ -297,7 -297,7 +301,7 @@@ static int get_value(const char *key_, 
  
                key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(key_regexp, key, REG_EXTENDED)) {
-                       error("invalid key pattern: %s", key_);
+                       error(_("invalid key pattern: %s"), key_);
                        FREE_AND_NULL(key_regexp);
                        ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
  
                regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(regexp, regex_, REG_EXTENDED)) {
-                       error("invalid pattern: %s", regex_);
+                       error(_("invalid pattern: %s"), regex_);
                        FREE_AND_NULL(regexp);
                        ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
@@@ -390,7 -390,7 +394,7 @@@ static char *normalize_value(const cha
        if (type == TYPE_COLOR) {
                char v[COLOR_MAXLEN];
                if (git_config_color(v, key, value))
-                       die("cannot parse color '%s'", value);
+                       die(_("cannot parse color '%s'"), value);
  
                /*
                 * The contents of `v` now contain an ANSI escape
@@@ -485,13 -485,13 +489,13 @@@ static int get_colorbool(const char *va
  static void check_write(void)
  {
        if (!given_config_source.file && !startup_info->have_repository)
-               die("not in a git directory");
+               die(_("not in a git directory"));
  
        if (given_config_source.use_stdin)
-               die("writing to stdin is not supported");
+               die(_("writing to stdin is not supported"));
  
        if (given_config_source.blob)
-               die("writing config blobs is not supported");
+               die(_("writing config blobs is not supported"));
  }
  
  struct urlmatch_current_candidate_value {
@@@ -599,8 -599,8 +603,8 @@@ int cmd_config(int argc, const char **a
  
        if (use_global_config + use_system_config + use_local_config +
            !!given_config_source.file + !!given_config_source.blob > 1) {
-               error("only one config file at a time.");
+               error(_("only one config file at a time"));
 -              usage_with_options(builtin_config_usage, builtin_config_options);
 +              usage_builtin_config();
        }
  
        if (use_local_config && nongit)
                         * location; error out even if XDG_CONFIG_HOME
                         * is set and points at a sane location.
                         */
-                       die("$HOME not set");
+                       die(_("$HOME not set"));
  
                if (access_or_warn(user_config, R_OK, 0) &&
                    xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
        }
  
        if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && type) {
-               error("--get-color and variable type are incoherent");
+               error(_("--get-color and variable type are incoherent"));
 -              usage_with_options(builtin_config_usage, builtin_config_options);
 +              usage_builtin_config();
        }
  
        if (HAS_MULTI_BITS(actions)) {
-               error("only one action at a time.");
+               error(_("only one action at a time"));
 -              usage_with_options(builtin_config_usage, builtin_config_options);
 +              usage_builtin_config();
        }
        if (actions == 0)
                switch (argc) {
                case 2: actions = ACTION_SET; break;
                case 3: actions = ACTION_SET_ALL; break;
                default:
 -                      usage_with_options(builtin_config_usage, builtin_config_options);
 +                      usage_builtin_config();
                }
        if (omit_values &&
            !(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
-               error("--name-only is only applicable to --list or --get-regexp");
+               error(_("--name-only is only applicable to --list or --get-regexp"));
 -              usage_with_options(builtin_config_usage, builtin_config_options);
 +              usage_builtin_config();
        }
  
        if (show_origin && !(actions &
                (ACTION_GET|ACTION_GET_ALL|ACTION_GET_REGEXP|ACTION_LIST))) {
-               error("--show-origin is only applicable to --get, --get-all, "
-                         "--get-regexp, and --list.");
+               error(_("--show-origin is only applicable to --get, --get-all, "
+                       "--get-regexp, and --list"));
 -              usage_with_options(builtin_config_usage, builtin_config_options);
 +              usage_builtin_config();
        }
  
        if (default_value && !(actions & ACTION_GET)) {
-               error("--default is only applicable to --get");
+               error(_("--default is only applicable to --get"));
 -              usage_with_options(builtin_config_usage,
 -                      builtin_config_options);
 +              usage_builtin_config();
        }
  
        if (actions & PAGING_ACTIONS)
                                        &given_config_source,
                                        &config_options) < 0) {
                        if (given_config_source.file)
-                               die_errno("unable to read config file '%s'",
+                               die_errno(_("unable to read config file '%s'"),
                                          given_config_source.file);
                        else
-                               die("error processing config file(s)");
+                               die(_("error processing config file(s)"));
                }
        }
        else if (actions == ACTION_EDIT) {
  
                check_argc(argc, 0, 0);
                if (!given_config_source.file && nongit)
-                       die("not in a git directory");
+                       die(_("not in a git directory"));
                if (given_config_source.use_stdin)
-                       die("editing stdin is not supported");
+                       die(_("editing stdin is not supported"));
                if (given_config_source.blob)
-                       die("editing blobs is not supported");
+                       die(_("editing blobs is not supported"));
                git_config(git_default_config, NULL);
                config_file = given_config_source.file ?
                                xstrdup(given_config_source.file) :
                if (ret < 0)
                        return ret;
                if (ret == 0)
-                       die("No such section!");
+                       die(_("no such section: %s"), argv[0]);
        }
        else if (actions == ACTION_REMOVE_SECTION) {
                int ret;
                if (ret < 0)
                        return ret;
                if (ret == 0)
-                       die("No such section!");
+                       die(_("no such section: %s"), argv[0]);
        }
        else if (actions == ACTION_GET_COLOR) {
                check_argc(argc, 1, 2);
diff --combined builtin/fast-export.c
index 223499d7ca4616553c6a7029f6534634f2fa93a5,83c482581b585116f5b78957b2f7a81a6b21a36e..9bd8a14b57b8e1b014503dffbcffa27e7242d67a
@@@ -8,7 -8,6 +8,7 @@@
  #include "config.h"
  #include "refs.h"
  #include "refspec.h"
 +#include "object-store.h"
  #include "commit.h"
  #include "object.h"
  #include "tag.h"
@@@ -230,22 -229,21 +230,22 @@@ static void export_blob(const struct ob
        if (is_null_oid(oid))
                return;
  
 -      object = lookup_object(oid->hash);
 +      object = lookup_object(the_repository, oid->hash);
        if (object && object->flags & SHOWN)
                return;
  
        if (anonymize) {
                buf = anonymize_blob(&size);
 -              object = (struct object *)lookup_blob(oid);
 +              object = (struct object *)lookup_blob(the_repository, oid);
                eaten = 0;
        } else {
                buf = read_object_file(oid, &type, &size);
                if (!buf)
-                       die ("Could not read blob %s", oid_to_hex(oid));
+                       die("could not read blob %s", oid_to_hex(oid));
                if (check_object_signature(oid, buf, size, type_name(type)) < 0)
                        die("sha1 mismatch in blob %s", oid_to_hex(oid));
 -              object = parse_object_buffer(oid, type, size, buf, &eaten);
 +              object = parse_object_buffer(the_repository, oid, type,
 +                                           size, buf, &eaten);
        }
  
        if (!object)
  
        printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size);
        if (size && fwrite(buf, size, 1, stdout) != 1)
-               die_errno ("Could not write blob '%s'", oid_to_hex(oid));
+               die_errno("could not write blob '%s'", oid_to_hex(oid));
        printf("\n");
  
        show_progress();
@@@ -403,8 -401,7 +403,8 @@@ static void show_filemodify(struct diff
                                                   anonymize_sha1(&spec->oid) :
                                                   spec->oid.hash));
                        else {
 -                              struct object *object = lookup_object(spec->oid.hash);
 +                              struct object *object = lookup_object(the_repository,
 +                                                                    spec->oid.hash);
                                printf("M %06o :%d ", spec->mode,
                                       get_object_mark(object));
                        }
@@@ -563,14 -560,14 +563,14 @@@ static void handle_commit(struct commi
        commit_buffer = get_commit_buffer(commit, NULL);
        author = strstr(commit_buffer, "\nauthor ");
        if (!author)
-               die ("Could not find author in commit %s",
-                    oid_to_hex(&commit->object.oid));
+               die("could not find author in commit %s",
+                   oid_to_hex(&commit->object.oid));
        author++;
        author_end = strchrnul(author, '\n');
        committer = strstr(author_end, "\ncommitter ");
        if (!committer)
-               die ("Could not find committer in commit %s",
-                    oid_to_hex(&commit->object.oid));
+               die("could not find committer in commit %s",
+                   oid_to_hex(&commit->object.oid));
        committer++;
        committer_end = strchrnul(committer, '\n');
        message = strstr(committer_end, "\n\n");
@@@ -691,7 -688,7 +691,7 @@@ static void handle_tag(const char *name
  
        buf = read_object_file(&tag->object.oid, &type, &size);
        if (!buf)
-               die ("Could not read tag %s", oid_to_hex(&tag->object.oid));
+               die("could not read tag %s", oid_to_hex(&tag->object.oid));
        message = memmem(buf, size, "\n\n", 2);
        if (message) {
                message += 2;
                if (signature)
                        switch(signed_tag_mode) {
                        case ABORT:
-                               die ("Encountered signed tag %s; use "
-                                    "--signed-tags=<mode> to handle it.",
-                                    oid_to_hex(&tag->object.oid));
+                               die("encountered signed tag %s; use "
+                                   "--signed-tags=<mode> to handle it",
+                                   oid_to_hex(&tag->object.oid));
                        case WARN:
-                               warning ("Exporting signed tag %s",
-                                        oid_to_hex(&tag->object.oid));
+                               warning("exporting signed tag %s",
+                                       oid_to_hex(&tag->object.oid));
                                /* fallthru */
                        case VERBATIM:
                                break;
                        case WARN_STRIP:
-                               warning ("Stripping signature from tag %s",
-                                        oid_to_hex(&tag->object.oid));
+                               warning("stripping signature from tag %s",
+                                       oid_to_hex(&tag->object.oid));
                                /* fallthru */
                        case STRIP:
                                message_size = signature + 1 - message;
        if (!tagged_mark) {
                switch(tag_of_filtered_mode) {
                case ABORT:
-                       die ("Tag %s tags unexported object; use "
-                            "--tag-of-filtered-object=<mode> to handle it.",
-                            oid_to_hex(&tag->object.oid));
+                       die("tag %s tags unexported object; use "
+                           "--tag-of-filtered-object=<mode> to handle it",
+                           oid_to_hex(&tag->object.oid));
                case DROP:
                        /* Ignore this tag altogether */
                        free(buf);
                        return;
                case REWRITE:
                        if (tagged->type != OBJ_COMMIT) {
-                               die ("Tag %s tags unexported %s!",
-                                    oid_to_hex(&tag->object.oid),
-                                    type_name(tagged->type));
+                               die("tag %s tags unexported %s!",
+                                   oid_to_hex(&tag->object.oid),
+                                   type_name(tagged->type));
                        }
                        p = (struct commit *)tagged;
                        for (;;) {
                                if (!(p->object.flags & TREESAME))
                                        break;
                                if (!p->parents)
-                                       die ("Can't find replacement commit for tag %s\n",
+                                       die("can't find replacement commit for tag %s",
                                             oid_to_hex(&tag->object.oid));
                                p = p->parents->item;
                        }
@@@ -803,7 -800,7 +803,7 @@@ static struct commit *get_commit(struc
  
                /* handle nested tags */
                while (tag && tag->object.type == OBJ_TAG) {
 -                      parse_object(&tag->object.oid);
 +                      parse_object(the_repository, &tag->object.oid);
                        string_list_append(&extra_refs, full_name)->util = tag;
                        tag = (struct tag *)tag->tagged;
                }
@@@ -963,7 -960,7 +963,7 @@@ static void import_marks(char *input_fi
                        /* only commits */
                        continue;
  
 -              commit = lookup_commit(&oid);
 +              commit = lookup_commit(the_repository, &oid);
                if (!commit)
                        die("not a commit? can't happen: %s", oid_to_hex(&oid));
  
diff --combined builtin/fmt-merge-msg.c
index ca9206fbbe1c2d9da706111a8de31396b3bf5909,a08f239e005c58ce77ec150d4e590a339a2f809e..f35ff1612bb563c819b611e82f8e3a7730d32461
@@@ -2,7 -2,6 +2,7 @@@
  #include "cache.h"
  #include "config.h"
  #include "refs.h"
 +#include "object-store.h"
  #include "commit.h"
  #include "diff.h"
  #include "revision.h"
@@@ -11,7 -10,6 +11,7 @@@
  #include "branch.h"
  #include "fmt-merge-msg.h"
  #include "gpg-interface.h"
 +#include "repository.h"
  
  static const char * const fmt_merge_msg_usage[] = {
        N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"),
@@@ -110,15 -108,14 +110,15 @@@ static int handle_line(char *line, stru
        struct string_list_item *item;
        int pulling_head = 0;
        struct object_id oid;
 +      const unsigned hexsz = the_hash_algo->hexsz;
  
 -      if (len < GIT_SHA1_HEXSZ + 3 || line[GIT_SHA1_HEXSZ] != '\t')
 +      if (len < hexsz + 3 || line[hexsz] != '\t')
                return 1;
  
 -      if (starts_with(line + GIT_SHA1_HEXSZ + 1, "not-for-merge"))
 +      if (starts_with(line + hexsz + 1, "not-for-merge"))
                return 0;
  
 -      if (line[GIT_SHA1_HEXSZ + 1] != '\t')
 +      if (line[hexsz + 1] != '\t')
                return 2;
  
        i = get_oid_hex(line, &oid);
  
        if (line[len - 1] == '\n')
                line[len - 1] = 0;
 -      line += GIT_SHA1_HEXSZ + 2;
 +      line += hexsz + 2;
  
        /*
         * At this point, line points at the beginning of comment e.g.
@@@ -345,9 -342,7 +345,9 @@@ static void shortlog(const char *name
        const struct object_id *oid = &origin_data->oid;
        int limit = opts->shortlog_len;
  
 -      branch = deref_tag(parse_object(oid), oid_to_hex(oid), GIT_SHA1_HEXSZ);
 +      branch = deref_tag(the_repository, parse_object(the_repository, oid),
 +                         oid_to_hex(oid),
 +                         the_hash_algo->hexsz);
        if (!branch || branch->type != OBJ_COMMIT)
                return;
  
@@@ -550,7 -545,6 +550,7 @@@ static void find_merge_parents(struct m
                int len;
                char *p = in->buf + pos;
                char *newline = strchr(p, '\n');
 +              const char *q;
                struct object_id oid;
                struct commit *parent;
                struct object *obj;
                len = newline ? newline - p : strlen(p);
                pos += len + !!newline;
  
 -              if (len < GIT_SHA1_HEXSZ + 3 ||
 -                  get_oid_hex(p, &oid) ||
 -                  p[GIT_SHA1_HEXSZ] != '\t' ||
 -                  p[GIT_SHA1_HEXSZ + 1] != '\t')
 +              if (parse_oid_hex(p, &oid, &q) ||
 +                  q[0] != '\t' ||
 +                  q[1] != '\t')
                        continue; /* skip not-for-merge */
                /*
                 * Do not use get_merge_parent() here; we do not have
                 * "name" here and we do not want to contaminate its
                 * util field yet.
                 */
 -              obj = parse_object(&oid);
 +              obj = parse_object(the_repository, &oid);
                parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
                if (!parent)
                        continue;
                commit_list_insert(parent, &parents);
                add_merge_parent(result, &obj->oid, &parent->object.oid);
        }
 -      head_commit = lookup_commit(head);
 +      head_commit = lookup_commit(the_repository, head);
        if (head_commit)
                commit_list_insert(head_commit, &parents);
        reduce_heads_replace(&parents);
@@@ -628,7 -623,7 +628,7 @@@ int fmt_merge_msg(struct strbuf *in, st
                i++;
                p[len] = 0;
                if (handle_line(p, &merge_parents))
-                       die ("Error in line %d: %.*s", i, len, p);
+                       die("error in line %d: %.*s", i, len, p);
        }
  
        if (opts->add_title && srcs.nr)
diff --combined builtin/grep.c
index 056161f0f88596a6074ef6edddeaa6c894d8b801,58f941e951949ab9a3d7c2cc34e9072da550d314..ee5a1bd355a5f239a23b524a3e05b9c8646f6bc8
@@@ -489,7 -489,7 +489,7 @@@ static int grep_cache(struct grep_opt *
        }
  
        if (repo_read_index(repo) < 0)
-               die("index file corrupt");
+               die(_("index file corrupt"));
  
        for (nr = 0; nr < repo->index->cache_nr; nr++) {
                const struct cache_entry *ce = repo->index->cache[nr];
@@@ -647,8 -647,7 +647,8 @@@ static int grep_objects(struct grep_op
  
        for (i = 0; i < nr; i++) {
                struct object *real_obj;
 -              real_obj = deref_tag(list->objects[i].item, NULL, 0);
 +              real_obj = deref_tag(the_repository, list->objects[i].item,
 +                                   NULL, 0);
  
                /* load the gitmodules file for this rev */
                if (recurse_submodules) {
@@@ -829,7 -828,6 +829,7 @@@ int cmd_grep(int argc, const char **arg
                            GREP_PATTERN_TYPE_PCRE),
                OPT_GROUP(""),
                OPT_BOOL('n', "line-number", &opt.linenum, N_("show line numbers")),
 +              OPT_BOOL(0, "column", &opt.columnnum, N_("show column number of first match")),
                OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1),
                OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1),
                OPT_NEGBIT(0, "full-name", &opt.relative,
                OPT_BOOL_F('z', "null", &opt.null_following_name,
                           N_("print NUL after filenames"),
                           PARSE_OPT_NOCOMPLETE),
 +              OPT_BOOL('o', "only-matching", &opt.only_matching,
 +                      N_("show only matching parts of a line")),
                OPT_BOOL('c', "count", &opt.count,
                        N_("show the number of matches instead of matching lines")),
                OPT__COLOR(&opt.color, N_("highlight matches")),
        }
  
        if (!opt.pattern_list)
-               die(_("no pattern given."));
+               die(_("no pattern given"));
  
 +      /* --only-matching has no effect with --invert. */
 +      if (opt.invert)
 +              opt.only_matching = 0;
 +
        /*
         * We have to find "--" in a separate pass, because its presence
         * influences how we will parse arguments that come before it.
        }
  
        if (recurse_submodules && (!use_index || untracked))
-               die(_("option not supported with --recurse-submodules."));
+               die(_("option not supported with --recurse-submodules"));
  
        if (!show_in_pager && !opt.status_only)
                setup_pager();
  
        if (!use_index && (untracked || cached))
-               die(_("--cached or --untracked cannot be used with --no-index."));
+               die(_("--cached or --untracked cannot be used with --no-index"));
  
        if (!use_index || untracked) {
                int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
                hit = grep_directory(&opt, &pathspec, use_exclude, use_index);
        } else if (0 <= opt_exclude) {
-               die(_("--[no-]exclude-standard cannot be used for tracked contents."));
+               die(_("--[no-]exclude-standard cannot be used for tracked contents"));
        } else if (!list.nr) {
                if (!cached)
                        setup_work_tree();
                hit = grep_cache(&opt, the_repository, &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 574595132af4a799da3665543d19787e670b2791,99d4c6996e027f824c632898266a29731c2ab383..e094560d9abca6e819c24b845dc7c04d384850c3
@@@ -7,7 -7,6 +7,7 @@@
  #include "cache.h"
  #include "config.h"
  #include "refs.h"
 +#include "object-store.h"
  #include "color.h"
  #include "commit.h"
  #include "diff.h"
@@@ -30,7 -29,6 +30,7 @@@
  #include "gpg-interface.h"
  #include "progress.h"
  #include "commit-slab.h"
 +#include "repository.h"
  
  #define MAIL_DEFAULT_WRAP 72
  
@@@ -620,7 -618,7 +620,7 @@@ int cmd_show(int argc, const char **arg
                        rev.shown_one = 1;
                        if (ret)
                                break;
 -                      o = parse_object(&t->tagged->oid);
 +                      o = parse_object(the_repository, &t->tagged->oid);
                        if (!o)
                                ret = error(_("Could not read object %s"),
                                            oid_to_hex(&t->tagged->oid));
@@@ -907,8 -905,8 +907,8 @@@ static void get_patch_ids(struct rev_in
        o2 = rev->pending.objects[1].item;
        flags1 = o1->flags;
        flags2 = o2->flags;
 -      c1 = lookup_commit_reference(&o1->oid);
 -      c2 = lookup_commit_reference(&o2->oid);
 +      c1 = lookup_commit_reference(the_repository, &o1->oid);
 +      c2 = lookup_commit_reference(the_repository, &o2->oid);
  
        if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
                die(_("Not a range."));
@@@ -1608,14 -1606,14 +1608,14 @@@ int cmd_format_patch(int argc, const ch
                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/--rfc and -k are mutually exclusive."));
+               die(_("--subject-prefix/--rfc and -k are mutually exclusive"));
        rev.preserve_subject = keep_subject;
  
        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"));
        if (base_commit || base_auto) {
                struct commit *base = get_base_commit(base_commit, list, nr);
                reset_revision_walk();
 +              clear_object_flags(UNINTERESTING);
                prepare_bases(&bases, base, list, nr);
        }
  
@@@ -1865,8 -1862,7 +1865,8 @@@ static int add_pending_commit(const cha
  {
        struct object_id oid;
        if (get_oid(arg, &oid) == 0) {
 -              struct commit *commit = lookup_commit_reference(&oid);
 +              struct commit *commit = lookup_commit_reference(the_repository,
 +                                                              &oid);
                if (commit) {
                        commit->object.flags |= flags;
                        add_pending_object(revs, &commit->object, arg);
diff --combined builtin/merge.c
index 77e1694a785f533f2953727897fee8a19fb74d4e,f553f89a480aa38cff18fd981b7c0e00b4a6829b..8f4a5065c209b5b50e02271b48277fff90306338
@@@ -111,35 -111,6 +111,35 @@@ static int option_parse_message(const s
        return 0;
  }
  
 +static int option_read_message(struct parse_opt_ctx_t *ctx,
 +                             const struct option *opt, int unset)
 +{
 +      struct strbuf *buf = opt->value;
 +      const char *arg;
 +
 +      if (unset)
 +              BUG("-F cannot be negated");
 +
 +      if (ctx->opt) {
 +              arg = ctx->opt;
 +              ctx->opt = NULL;
 +      } else if (ctx->argc > 1) {
 +              ctx->argc--;
 +              arg = *++ctx->argv;
 +      } else
 +              return opterror(opt, "requires a value", 0);
 +
 +      if (buf->len)
 +              strbuf_addch(buf, '\n');
 +      if (ctx->prefix && !is_absolute_path(arg))
 +              arg = prefix_filename(ctx->prefix, arg);
 +      if (strbuf_read_file(buf, arg, 0) < 0)
 +              return error(_("could not read file '%s'"), arg);
 +      have_message = 1;
 +
 +      return 0;
 +}
 +
  static struct strategy *get_strategy(const char *name)
  {
        int i;
@@@ -257,9 -228,6 +257,9 @@@ static struct option builtin_merge_opti
        OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
                N_("merge commit message (for a non-fast-forward merge)"),
                option_parse_message),
 +      { OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"),
 +              N_("read message from file"), PARSE_OPT_NONEG,
 +              (parse_opt_cb *) option_read_message },
        OPT__VERBOSITY(&verbosity),
        OPT_BOOL(0, "abort", &abort_current_merge,
                N_("abort the current in-progress merge")),
  /* Cleans up metadata that is uninteresting after a succeeded merge. */
  static void drop_save(void)
  {
 -      unlink(git_path_merge_head());
 -      unlink(git_path_merge_msg());
 -      unlink(git_path_merge_mode());
 +      unlink(git_path_merge_head(the_repository));
 +      unlink(git_path_merge_msg(the_repository));
 +      unlink(git_path_merge_mode(the_repository));
  }
  
  static int save_state(struct object_id *stash)
@@@ -414,7 -382,7 +414,7 @@@ static void squash_message(struct commi
                        oid_to_hex(&commit->object.oid));
                pretty_print_commit(&ctx, commit, &out);
        }
 -      write_file_buf(git_path_squash_msg(), out.buf, out.len);
 +      write_file_buf(git_path_squash_msg(the_repository), out.buf, out.len);
        strbuf_release(&out);
  }
  
@@@ -725,7 -693,7 +725,7 @@@ static int try_merge_strategy(const cha
                        exit(128);
                if (write_locked_index(&the_index, &lock,
                                       COMMIT_LOCK | SKIP_IF_UNCHANGED))
-                       die (_("unable to write %s"), get_index_file());
+                       die(_("unable to write %s"), get_index_file());
                return clean ? 0 : 1;
        } else {
                return try_merge_command(strategy, xopts_nr, xopts,
@@@ -773,7 -741,7 +773,7 @@@ static void add_strategies(const char *
  
  static void read_merge_msg(struct strbuf *msg)
  {
 -      const char *filename = git_path_merge_msg();
 +      const char *filename = git_path_merge_msg(the_repository);
        strbuf_reset(msg);
        if (strbuf_read_file(msg, filename, 0) < 0)
                die_errno(_("Could not read from '%s'"), filename);
@@@ -810,18 -778,18 +810,18 @@@ static void prepare_to_commit(struct co
        if (signoff)
                append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
        write_merge_heads(remoteheads);
 -      write_file_buf(git_path_merge_msg(), msg.buf, msg.len);
 +      write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len);
        if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
 -                          git_path_merge_msg(), "merge", NULL))
 +                          git_path_merge_msg(the_repository), "merge", NULL))
                abort_commit(remoteheads, NULL);
        if (0 < option_edit) {
 -              if (launch_editor(git_path_merge_msg(), NULL, NULL))
 +              if (launch_editor(git_path_merge_msg(the_repository), NULL, NULL))
                        abort_commit(remoteheads, NULL);
        }
  
        if (verify_msg && run_commit_hook(0 < option_edit, get_index_file(),
                                          "commit-msg",
 -                                        git_path_merge_msg(), NULL))
 +                                        git_path_merge_msg(the_repository), NULL))
                abort_commit(remoteheads, NULL);
  
        read_merge_msg(&msg);
@@@ -891,7 -859,7 +891,7 @@@ static int suggest_conflicts(void
        FILE *fp;
        struct strbuf msgbuf = STRBUF_INIT;
  
 -      filename = git_path_merge_msg();
 +      filename = git_path_merge_msg(the_repository);
        fp = xfopen(filename, "a");
  
        append_conflicts_hint(&msgbuf);
@@@ -974,12 -942,12 +974,12 @@@ static void write_merge_heads(struct co
                }
                strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
        }
 -      write_file_buf(git_path_merge_head(), buf.buf, buf.len);
 +      write_file_buf(git_path_merge_head(the_repository), buf.buf, buf.len);
  
        strbuf_reset(&buf);
        if (fast_forward == FF_NO)
                strbuf_addstr(&buf, "no-ff");
 -      write_file_buf(git_path_merge_mode(), buf.buf, buf.len);
 +      write_file_buf(git_path_merge_mode(the_repository), buf.buf, buf.len);
        strbuf_release(&buf);
  }
  
@@@ -987,8 -955,7 +987,8 @@@ static void write_merge_state(struct co
  {
        write_merge_heads(remoteheads);
        strbuf_addch(&merge_msg, '\n');
 -      write_file_buf(git_path_merge_msg(), merge_msg.buf, merge_msg.len);
 +      write_file_buf(git_path_merge_msg(the_repository), merge_msg.buf,
 +                     merge_msg.len);
  }
  
  static int default_edit_option(void)
@@@ -1067,12 -1034,11 +1067,12 @@@ static void handle_fetch_head(struct co
        const char *filename;
        int fd, pos, npos;
        struct strbuf fetch_head_file = STRBUF_INIT;
 +      const unsigned hexsz = the_hash_algo->hexsz;
  
        if (!merge_names)
                merge_names = &fetch_head_file;
  
 -      filename = git_path_fetch_head();
 +      filename = git_path_fetch_head(the_repository);
        fd = open(filename, O_RDONLY);
        if (fd < 0)
                die_errno(_("could not open '%s' for reading"), filename);
                else
                        npos = merge_names->len;
  
 -              if (npos - pos < GIT_SHA1_HEXSZ + 2 ||
 +              if (npos - pos < hexsz + 2 ||
                    get_oid_hex(merge_names->buf + pos, &oid))
                        commit = NULL; /* bad */
 -              else if (memcmp(merge_names->buf + pos + GIT_SHA1_HEXSZ, "\t\t", 2))
 +              else if (memcmp(merge_names->buf + pos + hexsz, "\t\t", 2))
                        continue; /* not-for-merge */
                else {
 -                      char saved = merge_names->buf[pos + GIT_SHA1_HEXSZ];
 -                      merge_names->buf[pos + GIT_SHA1_HEXSZ] = '\0';
 +                      char saved = merge_names->buf[pos + hexsz];
 +                      merge_names->buf[pos + hexsz] = '\0';
                        commit = get_merge_parent(merge_names->buf + pos);
 -                      merge_names->buf[pos + GIT_SHA1_HEXSZ] = saved;
 +                      merge_names->buf[pos + hexsz] = saved;
                }
                if (!commit) {
                        if (ptr)
@@@ -1247,7 -1213,7 +1247,7 @@@ int cmd_merge(int argc, const char **ar
                        usage_msg_opt(_("--abort expects no arguments"),
                              builtin_merge_usage, builtin_merge_options);
  
 -              if (!file_exists(git_path_merge_head()))
 +              if (!file_exists(git_path_merge_head(the_repository)))
                        die(_("There is no merge to abort (MERGE_HEAD missing)."));
  
                /* Invoke 'git reset --merge' */
                        usage_msg_opt(_("--continue expects no arguments"),
                              builtin_merge_usage, builtin_merge_options);
  
 -              if (!file_exists(git_path_merge_head()))
 +              if (!file_exists(git_path_merge_head(the_repository)))
                        die(_("There is no merge in progress (MERGE_HEAD missing)."));
  
                /* Invoke 'git commit' */
        if (read_cache_unmerged())
                die_resolve_conflict("merge");
  
 -      if (file_exists(git_path_merge_head())) {
 +      if (file_exists(git_path_merge_head(the_repository))) {
                /*
                 * There is no unmerged entry, don't advise 'git
                 * add/rm <file>', just 'git commit'.
                else
                        die(_("You have not concluded your merge (MERGE_HEAD exists)."));
        }
 -      if (file_exists(git_path_cherry_pick_head())) {
 +      if (file_exists(git_path_cherry_pick_head(the_repository))) {
                if (advice_resolve_conflict)
                        die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
                            "Please, commit your changes before you merge."));
diff --combined builtin/pack-objects.c
index 33f23f99ceba8f52271f50759142579f656bcdf4,37d63f6721c79382f3ef24fad48f7f305177ff5e..3848f3782dd08eaf23c4ff1d889f7e2623bdd992
@@@ -140,7 -140,7 +140,7 @@@ static void *get_delta(struct object_en
  
        buf = read_object_file(&entry->idx.oid, &type, &size);
        if (!buf)
-               die("unable to read %s", oid_to_hex(&entry->idx.oid));
+               die(_("unable to read %s"), oid_to_hex(&entry->idx.oid));
        base_buf = read_object_file(&DELTA(entry)->idx.oid, &type,
                                    &base_size);
        if (!base_buf)
                    oid_to_hex(&DELTA(entry)->idx.oid));
        delta_buf = diff_delta(base_buf, base_size,
                               buf, size, &delta_size, 0);
+       /*
+        * We succesfully computed this delta once but dropped it for
+        * memory reasons. Something is very wrong if this time we
+        * recompute and create a different delta.
+        */
        if (!delta_buf || delta_size != DELTA_SIZE(entry))
-               die("delta size changed");
+               BUG("delta size changed");
        free(buf);
        free(base_buf);
        return delta_buf;
@@@ -406,7 -411,7 +411,7 @@@ static off_t write_reuse_object(struct 
        datalen = revidx[1].offset - offset;
        if (!pack_to_stdout && p->index_version > 1 &&
            check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) {
-               error("bad packed object CRC for %s",
+               error(_("bad packed object CRC for %s"),
                      oid_to_hex(&entry->idx.oid));
                unuse_pack(&w_curs);
                return write_no_reuse_object(f, entry, limit, usable_delta);
  
        if (!pack_to_stdout && p->index_version == 1 &&
            check_pack_inflate(p, &w_curs, offset, datalen, entry_size)) {
-               error("corrupt packed object for %s",
+               error(_("corrupt packed object for %s"),
                      oid_to_hex(&entry->idx.oid));
                unuse_pack(&w_curs);
                return write_no_reuse_object(f, entry, limit, usable_delta);
@@@ -548,7 -553,7 +553,7 @@@ static enum write_one_status write_one(
         */
        recursing = (e->idx.offset == 1);
        if (recursing) {
-               warning("recursive delta detected for object %s",
+               warning(_("recursive delta detected for object %s"),
                        oid_to_hex(&e->idx.oid));
                return WRITE_ONE_RECURSIVE;
        } else if (e->idx.offset || e->preferred_base) {
  
        /* make sure off_t is sufficiently large not to wrap */
        if (signed_add_overflows(*offset, size))
-               die("pack too large for current definition of off_t");
+               die(_("pack too large for current definition of off_t"));
        *offset += size;
        return WRITE_ONE_WRITTEN;
  }
@@@ -748,7 -753,8 +753,8 @@@ static struct object_entry **compute_wr
        }
  
        if (wo_end != to_pack.nr_objects)
-               die("ordered %u objects, expected %"PRIu32, wo_end, to_pack.nr_objects);
+               die(_("ordered %u objects, expected %"PRIu32),
+                   wo_end, to_pack.nr_objects);
  
        return wo;
  }
@@@ -760,15 -766,15 +766,15 @@@ static off_t write_reused_pack(struct h
        int fd;
  
        if (!is_pack_valid(reuse_packfile))
-               die("packfile is invalid: %s", reuse_packfile->pack_name);
+               die(_("packfile is invalid: %s"), reuse_packfile->pack_name);
  
        fd = git_open(reuse_packfile->pack_name);
        if (fd < 0)
-               die_errno("unable to open packfile for reuse: %s",
+               die_errno(_("unable to open packfile for reuse: %s"),
                          reuse_packfile->pack_name);
  
        if (lseek(fd, sizeof(struct pack_header), SEEK_SET) == -1)
-               die_errno("unable to seek in reused packfile");
+               die_errno(_("unable to seek in reused packfile"));
  
        if (reuse_packfile_offset < 0)
                reuse_packfile_offset = reuse_packfile->pack_size - the_hash_algo->rawsz;
                int read_pack = xread(fd, buffer, sizeof(buffer));
  
                if (read_pack <= 0)
-                       die_errno("unable to read from reused packfile");
+                       die_errno(_("unable to read from reused packfile"));
  
                if (read_pack > to_write)
                        read_pack = to_write;
@@@ -882,7 -888,7 +888,7 @@@ static void write_pack_file(void
                         * to preserve this property.
                         */
                        if (stat(pack_tmp_name, &st) < 0) {
-                               warning_errno("failed to stat %s", pack_tmp_name);
+                               warning_errno(_("failed to stat %s"), pack_tmp_name);
                        } else if (!last_mtime) {
                                last_mtime = st.st_mtime;
                        } else {
                                utb.actime = st.st_atime;
                                utb.modtime = --last_mtime;
                                if (utime(pack_tmp_name, &utb) < 0)
-                                       warning_errno("failed utime() on %s", pack_tmp_name);
+                                       warning_errno(_("failed utime() on %s"), pack_tmp_name);
                        }
  
                        strbuf_addf(&tmpname, "%s-", base_name);
        free(write_order);
        stop_progress(&progress_state);
        if (written != nr_result)
-               die("wrote %"PRIu32" objects while expecting %"PRIu32,
-                       written, nr_result);
+               die(_("wrote %"PRIu32" objects while expecting %"PRIu32),
+                   written, nr_result);
  }
  
  static int no_try_delta(const char *path)
@@@ -1480,7 -1486,7 +1486,7 @@@ static void check_object(struct object_
                        while (c & 128) {
                                ofs += 1;
                                if (!ofs || MSB(ofs, 7)) {
-                                       error("delta base offset overflow in pack for %s",
+                                       error(_("delta base offset overflow in pack for %s"),
                                              oid_to_hex(&entry->idx.oid));
                                        goto give_up;
                                }
                        }
                        ofs = entry->in_pack_offset - ofs;
                        if (ofs <= 0 || ofs >= entry->in_pack_offset) {
-                               error("delta base offset out of bound for %s",
+                               error(_("delta base offset out of bound for %s"),
                                      oid_to_hex(&entry->idx.oid));
                                goto give_up;
                        }
@@@ -1974,10 -1980,10 +1980,10 @@@ static int try_delta(struct unpacked *t
                trg->data = read_object_file(&trg_entry->idx.oid, &type, &sz);
                read_unlock();
                if (!trg->data)
-                       die("object %s cannot be read",
+                       die(_("object %s cannot be read"),
                            oid_to_hex(&trg_entry->idx.oid));
                if (sz != trg_size)
-                       die("object %s inconsistent object length (%lu vs %lu)",
+                       die(_("object %s inconsistent object length (%lu vs %lu)"),
                            oid_to_hex(&trg_entry->idx.oid), sz,
                            trg_size);
                *mem_usage += sz;
                        if (src_entry->preferred_base) {
                                static int warned = 0;
                                if (!warned++)
-                                       warning("object %s cannot be read",
+                                       warning(_("object %s cannot be read"),
                                                oid_to_hex(&src_entry->idx.oid));
                                /*
                                 * Those objects are not included in the
                                 */
                                return 0;
                        }
-                       die("object %s cannot be read",
+                       die(_("object %s cannot be read"),
                            oid_to_hex(&src_entry->idx.oid));
                }
                if (sz != src_size)
-                       die("object %s inconsistent object length (%lu vs %lu)",
+                       die(_("object %s inconsistent object length (%lu vs %lu)"),
                            oid_to_hex(&src_entry->idx.oid), sz,
                            src_size);
                *mem_usage += sz;
                if (!src->index) {
                        static int warned = 0;
                        if (!warned++)
-                               warning("suboptimal pack - out of memory");
+                               warning(_("suboptimal pack - out of memory"));
                        return 0;
                }
                *mem_usage += sizeof_delta_index(src->index);
@@@ -2341,8 -2347,8 +2347,8 @@@ static void ll_find_deltas(struct objec
                return;
        }
        if (progress > pack_to_stdout)
-               fprintf(stderr, "Delta compression using up to %d threads.\n",
-                               delta_search_threads);
+               fprintf_ln(stderr, _("Delta compression using up to %d threads"),
+                          delta_search_threads);
        p = xcalloc(delta_search_threads, sizeof(*p));
  
        /* Partition the work amongst work threads. */
                ret = pthread_create(&p[i].thread, NULL,
                                     threaded_find_deltas, &p[i]);
                if (ret)
-                       die("unable to create thread: %s", strerror(ret));
+                       die(_("unable to create thread: %s"), strerror(ret));
                active_threads++;
        }
  
@@@ -2474,10 -2480,10 +2480,10 @@@ static void add_tag_chain(const struct 
        if (packlist_find(&to_pack, oid->hash, NULL))
                return;
  
 -      tag = lookup_tag(oid);
 +      tag = lookup_tag(the_repository, oid);
        while (1) {
                if (!tag || parse_tag(tag) || !tag->tagged)
-                       die("unable to pack objects reachable from tag %s",
+                       die(_("unable to pack objects reachable from tag %s"),
                            oid_to_hex(oid));
  
                add_object_entry(&tag->object.oid, OBJ_TAG, NULL, 0);
@@@ -2543,7 -2549,7 +2549,7 @@@ static void prepare_pack(int window, in
                if (!entry->preferred_base) {
                        nr_deltas++;
                        if (oe_type(entry) < 0)
-                               die("unable to get type of object %s",
+                               die(_("unable to get type of object %s"),
                                    oid_to_hex(&entry->idx.oid));
                } else {
                        if (oe_type(entry) < 0) {
                ll_find_deltas(delta_list, n, window+1, depth, &nr_done);
                stop_progress(&progress_state);
                if (nr_done != nr_deltas)
-                       die("inconsistency with delta count");
+                       die(_("inconsistency with delta count"));
        }
        free(delta_list);
  }
@@@ -2607,11 -2613,11 +2613,11 @@@ static int git_pack_config(const char *
        if (!strcmp(k, "pack.threads")) {
                delta_search_threads = git_config_int(k, v);
                if (delta_search_threads < 0)
-                       die("invalid number of threads specified (%d)",
+                       die(_("invalid number of threads specified (%d)"),
                            delta_search_threads);
  #ifdef NO_PTHREADS
                if (delta_search_threads != 1) {
-                       warning("no threads support, ignoring %s", k);
+                       warning(_("no threads support, ignoring %s"), k);
                        delta_search_threads = 0;
                }
  #endif
        if (!strcmp(k, "pack.indexversion")) {
                pack_idx_opts.version = git_config_int(k, v);
                if (pack_idx_opts.version > 2)
-                       die("bad pack.indexversion=%"PRIu32,
+                       die(_("bad pack.indexversion=%"PRIu32),
                            pack_idx_opts.version);
                return 0;
        }
@@@ -2638,7 -2644,7 +2644,7 @@@ static void read_object_list_from_stdin
                        if (feof(stdin))
                                break;
                        if (!ferror(stdin))
-                               die("fgets returned NULL, not EOF, not error!");
+                               die("BUG: fgets returned NULL, not EOF, not error!");
                        if (errno != EINTR)
                                die_errno("fgets");
                        clearerr(stdin);
                }
                if (line[0] == '-') {
                        if (get_oid_hex(line+1, &oid))
-                               die("expected edge object ID, got garbage:\n %s",
+                               die(_("expected edge object ID, got garbage:\n %s"),
                                    line);
                        add_preferred_base(&oid);
                        continue;
                }
                if (parse_oid_hex(line, &oid, &p))
-                       die("expected object ID, got garbage:\n %s", line);
+                       die(_("expected object ID, got garbage:\n %s"), line);
  
                add_preferred_base_object(p + 1);
                add_object_entry(&oid, OBJ_NONE, p + 1, 0);
@@@ -2791,7 -2797,7 +2797,7 @@@ static void add_objects_in_unpacked_pac
                if (!p->pack_local || p->pack_keep || p->pack_keep_in_core)
                        continue;
                if (open_pack_index(p))
-                       die("cannot open pack index");
+                       die(_("cannot open pack index"));
  
                ALLOC_GROW(in_pack.array,
                           in_pack.nr + p->num_objects,
@@@ -2822,7 -2828,7 +2828,7 @@@ static int add_loose_object(const struc
        enum object_type type = oid_object_info(the_repository, oid, NULL);
  
        if (type < 0) {
-               warning("loose object at %s could not be examined", path);
+               warning(_("loose object at %s could not be examined"), path);
                return 0;
        }
  
@@@ -2899,7 -2905,7 +2905,7 @@@ static void loosen_unused_packed_object
                        continue;
  
                if (open_pack_index(p))
-                       die("cannot open pack index");
+                       die(_("cannot open pack index"));
  
                for (i = 0; i < p->num_objects; i++) {
                        nth_packed_object_oid(&oid, p, i);
                            !has_sha1_pack_kept_or_nonlocal(&oid) &&
                            !loosened_object_can_be_discarded(&oid, p->mtime))
                                if (force_object_loose(&oid, p->mtime))
-                                       die("unable to force loose object");
+                                       die(_("unable to force loose object"));
                }
        }
  }
@@@ -2929,13 -2935,11 +2935,13 @@@ static int pack_options_allow_reuse(voi
  
  static int get_object_list_from_bitmap(struct rev_info *revs)
  {
 -      if (prepare_bitmap_walk(revs) < 0)
 +      struct bitmap_index *bitmap_git;
 +      if (!(bitmap_git = prepare_bitmap_walk(revs)))
                return -1;
  
        if (pack_options_allow_reuse() &&
            !reuse_partial_packfile_from_bitmap(
 +                      bitmap_git,
                        &reuse_packfile,
                        &reuse_packfile_objects,
                        &reuse_packfile_offset)) {
                display_progress(progress_state, nr_result);
        }
  
 -      traverse_bitmap_commit_list(&add_object_entry_from_bitmap);
 +      traverse_bitmap_commit_list(bitmap_git, &add_object_entry_from_bitmap);
 +      free_bitmap_index(bitmap_git);
        return 0;
  }
  
@@@ -2972,7 -2975,7 +2978,7 @@@ static void get_object_list(int ac, con
        setup_revisions(ac, av, &revs, NULL);
  
        /* make sure shallows are read */
 -      is_repository_shallow();
 +      is_repository_shallow(the_repository);
  
        while (fgets(line, sizeof(line), stdin) != NULL) {
                int len = strlen(line);
                                struct object_id oid;
                                if (get_oid_hex(line + 10, &oid))
                                        die("not an SHA-1 '%s'", line + 10);
 -                              register_shallow(&oid);
 +                              register_shallow(the_repository, &oid);
                                use_bitmap_index = 0;
                                continue;
                        }
-                       die("not a rev '%s'", line);
+                       die(_("not a rev '%s'"), line);
                }
                if (handle_revision_arg(line, &revs, flags, REVARG_CANNOT_BE_FILENAME))
-                       die("bad revision '%s'", line);
+                       die(_("bad revision '%s'"), line);
        }
  
        if (use_bitmap_index && !get_object_list_from_bitmap(&revs))
                return;
  
        if (prepare_revision_walk(&revs))
-               die("revision walk setup failed");
+               die(_("revision walk setup failed"));
        mark_edges_uninteresting(&revs, show_edge);
  
        if (!fn_show_object)
                revs.ignore_missing_links = 1;
                if (add_unseen_recent_objects_to_traversal(&revs,
                                unpack_unreachable_expiration))
-                       die("unable to add recent objects");
+                       die(_("unable to add recent objects"));
                if (prepare_revision_walk(&revs))
-                       die("revision walk setup failed");
+                       die(_("revision walk setup failed"));
                traverse_commit_list(&revs, record_recent_commit,
                                     record_recent_object, NULL);
        }
@@@ -3188,7 -3191,7 +3194,7 @@@ int cmd_pack_objects(int argc, const ch
        if (DFS_NUM_STATES > (1 << OE_DFS_STATE_BITS))
                BUG("too many dfs states, increase OE_DFS_STATE_BITS");
  
 -      check_replace_refs = 0;
 +      read_replace_refs = 0;
  
        reset_pack_idx_option(&pack_idx_opts);
        git_config(git_pack_config, NULL);
        if (pack_compression_level == -1)
                pack_compression_level = Z_DEFAULT_COMPRESSION;
        else if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)
-               die("bad pack compression level %d", pack_compression_level);
+               die(_("bad pack compression level %d"), pack_compression_level);
  
        if (!delta_search_threads)      /* --threads=0 means autodetect */
                delta_search_threads = online_cpus();
  
  #ifdef NO_PTHREADS
        if (delta_search_threads != 1)
-               warning("no threads support, ignoring --threads");
+               warning(_("no threads support, ignoring --threads"));
  #endif
        if (!pack_to_stdout && !pack_size_limit)
                pack_size_limit = pack_size_limit_cfg;
        if (pack_to_stdout && pack_size_limit)
-               die("--max-pack-size cannot be used to build a pack for transfer.");
+               die(_("--max-pack-size cannot be used to build a pack for transfer"));
        if (pack_size_limit && pack_size_limit < 1024*1024) {
-               warning("minimum pack size limit is 1 MiB");
+               warning(_("minimum pack size limit is 1 MiB"));
                pack_size_limit = 1024*1024;
        }
  
        if (!pack_to_stdout && thin)
-               die("--thin cannot be used to build an indexable pack.");
+               die(_("--thin cannot be used to build an indexable pack"));
  
        if (keep_unreachable && unpack_unreachable)
-               die("--keep-unreachable and --unpack-unreachable are incompatible.");
+               die(_("--keep-unreachable and --unpack-unreachable are incompatible"));
        if (!rev_list_all || !rev_list_reflog || !rev_list_index)
                unpack_unreachable_expiration = 0;
  
        if (filter_options.choice) {
                if (!pack_to_stdout)
-                       die("cannot use --filter without --stdout.");
+                       die(_("cannot use --filter without --stdout"));
                use_bitmap_index = 0;
        }
  
                use_bitmap_index = use_bitmap_index_default;
  
        /* "hard" reasons not to use bitmaps; these just won't work at all */
 -      if (!use_internal_rev_list || (!pack_to_stdout && write_bitmap_index) || is_repository_shallow())
 +      if (!use_internal_rev_list || (!pack_to_stdout && write_bitmap_index) || is_repository_shallow(the_repository))
                use_bitmap_index = 0;
  
        if (pack_to_stdout || !rev_list_all)
                prepare_pack(window, depth);
        write_pack_file();
        if (progress)
-               fprintf(stderr, "Total %"PRIu32" (delta %"PRIu32"),"
-                       " reused %"PRIu32" (delta %"PRIu32")\n",
-                       written, written_delta, reused, reused_delta);
+               fprintf_ln(stderr,
+                          _("Total %"PRIu32" (delta %"PRIu32"),"
+                            " reused %"PRIu32" (delta %"PRIu32")"),
+                          written, written_delta, reused, reused_delta);
        return 0;
  }
diff --combined builtin/replace.c
index e997a562f0fc9201f22b3a162621d3888dc1b70c,e879ace2774d3cb587d0ef742b7e53e3a14a9405..4f05791f3e895f78ba511dd6571bd09abab9269c
@@@ -54,7 -54,7 +54,7 @@@ static int show_reference(const char *r
                        enum object_type obj_type, repl_type;
  
                        if (get_oid(refname, &object))
-                               return error("Failed to resolve '%s' as a valid ref.", refname);
+                               return error(_("failed to resolve '%s' as a valid ref"), refname);
  
                        obj_type = oid_object_info(the_repository, &object,
                                                   NULL);
@@@ -83,8 -83,8 +83,8 @@@ static int list_replace_refs(const cha
        else if (!strcmp(format, "long"))
                data.format = REPLACE_FORMAT_LONG;
        else
-               return error("invalid replace format '%s'\n"
-                            "valid formats are 'short', 'medium' and 'long'\n",
+               return error(_("invalid replace format '%s'\n"
+                              "valid formats are 'short', 'medium' and 'long'"),
                             format);
  
        for_each_replace_ref(the_repository, show_reference, (void *)&data);
@@@ -108,7 -108,7 +108,7 @@@ static int for_each_replace_name(const 
  
        for (p = argv; *p; p++) {
                if (get_oid(*p, &oid)) {
-                       error("Failed to resolve '%s' as a valid ref.", *p);
+                       error("failed to resolve '%s' as a valid ref", *p);
                        had_error = 1;
                        continue;
                }
                full_hex = ref.buf + base_len;
  
                if (read_ref(ref.buf, &oid)) {
-                       error("replace ref '%s' not found.", full_hex);
+                       error(_("replace ref '%s' not found"), full_hex);
                        had_error = 1;
                        continue;
                }
@@@ -134,7 -134,7 +134,7 @@@ static int delete_replace_ref(const cha
  {
        if (delete_ref(NULL, ref, oid, 0))
                return 1;
-       printf("Deleted replace ref '%s'\n", name);
+       printf_ln(_("Deleted replace ref '%s'"), name);
        return 0;
  }
  
@@@ -146,12 -146,12 +146,12 @@@ static int check_ref_valid(struct objec
        strbuf_reset(ref);
        strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object));
        if (check_refname_format(ref->buf, 0))
-               return error("'%s' is not a valid ref name.", ref->buf);
+               return error(_("'%s' is not a valid ref name"), ref->buf);
  
        if (read_ref(ref->buf, prev))
                oidclr(prev);
        else if (!force)
-               return error("replace ref '%s' already exists", ref->buf);
+               return error(_("replace ref '%s' already exists"), ref->buf);
        return 0;
  }
  
@@@ -171,10 -171,10 +171,10 @@@ static int replace_object_oid(const cha
        obj_type = oid_object_info(the_repository, object, NULL);
        repl_type = oid_object_info(the_repository, repl, NULL);
        if (!force && obj_type != repl_type)
-               return error("Objects must be of the same type.\n"
-                            "'%s' points to a replaced object of type '%s'\n"
-                            "while '%s' points to a replacement object of "
-                            "type '%s'.",
+               return error(_("Objects must be of the same type.\n"
+                              "'%s' points to a replaced object of type '%s'\n"
+                              "while '%s' points to a replacement object of "
+                              "type '%s'."),
                             object_ref, type_name(obj_type),
                             replace_ref, type_name(repl_type));
  
@@@ -200,10 -200,10 +200,10 @@@ static int replace_object(const char *o
        struct object_id object, repl;
  
        if (get_oid(object_ref, &object))
-               return error("Failed to resolve '%s' as a valid ref.",
+               return error(_("failed to resolve '%s' as a valid ref"),
                             object_ref);
        if (get_oid(replace_ref, &repl))
-               return error("Failed to resolve '%s' as a valid ref.",
+               return error(_("failed to resolve '%s' as a valid ref"),
                             replace_ref);
  
        return replace_object_oid(object_ref, &object, replace_ref, &repl, force);
@@@ -222,7 -222,7 +222,7 @@@ static int export_object(const struct o
  
        fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
        if (fd < 0)
-               return error_errno("unable to open %s for writing", filename);
+               return error_errno(_("unable to open %s for writing"), filename);
  
        argv_array_push(&cmd.args, "--no-replace-objects");
        argv_array_push(&cmd.args, "cat-file");
        cmd.out = fd;
  
        if (run_command(&cmd))
-               return error("cat-file reported failure");
+               return error(_("cat-file reported failure"));
        return 0;
  }
  
@@@ -251,7 -251,7 +251,7 @@@ static int import_object(struct object_
  
        fd = open(filename, O_RDONLY);
        if (fd < 0)
-               return error_errno("unable to open %s for reading", filename);
+               return error_errno(_("unable to open %s for reading"), filename);
  
        if (!raw && type == OBJ_TREE) {
                const char *argv[] = { "mktree", NULL };
  
                if (start_command(&cmd)) {
                        close(fd);
-                       return error("unable to spawn mktree");
+                       return error(_("unable to spawn mktree"));
                }
  
                if (strbuf_read(&result, cmd.out, 41) < 0) {
-                       error_errno("unable to read from mktree");
+                       error_errno(_("unable to read from mktree"));
                        close(fd);
                        close(cmd.out);
                        return -1;
  
                if (finish_command(&cmd)) {
                        strbuf_release(&result);
-                       return error("mktree reported failure");
+                       return error(_("mktree reported failure"));
                }
                if (get_oid_hex(result.buf, oid) < 0) {
                        strbuf_release(&result);
-                       return error("mktree did not return an object name");
+                       return error(_("mktree did not return an object name"));
                }
  
                strbuf_release(&result);
                int flags = HASH_FORMAT_CHECK | HASH_WRITE_OBJECT;
  
                if (fstat(fd, &st) < 0) {
-                       error_errno("unable to fstat %s", filename);
+                       error_errno(_("unable to fstat %s"), filename);
                        close(fd);
                        return -1;
                }
                if (index_fd(oid, fd, &st, type, NULL, flags) < 0)
-                       return error("unable to write object to database");
+                       return error(_("unable to write object to database"));
                /* index_fd close()s fd for us */
        }
  
@@@ -315,11 -315,11 +315,11 @@@ static int edit_and_replace(const char 
        struct strbuf ref = STRBUF_INIT;
  
        if (get_oid(object_ref, &old_oid) < 0)
-               return error("Not a valid object name: '%s'", object_ref);
+               return error(_("not a valid object name: '%s'"), object_ref);
  
        type = oid_object_info(the_repository, &old_oid, NULL);
        if (type < 0)
-               return error("unable to get object type for %s",
+               return error(_("unable to get object type for %s"),
                             oid_to_hex(&old_oid));
  
        if (check_ref_valid(&old_oid, &prev, &ref, force)) {
        }
        if (launch_editor(tmpfile, NULL, NULL) < 0) {
                free(tmpfile);
-               return error("editing object file failed");
+               return error(_("editing object file failed"));
        }
        if (import_object(&new_oid, type, raw, tmpfile)) {
                free(tmpfile);
        free(tmpfile);
  
        if (!oidcmp(&old_oid, &new_oid))
-               return error("new object is the same as the old one: '%s'", oid_to_hex(&old_oid));
+               return error(_("new object is the same as the old one: '%s'"), oid_to_hex(&old_oid));
  
        return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force);
  }
@@@ -368,10 -368,10 +368,10 @@@ static int replace_parents(struct strbu
                struct object_id oid;
                if (get_oid(argv[i], &oid) < 0) {
                        strbuf_release(&new_parents);
-                       return error(_("Not a valid object name: '%s'"),
+                       return error(_("not a valid object name: '%s'"),
                                     argv[i]);
                }
 -              if (!lookup_commit_reference(&oid)) {
 +              if (!lookup_commit_reference(the_repository, &oid)) {
                        strbuf_release(&new_parents);
                        return error(_("could not parse %s"), argv[i]);
                }
@@@ -402,17 -402,17 +402,17 @@@ static int check_one_mergetag(struct co
        int i;
  
        hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &tag_oid);
 -      tag = lookup_tag(&tag_oid);
 +      tag = lookup_tag(the_repository, &tag_oid);
        if (!tag)
                return error(_("bad mergetag in commit '%s'"), ref);
 -      if (parse_tag_buffer(tag, extra->value, extra->len))
 +      if (parse_tag_buffer(the_repository, tag, extra->value, extra->len))
                return error(_("malformed mergetag in commit '%s'"), ref);
  
        /* iterate over new parents */
        for (i = 1; i < mergetag_data->argc; i++) {
                struct object_id oid;
                if (get_oid(mergetag_data->argv[i], &oid) < 0)
-                       return error(_("Not a valid object name: '%s'"),
+                       return error(_("not a valid object name: '%s'"),
                                     mergetag_data->argv[i]);
                if (!oidcmp(&tag->tagged->oid, &oid))
                        return 0; /* found */
@@@ -442,8 -442,8 +442,8 @@@ static int create_graft(int argc, cons
        unsigned long size;
  
        if (get_oid(old_ref, &old_oid) < 0)
-               return error(_("Not a valid object name: '%s'"), old_ref);
+               return error(_("not a valid object name: '%s'"), old_ref);
 -      commit = lookup_commit_reference(&old_oid);
 +      commit = lookup_commit_reference(the_repository, &old_oid);
        if (!commit)
                return error(_("could not parse %s"), old_ref);
  
        }
  
        if (remove_signature(&buf)) {
-               warning(_("the original commit '%s' has a gpg signature."), old_ref);
+               warning(_("the original commit '%s' has a gpg signature"), old_ref);
                warning(_("the signature will be removed in the replacement commit!"));
        }
  
  
        if (!oidcmp(&old_oid, &new_oid)) {
                if (gentle) {
-                       warning("graft for '%s' unnecessary", oid_to_hex(&old_oid));
+                       warning(_("graft for '%s' unnecessary"), oid_to_hex(&old_oid));
                        return 0;
                }
-               return error("new commit is the same as the old one: '%s'", oid_to_hex(&old_oid));
+               return error(_("new commit is the same as the old one: '%s'"), oid_to_hex(&old_oid));
        }
  
        return replace_object_oid(old_ref, &old_oid, "replacement", &new_oid, force);
  
  static int convert_graft_file(int force)
  {
 -      const char *graft_file = get_graft_file();
 +      const char *graft_file = get_graft_file(the_repository);
        FILE *fp = fopen_or_warn(graft_file, "r");
        struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT;
        struct argv_array args = ARGV_ARRAY_INIT;
@@@ -544,7 -544,7 +544,7 @@@ int cmd_replace(int argc, const char **
                OPT_END()
        };
  
 -      check_replace_refs = 0;
 +      read_replace_refs = 0;
        git_config(git_default_config, NULL);
  
        argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
                cmdmode = argc ? MODE_REPLACE : MODE_LIST;
  
        if (format && cmdmode != MODE_LIST)
-               usage_msg_opt("--format cannot be used when not listing",
+               usage_msg_opt(_("--format cannot be used when not listing"),
                              git_replace_usage, options);
  
        if (force &&
            cmdmode != MODE_EDIT &&
            cmdmode != MODE_GRAFT &&
            cmdmode != MODE_CONVERT_GRAFT_FILE)
-               usage_msg_opt("-f only makes sense when writing a replacement",
+               usage_msg_opt(_("-f only makes sense when writing a replacement"),
                              git_replace_usage, options);
  
        if (raw && cmdmode != MODE_EDIT)
-               usage_msg_opt("--raw only makes sense with --edit",
+               usage_msg_opt(_("--raw only makes sense with --edit"),
                              git_replace_usage, options);
  
        switch (cmdmode) {
        case MODE_DELETE:
                if (argc < 1)
-                       usage_msg_opt("-d needs at least one argument",
+                       usage_msg_opt(_("-d needs at least one argument"),
                                      git_replace_usage, options);
                return for_each_replace_name(argv, delete_replace_ref);
  
        case MODE_REPLACE:
                if (argc != 2)
-                       usage_msg_opt("bad number of arguments",
+                       usage_msg_opt(_("bad number of arguments"),
                                      git_replace_usage, options);
                return replace_object(argv[0], argv[1], force);
  
        case MODE_EDIT:
                if (argc != 1)
-                       usage_msg_opt("-e needs exactly one argument",
+                       usage_msg_opt(_("-e needs exactly one argument"),
                                      git_replace_usage, options);
                return edit_and_replace(argv[0], force, raw);
  
        case MODE_GRAFT:
                if (argc < 1)
-                       usage_msg_opt("-g needs at least one argument",
+                       usage_msg_opt(_("-g needs at least one argument"),
                                      git_replace_usage, options);
                return create_graft(argc, argv, force, 0);
  
        case MODE_CONVERT_GRAFT_FILE:
                if (argc != 0)
-                       usage_msg_opt("--convert-graft-file takes no argument",
+                       usage_msg_opt(_("--convert-graft-file takes no argument"),
                                      git_replace_usage, options);
                return !!convert_graft_file(force);
  
        case MODE_LIST:
                if (argc > 1)
-                       usage_msg_opt("only one pattern can be given with -l",
+                       usage_msg_opt(_("only one pattern can be given with -l"),
                                      git_replace_usage, options);
                return list_replace_refs(argv[0], format);
  
diff --combined commit-graph.c
index b0a55ad128fbcaa2e34c25b8487856d20d0ad3d5,c8d521923c29fbc48d36ff3bd7cd02d5638b910e..0034740c26b48eda147d45258505df278b84cc0a
@@@ -7,12 -7,10 +7,12 @@@
  #include "packfile.h"
  #include "commit.h"
  #include "object.h"
 +#include "refs.h"
  #include "revision.h"
  #include "sha1-lookup.h"
  #include "commit-graph.h"
  #include "object-store.h"
 +#include "alloc.h"
  
  #define GRAPH_SIGNATURE 0x43475048 /* "CGPH" */
  #define GRAPH_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
  
  #define GRAPH_LAST_EDGE 0x80000000
  
 +#define GRAPH_HEADER_SIZE 8
  #define GRAPH_FANOUT_SIZE (4 * 256)
  #define GRAPH_CHUNKLOOKUP_WIDTH 12
 -#define GRAPH_MIN_SIZE (5 * GRAPH_CHUNKLOOKUP_WIDTH + GRAPH_FANOUT_SIZE + \
 -                      GRAPH_OID_LEN + 8)
 +#define GRAPH_MIN_SIZE (GRAPH_HEADER_SIZE + 4 * GRAPH_CHUNKLOOKUP_WIDTH \
 +                      + GRAPH_FANOUT_SIZE + GRAPH_OID_LEN)
  
  char *get_commit_graph_filename(const char *obj_dir)
  {
@@@ -80,28 -77,28 +80,28 @@@ struct commit_graph *load_commit_graph_
  
        if (graph_size < GRAPH_MIN_SIZE) {
                close(fd);
-               die("graph file %s is too small", graph_file);
+               die(_("graph file %s is too small"), graph_file);
        }
        graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
        data = (const unsigned char *)graph_map;
  
        graph_signature = get_be32(data);
        if (graph_signature != GRAPH_SIGNATURE) {
-               error("graph signature %X does not match signature %X",
+               error(_("graph signature %X does not match signature %X"),
                      graph_signature, GRAPH_SIGNATURE);
                goto cleanup_fail;
        }
  
        graph_version = *(unsigned char*)(data + 4);
        if (graph_version != GRAPH_VERSION) {
-               error("graph version %X does not match version %X",
+               error(_("graph version %X does not match version %X"),
                      graph_version, GRAPH_VERSION);
                goto cleanup_fail;
        }
  
        hash_version = *(unsigned char*)(data + 5);
        if (hash_version != GRAPH_OID_VERSION) {
-               error("hash version %X does not match version %X",
+               error(_("hash version %X does not match version %X"),
                      hash_version, GRAPH_OID_VERSION);
                goto cleanup_fail;
        }
                chunk_lookup += GRAPH_CHUNKLOOKUP_WIDTH;
  
                if (chunk_offset > graph_size - GIT_MAX_RAWSZ) {
-                       error("improper chunk offset %08x%08x", (uint32_t)(chunk_offset >> 32),
+                       error(_("improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
                              (uint32_t)chunk_offset);
                        goto cleanup_fail;
                }
                }
  
                if (chunk_repeated) {
-                       error("chunk id %08x appears multiple times", chunk_id);
+                       error(_("chunk id %08x appears multiple times"), chunk_id);
                        goto cleanup_fail;
                }
  
@@@ -183,60 -180,53 +183,60 @@@ cleanup_fail
        exit(1);
  }
  
 -/* global storage */
 -static struct commit_graph *commit_graph = NULL;
 -
 -static void prepare_commit_graph_one(const char *obj_dir)
 +static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
  {
        char *graph_name;
  
 -      if (commit_graph)
 +      if (r->objects->commit_graph)
                return;
  
        graph_name = get_commit_graph_filename(obj_dir);
 -      commit_graph = load_commit_graph_one(graph_name);
 +      r->objects->commit_graph =
 +              load_commit_graph_one(graph_name);
  
        FREE_AND_NULL(graph_name);
  }
  
 -static int prepare_commit_graph_run_once = 0;
 -static void prepare_commit_graph(void)
 +/*
 + * Return 1 if commit_graph is non-NULL, and 0 otherwise.
 + *
 + * On the first invocation, this function attemps to load the commit
 + * graph if the_repository is configured to have one.
 + */
 +static int prepare_commit_graph(struct repository *r)
  {
        struct alternate_object_database *alt;
        char *obj_dir;
 +      int config_value;
 +
 +      if (r->objects->commit_graph_attempted)
 +              return !!r->objects->commit_graph;
 +      r->objects->commit_graph_attempted = 1;
 +
 +      if (repo_config_get_bool(r, "core.commitgraph", &config_value) ||
 +          !config_value)
 +              /*
 +               * This repository is not configured to use commit graphs, so
 +               * do not load one. (But report commit_graph_attempted anyway
 +               * so that commit graph loading is not attempted again for this
 +               * repository.)
 +               */
 +              return 0;
  
 -      if (prepare_commit_graph_run_once)
 -              return;
 -      prepare_commit_graph_run_once = 1;
 -
 -      obj_dir = get_object_directory();
 -      prepare_commit_graph_one(obj_dir);
 -      prepare_alt_odb(the_repository);
 -      for (alt = the_repository->objects->alt_odb_list;
 -           !commit_graph && alt;
 +      obj_dir = r->objects->objectdir;
 +      prepare_commit_graph_one(r, obj_dir);
 +      prepare_alt_odb(r);
 +      for (alt = r->objects->alt_odb_list;
 +           !r->objects->commit_graph && alt;
             alt = alt->next)
 -              prepare_commit_graph_one(alt->path);
 +              prepare_commit_graph_one(r, alt->path);
 +      return !!r->objects->commit_graph;
  }
  
  static void close_commit_graph(void)
  {
 -      if (!commit_graph)
 -              return;
 -
 -      if (commit_graph->graph_fd >= 0) {
 -              munmap((void *)commit_graph->data, commit_graph->data_len);
 -              commit_graph->data = NULL;
 -              close(commit_graph->graph_fd);
 -      }
 -
 -      FREE_AND_NULL(commit_graph);
 +      free_commit_graph(the_repository->objects->commit_graph);
 +      the_repository->objects->commit_graph = NULL;
  }
  
  static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos)
@@@ -251,14 -241,10 +251,14 @@@ static struct commit_list **insert_pare
  {
        struct commit *c;
        struct object_id oid;
 +
 +      if (pos >= g->num_commits)
 +              die("invalid parent position %"PRIu64, pos);
 +
        hashcpy(oid.hash, g->chunk_oid_lookup + g->hash_len * pos);
 -      c = lookup_commit(&oid);
 +      c = lookup_commit(the_repository, &oid);
        if (!c)
-               die("could not find commit %s", oid_to_hex(&oid));
+               die(_("could not find commit %s"), oid_to_hex(&oid));
        c->graph_pos = pos;
        return &commit_list_insert(c, pptr)->next;
  }
@@@ -327,33 -313,28 +327,33 @@@ static int find_commit_in_graph(struct 
        }
  }
  
 -int parse_commit_in_graph(struct commit *item)
 +static int parse_commit_in_graph_one(struct commit_graph *g, struct commit *item)
  {
        uint32_t pos;
  
 -      if (!core_commit_graph)
 -              return 0;
        if (item->object.parsed)
                return 1;
 -      prepare_commit_graph();
 -      if (commit_graph && find_commit_in_graph(item, commit_graph, &pos))
 -              return fill_commit_in_graph(item, commit_graph, pos);
 +
 +      if (find_commit_in_graph(item, g, &pos))
 +              return fill_commit_in_graph(item, g, pos);
 +
        return 0;
  }
  
 -void load_commit_graph_info(struct commit *item)
 +int parse_commit_in_graph(struct repository *r, struct commit *item)
 +{
 +      if (!prepare_commit_graph(r))
 +              return 0;
 +      return parse_commit_in_graph_one(r->objects->commit_graph, item);
 +}
 +
 +void load_commit_graph_info(struct repository *r, struct commit *item)
  {
        uint32_t pos;
 -      if (!core_commit_graph)
 +      if (!prepare_commit_graph(r))
                return;
 -      prepare_commit_graph();
 -      if (commit_graph && find_commit_in_graph(item, commit_graph, &pos))
 -              fill_commit_graph_info(item, commit_graph, pos);
 +      if (find_commit_in_graph(item, r->objects->commit_graph, &pos))
 +              fill_commit_graph_info(item, r->objects->commit_graph, pos);
  }
  
  static struct tree *load_tree_for_commit(struct commit_graph *g, struct commit *c)
                                           GRAPH_DATA_WIDTH * (c->graph_pos);
  
        hashcpy(oid.hash, commit_data);
 -      c->maybe_tree = lookup_tree(&oid);
 +      c->maybe_tree = lookup_tree(the_repository, &oid);
  
        return c->maybe_tree;
  }
  
 -struct tree *get_commit_tree_in_graph(const struct commit *c)
 +static struct tree *get_commit_tree_in_graph_one(struct commit_graph *g,
 +                                               const struct commit *c)
  {
        if (c->maybe_tree)
                return c->maybe_tree;
        if (c->graph_pos == COMMIT_NOT_FROM_GRAPH)
 -              BUG("get_commit_tree_in_graph called from non-commit-graph commit");
 +              BUG("get_commit_tree_in_graph_one called from non-commit-graph commit");
  
 -      return load_tree_for_commit(commit_graph, (struct commit *)c);
 +      return load_tree_for_commit(g, (struct commit *)c);
 +}
 +
 +struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit *c)
 +{
 +      return get_commit_tree_in_graph_one(r->objects->commit_graph, c);
  }
  
  static void write_graph_chunk_fanout(struct hashfile *f,
@@@ -562,7 -537,7 +562,7 @@@ static int add_packed_commits(const str
  
        oi.typep = &type;
        if (packed_object_info(the_repository, pack, offset, &oi) < 0)
-               die("unable to get type of object %s", oid_to_hex(oid));
+               die(_("unable to get type of object %s"), oid_to_hex(oid));
  
        if (type != OBJ_COMMIT)
                return 0;
@@@ -593,7 -568,7 +593,7 @@@ static void close_reachable(struct pack
        struct commit *commit;
  
        for (i = 0; i < oids->nr; i++) {
 -              commit = lookup_commit(&oids->list[i]);
 +              commit = lookup_commit(the_repository, &oids->list[i]);
                if (commit)
                        commit->object.flags |= UNINTERESTING;
        }
         * closure.
         */
        for (i = 0; i < oids->nr; i++) {
 -              commit = lookup_commit(&oids->list[i]);
 +              commit = lookup_commit(the_repository, &oids->list[i]);
  
                if (commit && !parse_commit(commit))
                        add_missing_parents(oids, commit);
        }
  
        for (i = 0; i < oids->nr; i++) {
 -              commit = lookup_commit(&oids->list[i]);
 +              commit = lookup_commit(the_repository, &oids->list[i]);
  
                if (commit)
                        commit->object.flags &= ~UNINTERESTING;
@@@ -657,28 -632,11 +657,28 @@@ static void compute_generation_numbers(
        }
  }
  
 +static int add_ref_to_list(const char *refname,
 +                         const struct object_id *oid,
 +                         int flags, void *cb_data)
 +{
 +      struct string_list *list = (struct string_list *)cb_data;
 +
 +      string_list_append(list, oid_to_hex(oid));
 +      return 0;
 +}
 +
 +void write_commit_graph_reachable(const char *obj_dir, int append)
 +{
 +      struct string_list list;
 +
 +      string_list_init(&list, 1);
 +      for_each_ref(add_ref_to_list, &list);
 +      write_commit_graph(obj_dir, NULL, &list, append);
 +}
 +
  void write_commit_graph(const char *obj_dir,
 -                      const char **pack_indexes,
 -                      int nr_packs,
 -                      const char **commit_hex,
 -                      int nr_commits,
 +                      struct string_list *pack_indexes,
 +                      struct string_list *commit_hex,
                        int append)
  {
        struct packed_oid_list oids;
        oids.alloc = approximate_object_count() / 4;
  
        if (append) {
 -              prepare_commit_graph_one(obj_dir);
 -              if (commit_graph)
 -                      oids.alloc += commit_graph->num_commits;
 +              prepare_commit_graph_one(the_repository, obj_dir);
 +              if (the_repository->objects->commit_graph)
 +                      oids.alloc += the_repository->objects->commit_graph->num_commits;
        }
  
        if (oids.alloc < 1024)
                oids.alloc = 1024;
        ALLOC_ARRAY(oids.list, oids.alloc);
  
 -      if (append && commit_graph) {
 +      if (append && the_repository->objects->commit_graph) {
 +              struct commit_graph *commit_graph =
 +                      the_repository->objects->commit_graph;
                for (i = 0; i < commit_graph->num_commits; i++) {
                        const unsigned char *hash = commit_graph->chunk_oid_lookup +
                                commit_graph->hash_len * i;
                int dirlen;
                strbuf_addf(&packname, "%s/pack/", obj_dir);
                dirlen = packname.len;
 -              for (i = 0; i < nr_packs; i++) {
 +              for (i = 0; i < pack_indexes->nr; i++) {
                        struct packed_git *p;
                        strbuf_setlen(&packname, dirlen);
 -                      strbuf_addstr(&packname, pack_indexes[i]);
 +                      strbuf_addstr(&packname, pack_indexes->items[i].string);
                        p = add_packed_git(packname.buf, packname.len, 1);
                        if (!p)
-                               die("error adding pack %s", packname.buf);
+                               die(_("error adding pack %s"), packname.buf);
                        if (open_pack_index(p))
-                               die("error opening index for %s", packname.buf);
+                               die(_("error opening index for %s"), packname.buf);
                        for_each_object_in_pack(p, add_packed_commits, &oids);
                        close_pack(p);
                }
        }
  
        if (commit_hex) {
 -              for (i = 0; i < nr_commits; i++) {
 +              for (i = 0; i < commit_hex->nr; i++) {
                        const char *end;
                        struct object_id oid;
                        struct commit *result;
  
 -                      if (commit_hex[i] && parse_oid_hex(commit_hex[i], &oid, &end))
 +                      if (commit_hex->items[i].string &&
 +                          parse_oid_hex(commit_hex->items[i].string, &oid, &end))
                                continue;
  
 -                      result = lookup_commit_reference_gently(&oid, 1);
 +                      result = lookup_commit_reference_gently(the_repository, &oid, 1);
  
                        if (result) {
                                ALLOC_GROW(oids.list, oids.nr + 1, oids.alloc);
                if (i > 0 && !oidcmp(&oids.list[i-1], &oids.list[i]))
                        continue;
  
 -              commits.list[commits.nr] = lookup_commit(&oids.list[i]);
 +              commits.list[commits.nr] = lookup_commit(the_repository, &oids.list[i]);
                parse_commit(commits.list[commits.nr]);
  
                for (parent = commits.list[commits.nr]->parents;
        oids.alloc = 0;
        oids.nr = 0;
  }
 +
 +#define VERIFY_COMMIT_GRAPH_ERROR_HASH 2
 +static int verify_commit_graph_error;
 +
 +static void graph_report(const char *fmt, ...)
 +{
 +      va_list ap;
 +
 +      verify_commit_graph_error = 1;
 +      va_start(ap, fmt);
 +      vfprintf(stderr, fmt, ap);
 +      fprintf(stderr, "\n");
 +      va_end(ap);
 +}
 +
 +#define GENERATION_ZERO_EXISTS 1
 +#define GENERATION_NUMBER_EXISTS 2
 +
 +int verify_commit_graph(struct repository *r, struct commit_graph *g)
 +{
 +      uint32_t i, cur_fanout_pos = 0;
 +      struct object_id prev_oid, cur_oid, checksum;
 +      int generation_zero = 0;
 +      struct hashfile *f;
 +      int devnull;
 +
 +      if (!g) {
 +              graph_report("no commit-graph file loaded");
 +              return 1;
 +      }
 +
 +      verify_commit_graph_error = 0;
 +
 +      if (!g->chunk_oid_fanout)
 +              graph_report("commit-graph is missing the OID Fanout chunk");
 +      if (!g->chunk_oid_lookup)
 +              graph_report("commit-graph is missing the OID Lookup chunk");
 +      if (!g->chunk_commit_data)
 +              graph_report("commit-graph is missing the Commit Data chunk");
 +
 +      if (verify_commit_graph_error)
 +              return verify_commit_graph_error;
 +
 +      devnull = open("/dev/null", O_WRONLY);
 +      f = hashfd(devnull, NULL);
 +      hashwrite(f, g->data, g->data_len - g->hash_len);
 +      finalize_hashfile(f, checksum.hash, CSUM_CLOSE);
 +      if (hashcmp(checksum.hash, g->data + g->data_len - g->hash_len)) {
 +              graph_report(_("the commit-graph file has incorrect checksum and is likely corrupt"));
 +              verify_commit_graph_error = VERIFY_COMMIT_GRAPH_ERROR_HASH;
 +      }
 +
 +      for (i = 0; i < g->num_commits; i++) {
 +              struct commit *graph_commit;
 +
 +              hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
 +
 +              if (i && oidcmp(&prev_oid, &cur_oid) >= 0)
 +                      graph_report("commit-graph has incorrect OID order: %s then %s",
 +                                   oid_to_hex(&prev_oid),
 +                                   oid_to_hex(&cur_oid));
 +
 +              oidcpy(&prev_oid, &cur_oid);
 +
 +              while (cur_oid.hash[0] > cur_fanout_pos) {
 +                      uint32_t fanout_value = get_be32(g->chunk_oid_fanout + cur_fanout_pos);
 +
 +                      if (i != fanout_value)
 +                              graph_report("commit-graph has incorrect fanout value: fanout[%d] = %u != %u",
 +                                           cur_fanout_pos, fanout_value, i);
 +                      cur_fanout_pos++;
 +              }
 +
 +              graph_commit = lookup_commit(r, &cur_oid);
 +              if (!parse_commit_in_graph_one(g, graph_commit))
 +                      graph_report("failed to parse %s from commit-graph",
 +                                   oid_to_hex(&cur_oid));
 +      }
 +
 +      while (cur_fanout_pos < 256) {
 +              uint32_t fanout_value = get_be32(g->chunk_oid_fanout + cur_fanout_pos);
 +
 +              if (g->num_commits != fanout_value)
 +                      graph_report("commit-graph has incorrect fanout value: fanout[%d] = %u != %u",
 +                                   cur_fanout_pos, fanout_value, i);
 +
 +              cur_fanout_pos++;
 +      }
 +
 +      if (verify_commit_graph_error & ~VERIFY_COMMIT_GRAPH_ERROR_HASH)
 +              return verify_commit_graph_error;
 +
 +      for (i = 0; i < g->num_commits; i++) {
 +              struct commit *graph_commit, *odb_commit;
 +              struct commit_list *graph_parents, *odb_parents;
 +              uint32_t max_generation = 0;
 +
 +              hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
 +
 +              graph_commit = lookup_commit(r, &cur_oid);
 +              odb_commit = (struct commit *)create_object(r, cur_oid.hash, alloc_commit_node(r));
 +              if (parse_commit_internal(odb_commit, 0, 0)) {
 +                      graph_report("failed to parse %s from object database",
 +                                   oid_to_hex(&cur_oid));
 +                      continue;
 +              }
 +
 +              if (oidcmp(&get_commit_tree_in_graph_one(g, graph_commit)->object.oid,
 +                         get_commit_tree_oid(odb_commit)))
 +                      graph_report("root tree OID for commit %s in commit-graph is %s != %s",
 +                                   oid_to_hex(&cur_oid),
 +                                   oid_to_hex(get_commit_tree_oid(graph_commit)),
 +                                   oid_to_hex(get_commit_tree_oid(odb_commit)));
 +
 +              graph_parents = graph_commit->parents;
 +              odb_parents = odb_commit->parents;
 +
 +              while (graph_parents) {
 +                      if (odb_parents == NULL) {
 +                              graph_report("commit-graph parent list for commit %s is too long",
 +                                           oid_to_hex(&cur_oid));
 +                              break;
 +                      }
 +
 +                      if (oidcmp(&graph_parents->item->object.oid, &odb_parents->item->object.oid))
 +                              graph_report("commit-graph parent for %s is %s != %s",
 +                                           oid_to_hex(&cur_oid),
 +                                           oid_to_hex(&graph_parents->item->object.oid),
 +                                           oid_to_hex(&odb_parents->item->object.oid));
 +
 +                      if (graph_parents->item->generation > max_generation)
 +                              max_generation = graph_parents->item->generation;
 +
 +                      graph_parents = graph_parents->next;
 +                      odb_parents = odb_parents->next;
 +              }
 +
 +              if (odb_parents != NULL)
 +                      graph_report("commit-graph parent list for commit %s terminates early",
 +                                   oid_to_hex(&cur_oid));
 +
 +              if (!graph_commit->generation) {
 +                      if (generation_zero == GENERATION_NUMBER_EXISTS)
 +                              graph_report("commit-graph has generation number zero for commit %s, but non-zero elsewhere",
 +                                           oid_to_hex(&cur_oid));
 +                      generation_zero = GENERATION_ZERO_EXISTS;
 +              } else if (generation_zero == GENERATION_ZERO_EXISTS)
 +                      graph_report("commit-graph has non-zero generation number for commit %s, but zero elsewhere",
 +                                   oid_to_hex(&cur_oid));
 +
 +              if (generation_zero == GENERATION_ZERO_EXISTS)
 +                      continue;
 +
 +              /*
 +               * If one of our parents has generation GENERATION_NUMBER_MAX, then
 +               * our generation is also GENERATION_NUMBER_MAX. Decrement to avoid
 +               * extra logic in the following condition.
 +               */
 +              if (max_generation == GENERATION_NUMBER_MAX)
 +                      max_generation--;
 +
 +              if (graph_commit->generation != max_generation + 1)
 +                      graph_report("commit-graph generation for commit %s is %u != %u",
 +                                   oid_to_hex(&cur_oid),
 +                                   graph_commit->generation,
 +                                   max_generation + 1);
 +
 +              if (graph_commit->date != odb_commit->date)
 +                      graph_report("commit date for commit %s in commit-graph is %"PRItime" != %"PRItime,
 +                                   oid_to_hex(&cur_oid),
 +                                   graph_commit->date,
 +                                   odb_commit->date);
 +      }
 +
 +      return verify_commit_graph_error;
 +}
 +
 +void free_commit_graph(struct commit_graph *g)
 +{
 +      if (!g)
 +              return;
 +      if (g->graph_fd >= 0) {
 +              munmap((void *)g->data, g->data_len);
 +              g->data = NULL;
 +              close(g->graph_fd);
 +      }
 +      free(g);
 +}
diff --combined config.c
index efe27d5e525a8ce15d588c0dad1fff184952b927,736b9f23f7edb28601fe3505df34e86c0cbfddfb..10522f399e6eb5300b55eaeaf8fcbf6546e53d11
+++ b/config.c
@@@ -14,7 -14,6 +14,7 @@@
  #include "quote.h"
  #include "hashmap.h"
  #include "string-list.h"
 +#include "object-store.h"
  #include "utf8.h"
  #include "dir.h"
  #include "color.h"
@@@ -32,7 -31,7 +32,7 @@@ struct config_source 
        enum config_origin_type origin_type;
        const char *name;
        const char *path;
 -      int die_on_error;
 +      enum config_error_action default_error_action;
        int linenr;
        int eof;
        struct strbuf value;
@@@ -117,12 -116,12 +117,12 @@@ static long config_buf_ftell(struct con
  }
  
  #define MAX_INCLUDE_DEPTH 10
- static const char include_depth_advice[] =
+ static const char include_depth_advice[] = N_(
  "exceeded maximum include depth (%d) while including\n"
  "     %s\n"
  "from\n"
  "     %s\n"
- "Do you have circular includes?";
+ "Do you have circular includes?");
  static int handle_path_include(const char *path, struct config_include_data *inc)
  {
        int ret = 0;
  
        expanded = expand_user_path(path, 0);
        if (!expanded)
-               return error("could not expand include path '%s'", path);
+               return error(_("could not expand include path '%s'"), path);
        path = expanded;
  
        /*
                char *slash;
  
                if (!cf || !cf->path)
-                       return error("relative config includes must come from files");
+                       return error(_("relative config includes must come from files"));
  
                slash = find_last_dir_sep(cf->path);
                if (slash)
  
        if (!access_or_die(path, R_OK, 0)) {
                if (++inc->depth > MAX_INCLUDE_DEPTH)
-                       die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
+                       die(_(include_depth_advice), MAX_INCLUDE_DEPTH, path,
                            !cf ? "<unknown>" :
                            cf->name ? cf->name :
                            "the command line");
@@@ -343,13 -342,13 +343,13 @@@ static int git_config_parse_key_1(cons
  
        if (last_dot == NULL || last_dot == key) {
                if (!quiet)
-                       error("key does not contain a section: %s", key);
+                       error(_("key does not contain a section: %s"), key);
                return -CONFIG_NO_SECTION_OR_NAME;
        }
  
        if (!last_dot[1]) {
                if (!quiet)
-                       error("key does not contain variable name: %s", key);
+                       error(_("key does not contain variable name: %s"), key);
                return -CONFIG_NO_SECTION_OR_NAME;
        }
  
                        if (!iskeychar(c) ||
                            (i == baselen + 1 && !isalpha(c))) {
                                if (!quiet)
-                                       error("invalid key: %s", key);
+                                       error(_("invalid key: %s"), key);
                                goto out_free_ret_1;
                        }
                        c = tolower(c);
                } else if (c == '\n') {
                        if (!quiet)
-                               error("invalid key (newline): %s", key);
+                               error(_("invalid key (newline): %s"), key);
                        goto out_free_ret_1;
                }
                if (store_key)
@@@ -415,7 -414,7 +415,7 @@@ int git_config_parse_parameter(const ch
  
        pair = strbuf_split_str(text, '=', 2);
        if (!pair[0])
-               return error("bogus config parameter: %s", text);
+               return error(_("bogus config parameter: %s"), text);
  
        if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') {
                strbuf_setlen(pair[0], pair[0]->len - 1);
        strbuf_trim(pair[0]);
        if (!pair[0]->len) {
                strbuf_list_free(pair);
-               return error("bogus config parameter: %s", text);
+               return error(_("bogus config parameter: %s"), text);
        }
  
        if (git_config_parse_key(pair[0]->buf, &canonical_name, NULL)) {
@@@ -462,7 -461,7 +462,7 @@@ int git_config_from_parameters(config_f
        envw = xstrdup(env);
  
        if (sq_dequote_to_argv(envw, &argv, &nr, &alloc) < 0) {
-               ret = error("bogus format in " CONFIG_DATA_ENVIRONMENT);
+               ret = error(_("bogus format in %s"), CONFIG_DATA_ENVIRONMENT);
                goto out;
        }
  
@@@ -810,21 -809,10 +810,21 @@@ static int git_parse_source(config_fn_
                                      cf->linenr, cf->name);
        }
  
 -      if (cf->die_on_error)
 +      switch (opts && opts->error_action ?
 +              opts->error_action :
 +              cf->default_error_action) {
 +      case CONFIG_ERROR_DIE:
                die("%s", error_msg);
 -      else
 +              break;
 +      case CONFIG_ERROR_ERROR:
                error_return = error("%s", error_msg);
 +              break;
 +      case CONFIG_ERROR_SILENT:
 +              error_return = -1;
 +              break;
 +      case CONFIG_ERROR_UNSET:
 +              BUG("config error action unset");
 +      }
  
        free(error_msg);
        return error_return;
@@@ -1166,7 -1154,7 +1166,7 @@@ static int git_default_core_config(cons
                else {
                        int abbrev = git_config_int(var, value);
                        if (abbrev < minimum_abbrev || abbrev > 40)
-                               return error("abbrev length out of range: %d", abbrev);
+                               return error(_("abbrev length out of range: %d"), abbrev);
                        default_abbrev = abbrev;
                }
                return 0;
                        comment_line_char = value[0];
                        auto_comment_line_char = 0;
                } else
-                       return error("core.commentChar should only be one character");
+                       return error(_("core.commentChar should only be one character"));
                return 0;
        }
  
                return 0;
        }
  
 -      if (!strcmp(var, "core.commitgraph")) {
 -              core_commit_graph = git_config_bool(var, value);
 -              return 0;
 -      }
 -
        if (!strcmp(var, "core.sparsecheckout")) {
                core_apply_sparse_checkout = git_config_bool(var, value);
                return 0;
                                         var, value);
        }
  
 +      if (!strcmp(var, "core.usereplacerefs")) {
 +              read_replace_refs = git_config_bool(var, value);
 +              return 0;
 +      }
 +
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
  }
@@@ -1396,7 -1384,7 +1396,7 @@@ static int git_default_branch_config(co
                else if (!strcmp(value, "always"))
                        autorebase = AUTOREBASE_ALWAYS;
                else
-                       return error("malformed value for %s", var);
+                       return error(_("malformed value for %s"), var);
                return 0;
        }
  
@@@ -1422,9 -1410,9 +1422,9 @@@ static int git_default_push_config(cons
                else if (!strcmp(value, "current"))
                        push_default = PUSH_DEFAULT_CURRENT;
                else {
-                       error("malformed value for %s: %s", var, value);
-                       return error("Must be one of nothing, matching, simple, "
-                                    "upstream or current.");
+                       error(_("malformed value for %s: %s"), var, value);
+                       return error(_("must be one of nothing, matching, simple, "
+                                      "upstream or current"));
                }
                return 0;
        }
@@@ -1532,7 -1520,7 +1532,7 @@@ static int do_config_from_file(config_f
        top.origin_type = origin_type;
        top.name = name;
        top.path = path;
 -      top.die_on_error = 1;
 +      top.default_error_action = CONFIG_ERROR_DIE;
        top.do_fgetc = config_file_fgetc;
        top.do_ungetc = config_file_ungetc;
        top.do_ftell = config_file_ftell;
@@@ -1570,10 -1558,8 +1570,10 @@@ int git_config_from_file(config_fn_t fn
        return git_config_from_file_with_options(fn, filename, data, NULL);
  }
  
 -int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_type,
 -                      const char *name, const char *buf, size_t len, void *data)
 +int git_config_from_mem(config_fn_t fn,
 +                      const enum config_origin_type origin_type,
 +                      const char *name, const char *buf, size_t len,
 +                      void *data, const struct config_options *opts)
  {
        struct config_source top;
  
        top.origin_type = origin_type;
        top.name = name;
        top.path = NULL;
 -      top.die_on_error = 0;
 +      top.default_error_action = CONFIG_ERROR_ERROR;
        top.do_fgetc = config_buf_fgetc;
        top.do_ungetc = config_buf_ungetc;
        top.do_ftell = config_buf_ftell;
  
 -      return do_config_from(&top, fn, data, NULL);
 +      return do_config_from(&top, fn, data, opts);
  }
  
  int git_config_from_blob_oid(config_fn_t fn,
  
        buf = read_object_file(oid, &type, &size);
        if (!buf)
-               return error("unable to load config blob object '%s'", name);
+               return error(_("unable to load config blob object '%s'"), name);
        if (type != OBJ_BLOB) {
                free(buf);
-               return error("reference '%s' does not point to a blob", name);
+               return error(_("reference '%s' does not point to a blob"), name);
        }
  
 -      ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size, data);
 +      ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size,
 +                                data, NULL);
        free(buf);
  
        return ret;
@@@ -1623,7 -1608,7 +1623,7 @@@ static int git_config_from_blob_ref(con
        struct object_id oid;
  
        if (get_oid(name, &oid) < 0)
-               return error("unable to resolve config blob '%s'", name);
+               return error(_("unable to resolve config blob '%s'"), name);
        return git_config_from_blob_oid(fn, name, &oid, data);
  }
  
@@@ -1653,7 -1638,7 +1653,7 @@@ unsigned long git_env_ulong(const char 
  {
        const char *v = getenv(k);
        if (v && !git_parse_ulong(v, &val))
-               die("failed to parse %s", k);
+               die(_("failed to parse %s"), k);
        return val;
  }
  
@@@ -2187,6 -2172,23 +2187,6 @@@ int git_config_get_pathname(const char 
        return repo_config_get_pathname(the_repository, key, dest);
  }
  
 -/*
 - * Note: This function exists solely to maintain backward compatibility with
 - * 'fetch' and 'update_clone' storing configuration in '.gitmodules' and should
 - * NOT be used anywhere else.
 - *
 - * Runs the provided config function on the '.gitmodules' file found in the
 - * working directory.
 - */
 -void config_from_gitmodules(config_fn_t fn, void *data)
 -{
 -      if (the_repository->worktree) {
 -              char *file = repo_worktree_path(the_repository, GITMODULES_FILE);
 -              git_config_from_file(fn, file, data);
 -              free(file);
 -      }
 -}
 -
  int git_config_get_expiry(const char *key, const char **output)
  {
        int ret = git_config_get_string_const(key, output);
@@@ -2370,7 -2372,7 +2370,7 @@@ static int store_aux_event(enum config_
  
        if (type == CONFIG_EVENT_SECTION) {
                if (cf->var.len < 2 || cf->var.buf[cf->var.len - 1] != '.')
-                       return error("invalid section name '%s'", cf->var.buf);
+                       return error(_("invalid section name '%s'"), cf->var.buf);
  
                /* Is this the section we were looking for? */
                store->is_keys_section =
@@@ -2426,7 -2428,7 +2426,7 @@@ static int store_aux(const char *key, c
  
  static int write_error(const char *filename)
  {
-       error("failed to write new configuration file %s", filename);
+       error(_("failed to write new configuration file %s"), filename);
  
        /* Same error code as "failed to rename". */
        return 4;
@@@ -2677,7 -2679,7 +2677,7 @@@ int git_config_set_multivar_in_file_gen
         */
        fd = hold_lock_file_for_update(&lock, config_filename, 0);
        if (fd < 0) {
-               error_errno("could not lock config file %s", config_filename);
+               error_errno(_("could not lock config file %s"), config_filename);
                ret = CONFIG_NO_LOCK;
                goto out_free;
        }
        in_fd = open(config_filename, O_RDONLY);
        if ( in_fd < 0 ) {
                if ( ENOENT != errno ) {
-                       error_errno("opening %s", config_filename);
+                       error_errno(_("opening %s"), config_filename);
                        ret = CONFIG_INVALID_FILE; /* same as "invalid config file" */
                        goto out_free;
                }
                        store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
                        if (regcomp(store.value_regex, value_regex,
                                        REG_EXTENDED)) {
-                               error("invalid pattern: %s", value_regex);
+                               error(_("invalid pattern: %s"), value_regex);
                                FREE_AND_NULL(store.value_regex);
                                ret = CONFIG_INVALID_PATTERN;
                                goto out_free;
                if (git_config_from_file_with_options(store_aux,
                                                      config_filename,
                                                      &store, &opts)) {
-                       error("invalid config file %s", config_filename);
+                       error(_("invalid config file %s"), config_filename);
                        ret = CONFIG_INVALID_FILE;
                        goto out_free;
                }
                if (contents == MAP_FAILED) {
                        if (errno == ENODEV && S_ISDIR(st.st_mode))
                                errno = EISDIR;
-                       error_errno("unable to mmap '%s'", config_filename);
+                       error_errno(_("unable to mmap '%s'"), config_filename);
                        ret = CONFIG_INVALID_FILE;
                        contents = NULL;
                        goto out_free;
                in_fd = -1;
  
                if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
-                       error_errno("chmod on %s failed", get_lock_file_path(&lock));
+                       error_errno(_("chmod on %s failed"), get_lock_file_path(&lock));
                        ret = CONFIG_NO_WRITE;
                        goto out_free;
                }
        }
  
        if (commit_lock_file(&lock) < 0) {
-               error_errno("could not write config file %s", config_filename);
+               error_errno(_("could not write config file %s"), config_filename);
                ret = CONFIG_NO_WRITE;
                goto out_free;
        }
@@@ -2992,7 -2994,7 +2992,7 @@@ static int git_config_copy_or_rename_se
        memset(&store, 0, sizeof(store));
  
        if (new_name && !section_name_is_ok(new_name)) {
-               ret = error("invalid section name: %s", new_name);
+               ret = error(_("invalid section name: %s"), new_name);
                goto out_no_rollback;
        }
  
  
        out_fd = hold_lock_file_for_update(&lock, config_filename, 0);
        if (out_fd < 0) {
-               ret = error("could not lock config file %s", config_filename);
+               ret = error(_("could not lock config file %s"), config_filename);
                goto out;
        }
  
        }
  
        if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
-               ret = error_errno("chmod on %s failed",
+               ret = error_errno(_("chmod on %s failed"),
                                  get_lock_file_path(&lock));
                goto out;
        }
        config_file = NULL;
  commit_and_out:
        if (commit_lock_file(&lock) < 0)
-               ret = error_errno("could not write config file %s",
+               ret = error_errno(_("could not write config file %s"),
                                  config_filename);
  out:
        if (config_file)
@@@ -3159,7 -3161,7 +3159,7 @@@ int git_config_copy_section(const char 
  #undef config_error_nonbool
  int config_error_nonbool(const char *var)
  {
-       return error("missing value for '%s'", var);
+       return error(_("missing value for '%s'"), var);
  }
  
  int parse_config_key(const char *var,
diff --combined convert.c
index 7907efd16f279df81ca18f2f370bb89380ccf921,e53911d4f835e087cf4c44a93307388bea9711fa..3ee4bc274b302bbb59fd94d96d50a6c44376f0fd
+++ b/convert.c
@@@ -1,7 -1,6 +1,7 @@@
  #define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
  #include "config.h"
 +#include "object-store.h"
  #include "attr.h"
  #include "run-command.h"
  #include "quote.h"
@@@ -191,7 -190,7 +191,7 @@@ static enum eol output_eol(enum crlf_ac
                /* fall through */
                return text_eol_is_crlf() ? EOL_CRLF : EOL_LF;
        }
-       warning("Illegal crlf_action %d\n", (int)crlf_action);
+       warning(_("illegal crlf_action %d"), (int)crlf_action);
        return core_eol;
  }
  
@@@ -204,11 -203,11 +204,11 @@@ static void check_global_conv_flags_eol
                 * CRLFs would not be restored by checkout
                 */
                if (conv_flags & CONV_EOL_RNDTRP_DIE)
-                       die(_("CRLF would be replaced by LF in %s."), path);
+                       die(_("CRLF would be replaced by LF in %s"), path);
                else if (conv_flags & CONV_EOL_RNDTRP_WARN)
                        warning(_("CRLF will be replaced by LF in %s.\n"
                                  "The file will have its original line"
-                                 " endings in your working directory."), path);
+                                 " endings in your working directory"), path);
        } else if (old_stats->lonelf && !new_stats->lonelf ) {
                /*
                 * CRLFs would be added by checkout
                else if (conv_flags & CONV_EOL_RNDTRP_WARN)
                        warning(_("LF will be replaced by CRLF in %s.\n"
                                  "The file will have its original line"
-                                 " endings in your working directory."), path);
+                                 " endings in your working directory"), path);
        }
  }
  
@@@ -335,7 -334,7 +335,7 @@@ static void trace_encoding(const char *
        strbuf_addf(&trace, "%s (%s, considered %s):\n", context, path, encoding);
        for (i = 0; i < len && buf; ++i) {
                strbuf_addf(
 -                      &trace,"| \e[2m%2i:\e[0m %2x \e[2m%c\e[0m%c",
 +                      &trace, "| \033[2m%2i:\033[0m %2x \033[2m%c\033[0m%c",
                        i,
                        (unsigned char) buf[i],
                        (buf[i] > 32 && buf[i] < 127 ? buf[i] : ' '),
@@@ -493,8 -492,8 +493,8 @@@ static int encode_to_worktree(const cha
        dst = reencode_string_len(src, src_len, enc, default_encoding,
                                  &dst_len);
        if (!dst) {
-               error("failed to encode '%s' from %s to %s",
-                       path, default_encoding, enc);
+               error(_("failed to encode '%s' from %s to %s"),
+                     path, default_encoding, enc);
                return 0;
        }
  
@@@ -671,7 -670,8 +671,8 @@@ static int filter_buffer_or_fd(int in, 
  
        if (start_command(&child_process)) {
                strbuf_release(&cmd);
-               return error("cannot fork to run external filter '%s'", params->cmd);
+               return error(_("cannot fork to run external filter '%s'"),
+                            params->cmd);
        }
  
        sigchain_push(SIGPIPE, SIG_IGN);
        if (close(child_process.in))
                write_err = 1;
        if (write_err)
-               error("cannot feed the input to external filter '%s'", params->cmd);
+               error(_("cannot feed the input to external filter '%s'"),
+                     params->cmd);
  
        sigchain_pop(SIGPIPE);
  
        status = finish_command(&child_process);
        if (status)
-               error("external filter '%s' failed %d", params->cmd, status);
+               error(_("external filter '%s' failed %d"), params->cmd, status);
  
        strbuf_release(&cmd);
        return (write_err || status);
@@@ -731,13 -732,13 +733,13 @@@ static int apply_single_file_filter(con
                return 0;       /* error was already reported */
  
        if (strbuf_read(&nbuf, async.out, len) < 0) {
-               err = error("read from external filter '%s' failed", cmd);
+               err = error(_("read from external filter '%s' failed"), cmd);
        }
        if (close(async.out)) {
-               err = error("read from external filter '%s' failed", cmd);
+               err = error(_("read from external filter '%s' failed"), cmd);
        }
        if (finish_async(&async)) {
-               err = error("external filter '%s' failed", cmd);
+               err = error(_("external filter '%s' failed"), cmd);
        }
  
        if (!err) {
@@@ -791,7 -792,7 +793,7 @@@ static void handle_filter_error(const s
                 * Something went wrong with the protocol filter.
                 * Force shutdown and restart if another blob requires filtering.
                 */
-               error("external filter '%s' failed", entry->subprocess.cmd);
+               error(_("external filter '%s' failed"), entry->subprocess.cmd);
                subprocess_stop(&subprocess_map, &entry->subprocess);
                free(entry);
        }
@@@ -839,7 -840,7 +841,7 @@@ static int apply_multi_file_filter(cons
        else if (wanted_capability & CAP_SMUDGE)
                filter_type = "smudge";
        else
-               die("unexpected filter type");
+               die(_("unexpected filter type"));
  
        sigchain_push(SIGPIPE, SIG_IGN);
  
  
        err = strlen(path) > LARGE_PACKET_DATA_MAX - strlen("pathname=\n");
        if (err) {
-               error("path name too long for external filter");
+               error(_("path name too long for external filter"));
                goto done;
        }
  
@@@ -924,8 -925,8 +926,8 @@@ int async_query_available_blobs(const c
        assert(subprocess_map_initialized);
        entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
        if (!entry) {
-               error("external filter '%s' is not available anymore although "
-                     "not all paths have been filtered", cmd);
+               error(_("external filter '%s' is not available anymore although "
+                       "not all paths have been filtered"), cmd);
                return 0;
        }
        process = &entry->subprocess.process;
@@@ -1396,7 -1397,7 +1398,7 @@@ int convert_to_git(const struct index_s
  
        ret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN, NULL);
        if (!ret && ca.drv && ca.drv->required)
-               die("%s: clean filter '%s' failed", path, ca.drv->name);
+               die(_("%s: clean filter '%s' failed"), path, ca.drv->name);
  
        if (ret && dst) {
                src = dst->buf;
@@@ -1430,7 -1431,7 +1432,7 @@@ void convert_to_git_filter_fd(const str
        assert(ca.drv->clean || ca.drv->process);
  
        if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL))
-               die("%s: clean filter '%s' failed", path, ca.drv->name);
+               die(_("%s: clean filter '%s' failed"), path, ca.drv->name);
  
        encode_to_git(path, dst->buf, dst->len, dst, ca.working_tree_encoding, conv_flags);
        crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, conv_flags);
@@@ -1473,7 -1474,7 +1475,7 @@@ static int convert_to_working_tree_inte
        ret_filter = apply_filter(
                path, src, len, -1, dst, ca.drv, CAP_SMUDGE, dco);
        if (!ret_filter && ca.drv && ca.drv->required)
-               die("%s: smudge filter %s failed", path, ca.drv->name);
+               die(_("%s: smudge filter %s failed"), path, ca.drv->name);
  
        return ret | ret_filter;
  }
diff --combined diff.c
index 0746d59fe6d04287e0a4053b4bb0eeda5fd26778,b70eb79e47e7877073df06d0bd72acba9a7c9efd..f830afac79134219e706730c05d98f81d4a1d8cd
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -13,7 -13,6 +13,7 @@@
  #include "attr.h"
  #include "run-command.h"
  #include "utf8.h"
 +#include "object-store.h"
  #include "userdiff.h"
  #include "submodule-config.h"
  #include "submodule.h"
@@@ -37,7 -36,6 +37,7 @@@ static int diff_rename_limit_default = 
  static int diff_suppress_blank_empty;
  static int diff_use_color_default = -1;
  static int diff_color_moved_default;
 +static int diff_color_moved_ws_default;
  static int diff_context_default = 3;
  static int diff_interhunk_context_default;
  static const char *diff_word_regex_cfg;
@@@ -265,54 -263,14 +265,54 @@@ static int parse_color_moved(const cha
                return COLOR_MOVED_NO;
        else if (!strcmp(arg, "plain"))
                return COLOR_MOVED_PLAIN;
 +      else if (!strcmp(arg, "blocks"))
 +              return COLOR_MOVED_BLOCKS;
        else if (!strcmp(arg, "zebra"))
                return COLOR_MOVED_ZEBRA;
        else if (!strcmp(arg, "default"))
                return COLOR_MOVED_DEFAULT;
 +      else if (!strcmp(arg, "dimmed-zebra"))
 +              return COLOR_MOVED_ZEBRA_DIM;
        else if (!strcmp(arg, "dimmed_zebra"))
                return COLOR_MOVED_ZEBRA_DIM;
        else
 -              return error(_("color moved setting must be one of 'no', 'default', 'zebra', 'dimmed_zebra', 'plain'"));
 +              return error(_("color moved setting must be one of 'no', 'default', 'blocks', 'zebra', 'dimmed-zebra', 'plain'"));
 +}
 +
 +static int parse_color_moved_ws(const char *arg)
 +{
 +      int ret = 0;
 +      struct string_list l = STRING_LIST_INIT_DUP;
 +      struct string_list_item *i;
 +
 +      string_list_split(&l, arg, ',', -1);
 +
 +      for_each_string_list_item(i, &l) {
 +              struct strbuf sb = STRBUF_INIT;
 +              strbuf_addstr(&sb, i->string);
 +              strbuf_trim(&sb);
 +
 +              if (!strcmp(sb.buf, "ignore-space-change"))
 +                      ret |= XDF_IGNORE_WHITESPACE_CHANGE;
 +              else if (!strcmp(sb.buf, "ignore-space-at-eol"))
 +                      ret |= XDF_IGNORE_WHITESPACE_AT_EOL;
 +              else if (!strcmp(sb.buf, "ignore-all-space"))
 +                      ret |= XDF_IGNORE_WHITESPACE;
 +              else if (!strcmp(sb.buf, "allow-indentation-change"))
 +                      ret |= COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE;
 +              else
 +                      error(_("ignoring unknown color-moved-ws mode '%s'"), sb.buf);
 +
 +              strbuf_release(&sb);
 +      }
 +
 +      if ((ret & COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) &&
 +          (ret & XDF_WHITESPACE_FLAGS))
 +              die(_("color-moved-ws: allow-indentation-change cannot be combined with other white space modes"));
 +
 +      string_list_clear(&l, 0);
 +
 +      return ret;
  }
  
  int git_diff_ui_config(const char *var, const char *value, void *cb)
                diff_color_moved_default = cm;
                return 0;
        }
 +      if (!strcmp(var, "diff.colormovedws")) {
 +              int cm = parse_color_moved_ws(value);
 +              if (cm < 0)
 +                      return -1;
 +              diff_color_moved_ws_default = cm;
 +              return 0;
 +      }
        if (!strcmp(var, "diff.context")) {
                diff_context_default = git_config_int(var, value);
                if (diff_context_default < 0)
@@@ -746,116 -697,16 +746,116 @@@ struct moved_entry 
        struct hashmap_entry ent;
        const struct emitted_diff_symbol *es;
        struct moved_entry *next_line;
 +      struct ws_delta *wsd;
  };
  
 -static int moved_entry_cmp(const struct diff_options *diffopt,
 -                         const struct moved_entry *a,
 -                         const struct moved_entry *b,
 +/**
 + * The struct ws_delta holds white space differences between moved lines, i.e.
 + * between '+' and '-' lines that have been detected to be a move.
 + * The string contains the difference in leading white spaces, before the
 + * rest of the line is compared using the white space config for move
 + * coloring. The current_longer indicates if the first string in the
 + * comparision is longer than the second.
 + */
 +struct ws_delta {
 +      char *string;
 +      unsigned int current_longer : 1;
 +};
 +#define WS_DELTA_INIT { NULL, 0 }
 +
 +static int compute_ws_delta(const struct emitted_diff_symbol *a,
 +                           const struct emitted_diff_symbol *b,
 +                           struct ws_delta *out)
 +{
 +      const struct emitted_diff_symbol *longer =  a->len > b->len ? a : b;
 +      const struct emitted_diff_symbol *shorter = a->len > b->len ? b : a;
 +      int d = longer->len - shorter->len;
 +
 +      out->string = xmemdupz(longer->line, d);
 +      out->current_longer = (a == longer);
 +
 +      return !strncmp(longer->line + d, shorter->line, shorter->len);
 +}
 +
 +static int cmp_in_block_with_wsd(const struct diff_options *o,
 +                               const struct moved_entry *cur,
 +                               const struct moved_entry *match,
 +                               struct moved_entry *pmb,
 +                               int n)
 +{
 +      struct emitted_diff_symbol *l = &o->emitted_symbols->buf[n];
 +      int al = cur->es->len, cl = l->len;
 +      const char *a = cur->es->line,
 +                 *b = match->es->line,
 +                 *c = l->line;
 +
 +      int wslen;
 +
 +      /*
 +       * We need to check if 'cur' is equal to 'match'.
 +       * As those are from the same (+/-) side, we do not need to adjust for
 +       * indent changes. However these were found using fuzzy matching
 +       * so we do have to check if they are equal.
 +       */
 +      if (strcmp(a, b))
 +              return 1;
 +
 +      if (!pmb->wsd)
 +              /*
 +               * No white space delta was carried forward? This can happen
 +               * when we exit early in this function and do not carry
 +               * forward ws.
 +               */
 +              return 1;
 +
 +      /*
 +       * The indent changes of the block are known and carried forward in
 +       * pmb->wsd; however we need to check if the indent changes of the
 +       * current line are still the same as before.
 +       *
 +       * To do so we need to compare 'l' to 'cur', adjusting the
 +       * one of them for the white spaces, depending which was longer.
 +       */
 +
 +      wslen = strlen(pmb->wsd->string);
 +      if (pmb->wsd->current_longer) {
 +              c += wslen;
 +              cl -= wslen;
 +      } else {
 +              a += wslen;
 +              al -= wslen;
 +      }
 +
 +      if (strcmp(a, c))
 +              return 1;
 +
 +      return 0;
 +}
 +
 +static int moved_entry_cmp(const void *hashmap_cmp_fn_data,
 +                         const void *entry,
 +                         const void *entry_or_key,
                           const void *keydata)
  {
 +      const struct diff_options *diffopt = hashmap_cmp_fn_data;
 +      const struct moved_entry *a = entry;
 +      const struct moved_entry *b = entry_or_key;
 +      unsigned flags = diffopt->color_moved_ws_handling
 +                       & XDF_WHITESPACE_FLAGS;
 +
 +      if (diffopt->color_moved_ws_handling &
 +          COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE)
 +              /*
 +               * As there is not specific white space config given,
 +               * we'd need to check for a new block, so ignore all
 +               * white space. The setup of the white space
 +               * configuration for the next block is done else where
 +               */
 +              flags |= XDF_IGNORE_WHITESPACE;
 +
        return !xdiff_compare_lines(a->es->line, a->es->len,
                                    b->es->line, b->es->len,
 -                                  diffopt->xdl_opts);
 +                                  flags);
  }
  
  static struct moved_entry *prepare_entry(struct diff_options *o,
  {
        struct moved_entry *ret = xmalloc(sizeof(*ret));
        struct emitted_diff_symbol *l = &o->emitted_symbols->buf[line_no];
 +      unsigned flags = o->color_moved_ws_handling & XDF_WHITESPACE_FLAGS;
  
 -      ret->ent.hash = xdiff_hash_string(l->line, l->len, o->xdl_opts);
 +      ret->ent.hash = xdiff_hash_string(l->line, l->len, flags);
        ret->es = l;
        ret->next_line = NULL;
 +      ret->wsd = NULL;
  
        return ret;
  }
@@@ -905,56 -754,6 +905,56 @@@ static void add_lines_to_move_detection
        }
  }
  
 +static void pmb_advance_or_null(struct diff_options *o,
 +                              struct moved_entry *match,
 +                              struct hashmap *hm,
 +                              struct moved_entry **pmb,
 +                              int pmb_nr)
 +{
 +      int i;
 +      for (i = 0; i < pmb_nr; i++) {
 +              struct moved_entry *prev = pmb[i];
 +              struct moved_entry *cur = (prev && prev->next_line) ?
 +                              prev->next_line : NULL;
 +              if (cur && !hm->cmpfn(o, cur, match, NULL)) {
 +                      pmb[i] = cur;
 +              } else {
 +                      pmb[i] = NULL;
 +              }
 +      }
 +}
 +
 +static void pmb_advance_or_null_multi_match(struct diff_options *o,
 +                                          struct moved_entry *match,
 +                                          struct hashmap *hm,
 +                                          struct moved_entry **pmb,
 +                                          int pmb_nr, int n)
 +{
 +      int i;
 +      char *got_match = xcalloc(1, pmb_nr);
 +
 +      for (; match; match = hashmap_get_next(hm, match)) {
 +              for (i = 0; i < pmb_nr; i++) {
 +                      struct moved_entry *prev = pmb[i];
 +                      struct moved_entry *cur = (prev && prev->next_line) ?
 +                                      prev->next_line : NULL;
 +                      if (!cur)
 +                              continue;
 +                      if (!cmp_in_block_with_wsd(o, cur, match, pmb[i], n))
 +                              got_match[i] |= 1;
 +              }
 +      }
 +
 +      for (i = 0; i < pmb_nr; i++) {
 +              if (got_match[i]) {
 +                      /* Carry the white space delta forward */
 +                      pmb[i]->next_line->wsd = pmb[i]->wsd;
 +                      pmb[i] = pmb[i]->next_line;
 +              } else
 +                      pmb[i] = NULL;
 +      }
 +}
 +
  static int shrink_potential_moved_blocks(struct moved_entry **pmb,
                                         int pmb_nr)
  {
  
                if (lp < pmb_nr && rp > -1 && lp < rp) {
                        pmb[lp] = pmb[rp];
 +                      if (pmb[rp]->wsd) {
 +                              free(pmb[rp]->wsd->string);
 +                              FREE_AND_NULL(pmb[rp]->wsd);
 +                      }
                        pmb[rp] = NULL;
                        rp--;
                        lp++;
@@@ -1033,18 -828,19 +1033,18 @@@ static void mark_color_as_moved(struct 
                struct moved_entry *key;
                struct moved_entry *match = NULL;
                struct emitted_diff_symbol *l = &o->emitted_symbols->buf[n];
 -              int i;
  
                switch (l->s) {
                case DIFF_SYMBOL_PLUS:
                        hm = del_lines;
                        key = prepare_entry(o, n);
 -                      match = hashmap_get(hm, key, o);
 +                      match = hashmap_get(hm, key, NULL);
                        free(key);
                        break;
                case DIFF_SYMBOL_MINUS:
                        hm = add_lines;
                        key = prepare_entry(o, n);
 -                      match = hashmap_get(hm, key, o);
 +                      match = hashmap_get(hm, key, NULL);
                        free(key);
                        break;
                default:
                if (o->color_moved == COLOR_MOVED_PLAIN)
                        continue;
  
 -              /* Check any potential block runs, advance each or nullify */
 -              for (i = 0; i < pmb_nr; i++) {
 -                      struct moved_entry *p = pmb[i];
 -                      struct moved_entry *pnext = (p && p->next_line) ?
 -                                      p->next_line : NULL;
 -                      if (pnext && !hm->cmpfn(o, pnext, match, NULL)) {
 -                              pmb[i] = p->next_line;
 -                      } else {
 -                              pmb[i] = NULL;
 -                      }
 -              }
 +              if (o->color_moved_ws_handling &
 +                  COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE)
 +                      pmb_advance_or_null_multi_match(o, match, hm, pmb, pmb_nr, n);
 +              else
 +                      pmb_advance_or_null(o, match, hm, pmb, pmb_nr);
  
                pmb_nr = shrink_potential_moved_blocks(pmb, pmb_nr);
  
                         */
                        for (; match; match = hashmap_get_next(hm, match)) {
                                ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);
 -                              pmb[pmb_nr++] = match;
 +                              if (o->color_moved_ws_handling &
 +                                  COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {
 +                                      struct ws_delta *wsd = xmalloc(sizeof(*match->wsd));
 +                                      if (compute_ws_delta(l, match->es, wsd)) {
 +                                              match->wsd = wsd;
 +                                              pmb[pmb_nr++] = match;
 +                                      } else
 +                                              free(wsd);
 +                              } else {
 +                                      pmb[pmb_nr++] = match;
 +                              }
                        }
  
                        flipped_block = (flipped_block + 1) % 2;
  
                block_length++;
  
 -              if (flipped_block)
 +              if (flipped_block && o->color_moved != COLOR_MOVED_BLOCKS)
                        l->flags |= DIFF_SYMBOL_MOVED_LINE_ALT;
        }
        adjust_last_block(o, n, block_length);
@@@ -2071,8 -1863,8 +2071,8 @@@ static void init_diff_words_data(struc
                if (regcomp(ecbdata->diff_words->word_regex,
                            o->word_regex,
                            REG_EXTENDED | REG_NEWLINE))
-                       die ("Invalid regular expression: %s",
-                            o->word_regex);
+                       die("invalid regular expression: %s",
+                           o->word_regex);
        }
        for (i = 0; i < ARRAY_SIZE(diff_words_styles); i++) {
                if (o->word_diff == diff_words_styles[i].type) {
@@@ -4040,7 -3832,7 +4040,7 @@@ static const char *diff_abbrev_oid(cons
                char *hex = oid_to_hex(oid);
                if (abbrev < 0)
                        abbrev = FALLBACK_DEFAULT_ABBREV;
 -              if (abbrev > GIT_SHA1_HEXSZ)
 +              if (abbrev > the_hash_algo->hexsz)
                        BUG("oid abbreviation out of range: %d", abbrev);
                if (abbrev)
                        hex[abbrev] = '\0';
@@@ -4332,7 -4124,6 +4332,7 @@@ void diff_setup(struct diff_options *op
        }
  
        options->color_moved = diff_color_moved_default;
 +      options->color_moved_ws_handling = diff_color_moved_ws_default;
  }
  
  void diff_setup_done(struct diff_options *options)
@@@ -4912,8 -4703,6 +4912,8 @@@ int diff_opt_parse(struct diff_options 
                if (cm < 0)
                        die("bad --color-moved argument: %s", arg);
                options->color_moved = cm;
 +      } else if (skip_prefix(arg, "--color-moved-ws=", &arg)) {
 +              options->color_moved_ws_handling = parse_color_moved_ws(arg);
        } else if (skip_to_optional_arg_default(arg, "--color-words", &options->word_regex, NULL)) {
                options->use_color = 1;
                options->word_diff = DIFF_WORDS_COLOR;
@@@ -5158,7 -4947,7 +5158,7 @@@ const char *diff_aligned_abbrev(const s
        const char *abbrev;
  
        /* Do we want all 40 hex characters? */
 -      if (len == GIT_SHA1_HEXSZ)
 +      if (len == the_hash_algo->hexsz)
                return oid_to_hex(oid);
  
        /* An abbreviated value is fine, possibly followed by an ellipsis. */
         * the automatic sizing is supposed to give abblen that ensures
         * uniqueness across all objects (statistically speaking).
         */
 -      if (abblen < GIT_SHA1_HEXSZ - 3) {
 +      if (abblen < the_hash_algo->hexsz - 3) {
                static char hex[GIT_MAX_HEXSZ + 1];
                if (len < abblen && abblen <= len + 2)
                        xsnprintf(hex, sizeof(hex), "%s%.*s", abbrev, len+3-abblen, "..");
@@@ -5744,12 -5533,10 +5744,12 @@@ static void diff_flush_patch_all_file_p
                if (o->color_moved) {
                        struct hashmap add_lines, del_lines;
  
 -                      hashmap_init(&del_lines,
 -                                   (hashmap_cmp_fn)moved_entry_cmp, o, 0);
 -                      hashmap_init(&add_lines,
 -                                   (hashmap_cmp_fn)moved_entry_cmp, o, 0);
 +                      if (o->color_moved_ws_handling &
 +                          COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE)
 +                              o->color_moved_ws_handling |= XDF_IGNORE_WHITESPACE;
 +
 +                      hashmap_init(&del_lines, moved_entry_cmp, o, 0);
 +                      hashmap_init(&add_lines, moved_entry_cmp, o, 0);
  
                        add_lines_to_move_detection(o, &add_lines, &del_lines);
                        mark_color_as_moved(o, &add_lines, &del_lines);
diff --combined dir.c
index 21e6f2520a487ec9167e7d1f79101f82444af832,7c6e7a0a378233b3de6fb7f886bdc0caebcf653a..32f5f7275981ea1bd9a4be2fe87f5f7f47ffb571
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -11,7 -11,6 +11,7 @@@
  #include "cache.h"
  #include "config.h"
  #include "dir.h"
 +#include "object-store.h"
  #include "attr.h"
  #include "refs.h"
  #include "wildmatch.h"
@@@ -561,7 -560,7 +561,7 @@@ int report_path_error(const char *ps_ma
                if (found_dup)
                        continue;
  
-               error("pathspec '%s' did not match any file(s) known to git.",
+               error(_("pathspec '%s' did not match any file(s) known to git"),
                      pathspec->items[num].original);
                errors++;
        }
@@@ -950,7 -949,7 +950,7 @@@ static void add_excludes_from_file_1(st
                dir->unmanaged_exclude_files++;
        el = add_exclude_list(dir, EXC_FILE, fname);
        if (add_excludes(fname, "", 0, el, NULL, oid_stat) < 0)
-               die("cannot use %s as an exclude file", fname);
+               die(_("cannot use %s as an exclude file"), fname);
  }
  
  void add_excludes_from_file(struct dir_struct *dir, const char *fname)
@@@ -2231,7 -2230,7 +2231,7 @@@ static struct untracked_cache_dir *vali
                return NULL;
  
        if (!ident_in_untracked(dir->untracked)) {
-               warning(_("Untracked cache is disabled on this system or location."));
+               warning(_("untracked cache is disabled on this system or location"));
                return NULL;
        }
  
@@@ -2498,7 -2497,7 +2498,7 @@@ void setup_standard_excludes(struct dir
  {
        dir->exclude_per_dir = ".gitignore";
  
 -      /* core.excludefile defaulting to $XDG_HOME/git/ignore */
 +      /* core.excludesfile defaulting to $XDG_CONFIG_HOME/git/ignore */
        if (!excludes_file)
                excludes_file = xdg_config_home("ignore");
        if (excludes_file && !access_or_warn(excludes_file, R_OK, 0))
@@@ -3029,7 -3028,7 +3029,7 @@@ static void connect_wt_gitdir_in_nested
                return;
  
        if (repo_read_index(&subrepo) < 0)
-               die("index file corrupt in repo %s", subrepo.gitdir);
+               die(_("index file corrupt in repo %s"), subrepo.gitdir);
  
        for (i = 0; i < subrepo.index->cache_nr; i++) {
                const struct cache_entry *ce = subrepo.index->cache[i];
diff --combined environment.c
index b9d71a7fecc4de2b1381e71944cc4103e1e5124a,d129c4adc5800b27de31a1f00addcf8f609122c1..68523b6b0ecd3bf924b075bd47bf0cd3426795f3
@@@ -51,7 -51,7 +51,7 @@@ const char *editor_program
  const char *askpass_program;
  const char *excludes_file;
  enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
 -int check_replace_refs = 1; /* NEEDSWORK: rename to read_replace_refs */
 +int read_replace_refs = 1;
  char *git_replace_ref_base;
  enum eol core_eol = EOL_UNSET;
  int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
@@@ -66,6 -66,7 +66,6 @@@ enum push_default_type push_default = P
  enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
  char *notes_ref_name;
  int grafts_replace_parents = 1;
 -int core_commit_graph;
  int core_apply_sparse_checkout;
  int merge_log_config = -1;
  int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
@@@ -146,7 -147,7 +146,7 @@@ static char *expand_namespace(const cha
                        strbuf_addf(&buf, "refs/namespaces/%s", (*c)->buf);
        strbuf_list_free(components);
        if (check_refname_format(buf.buf, 0))
-               die("bad git namespace path \"%s\"", raw_namespace);
+               die(_("bad git namespace path \"%s\""), raw_namespace);
        strbuf_addch(&buf, '/');
        return strbuf_detach(&buf, NULL);
  }
@@@ -182,7 -183,7 +182,7 @@@ void setup_git_env(const char *git_dir
        argv_array_clear(&to_free);
  
        if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
 -              check_replace_refs = 0;
 +              read_replace_refs = 0;
        replace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);
        free(git_replace_ref_base);
        git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
        git_namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
        shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
        if (shallow_file)
 -              set_alternate_shallow_file(shallow_file, 0);
 +              set_alternate_shallow_file(the_repository, shallow_file, 0);
  }
  
  int is_bare_repository(void)
@@@ -318,17 -319,17 +318,17 @@@ char *get_index_file(void
        return the_repository->index_file;
  }
  
 -char *get_graft_file(void)
 +char *get_graft_file(struct repository *r)
  {
 -      if (!the_repository->graft_file)
 +      if (!r->graft_file)
                BUG("git environment hasn't been setup");
 -      return the_repository->graft_file;
 +      return r->graft_file;
  }
  
  static void set_git_dir_1(const char *path)
  {
        if (setenv(GIT_DIR_ENVIRONMENT, path, 1))
-               die("could not set GIT_DIR to '%s'", path);
+               die(_("could not set GIT_DIR to '%s'"), path);
        setup_git_env(path);
  }
  
diff --combined object.c
index e2c112cc1a757f666ce3ca234227c98abf146910,477e686da7dc783a5341888bb987a42226d75795..51c45945156c421ada403139faefdf145918f4f7
+++ b/object.c
@@@ -1,7 -1,6 +1,7 @@@
  #include "cache.h"
  #include "object.h"
  #include "replace-object.h"
 +#include "object-store.h"
  #include "blob.h"
  #include "tree.h"
  #include "commit.h"
@@@ -9,7 -8,6 +9,7 @@@
  #include "alloc.h"
  #include "object-store.h"
  #include "packfile.h"
 +#include "commit-graph.h"
  
  unsigned int get_max_object_index(void)
  {
@@@ -51,7 -49,7 +51,7 @@@ int type_from_string_gently(const char 
        if (gentle)
                return -1;
  
-       die("invalid object type \"%s\"", str);
+       die(_("invalid object type \"%s\""), str);
  }
  
  /*
@@@ -85,20 -83,21 +85,20 @@@ static void insert_obj_hash(struct obje
   * Look up the record for the given sha1 in the hash map stored in
   * obj_hash.  Return NULL if it was not found.
   */
 -struct object *lookup_object(const unsigned char *sha1)
 +struct object *lookup_object(struct repository *r, const unsigned char *sha1)
  {
        unsigned int i, first;
        struct object *obj;
  
 -      if (!the_repository->parsed_objects->obj_hash)
 +      if (!r->parsed_objects->obj_hash)
                return NULL;
  
 -      first = i = hash_obj(sha1,
 -                           the_repository->parsed_objects->obj_hash_size);
 -      while ((obj = the_repository->parsed_objects->obj_hash[i]) != NULL) {
 +      first = i = hash_obj(sha1, r->parsed_objects->obj_hash_size);
 +      while ((obj = r->parsed_objects->obj_hash[i]) != NULL) {
                if (!hashcmp(sha1, obj->oid.hash))
                        break;
                i++;
 -              if (i == the_repository->parsed_objects->obj_hash_size)
 +              if (i == r->parsed_objects->obj_hash_size)
                        i = 0;
        }
        if (obj && i != first) {
                 * that we do not need to walk the hash table the next
                 * time we look for it.
                 */
 -              SWAP(the_repository->parsed_objects->obj_hash[i],
 -                   the_repository->parsed_objects->obj_hash[first]);
 +              SWAP(r->parsed_objects->obj_hash[i],
 +                   r->parsed_objects->obj_hash[first]);
        }
        return obj;
  }
@@@ -158,19 -157,19 +158,19 @@@ void *create_object(struct repository *
        return obj;
  }
  
 -void *object_as_type(struct object *obj, enum object_type type, int quiet)
 +void *object_as_type(struct repository *r, struct object *obj, enum object_type type, int quiet)
  {
        if (obj->type == type)
                return obj;
        else if (obj->type == OBJ_NONE) {
                if (type == OBJ_COMMIT)
 -                      ((struct commit *)obj)->index = alloc_commit_index(the_repository);
 +                      ((struct commit *)obj)->index = alloc_commit_index(r);
                obj->type = type;
                return obj;
        }
        else {
                if (!quiet)
-                       error("object %s is a %s, not a %s",
+                       error(_("object %s is a %s, not a %s"),
                              oid_to_hex(&obj->oid),
                              type_name(obj->type), type_name(type));
                return NULL;
  
  struct object *lookup_unknown_object(const unsigned char *sha1)
  {
 -      struct object *obj = lookup_object(sha1);
 +      struct object *obj = lookup_object(the_repository, sha1);
        if (!obj)
                obj = create_object(the_repository, sha1,
                                    alloc_object_node(the_repository));
        return obj;
  }
  
 -struct object *parse_object_buffer(const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p)
 +struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p)
  {
        struct object *obj;
        *eaten_p = 0;
  
        obj = NULL;
        if (type == OBJ_BLOB) {
 -              struct blob *blob = lookup_blob(oid);
 +              struct blob *blob = lookup_blob(r, oid);
                if (blob) {
                        if (parse_blob_buffer(blob, buffer, size))
                                return NULL;
                        obj = &blob->object;
                }
        } else if (type == OBJ_TREE) {
 -              struct tree *tree = lookup_tree(oid);
 +              struct tree *tree = lookup_tree(r, oid);
                if (tree) {
                        obj = &tree->object;
                        if (!tree->buffer)
                        }
                }
        } else if (type == OBJ_COMMIT) {
 -              struct commit *commit = lookup_commit(oid);
 +              struct commit *commit = lookup_commit(r, oid);
                if (commit) {
 -                      if (parse_commit_buffer(commit, buffer, size, 1))
 +                      if (parse_commit_buffer(r, commit, buffer, size, 1))
                                return NULL;
 -                      if (!get_cached_commit_buffer(commit, NULL)) {
 -                              set_commit_buffer(commit, buffer, size);
 +                      if (!get_cached_commit_buffer(r, commit, NULL)) {
 +                              set_commit_buffer(r, commit, buffer, size);
                                *eaten_p = 1;
                        }
                        obj = &commit->object;
                }
        } else if (type == OBJ_TAG) {
 -              struct tag *tag = lookup_tag(oid);
 +              struct tag *tag = lookup_tag(r, oid);
                if (tag) {
 -                      if (parse_tag_buffer(tag, buffer, size))
 +                      if (parse_tag_buffer(r, tag, buffer, size))
                               return NULL;
                        obj = &tag->object;
                }
        } else {
-               warning("object %s has unknown type id %d", oid_to_hex(oid), type);
+               warning(_("object %s has unknown type id %d"), oid_to_hex(oid), type);
                obj = NULL;
        }
        return obj;
  struct object *parse_object_or_die(const struct object_id *oid,
                                   const char *name)
  {
 -      struct object *o = parse_object(oid);
 +      struct object *o = parse_object(the_repository, oid);
        if (o)
                return o;
  
        die(_("unable to parse object: %s"), name ? name : oid_to_hex(oid));
  }
  
 -struct object *parse_object(const struct object_id *oid)
 +struct object *parse_object(struct repository *r, const struct object_id *oid)
  {
        unsigned long size;
        enum object_type type;
        int eaten;
 -      const struct object_id *repl = lookup_replace_object(the_repository, oid);
 +      const struct object_id *repl = lookup_replace_object(r, oid);
        void *buffer;
        struct object *obj;
  
 -      obj = lookup_object(oid->hash);
 +      obj = lookup_object(r, oid->hash);
        if (obj && obj->parsed)
                return obj;
  
        if ((obj && obj->type == OBJ_BLOB && has_object_file(oid)) ||
            (!obj && has_object_file(oid) &&
 -           oid_object_info(the_repository, oid, NULL) == OBJ_BLOB)) {
 +           oid_object_info(r, oid, NULL) == OBJ_BLOB)) {
                if (check_object_signature(repl, NULL, 0, NULL) < 0) {
-                       error("sha1 mismatch %s", oid_to_hex(oid));
+                       error(_("sha1 mismatch %s"), oid_to_hex(oid));
                        return NULL;
                }
 -              parse_blob_buffer(lookup_blob(oid), NULL, 0);
 -              return lookup_object(oid->hash);
 +              parse_blob_buffer(lookup_blob(r, oid), NULL, 0);
 +              return lookup_object(r, oid->hash);
        }
  
        buffer = read_object_file(oid, &type, &size);
        if (buffer) {
                if (check_object_signature(repl, buffer, size, type_name(type)) < 0) {
                        free(buffer);
-                       error("sha1 mismatch %s", oid_to_hex(repl));
+                       error(_("sha1 mismatch %s"), oid_to_hex(repl));
                        return NULL;
                }
  
 -              obj = parse_object_buffer(oid, type, size, buffer, &eaten);
 +              obj = parse_object_buffer(r, oid, type, size,
 +                                        buffer, &eaten);
                if (!eaten)
                        free(buffer);
                return obj;
@@@ -465,11 -463,6 +465,11 @@@ struct parsed_object_pool *parsed_objec
        o->tag_state = allocate_alloc_state();
        o->object_state = allocate_alloc_state();
  
 +      o->is_shallow = -1;
 +      o->shallow_stat = xcalloc(1, sizeof(*o->shallow_stat));
 +
 +      o->buffer_slab = allocate_commit_buffer_slab();
 +
        return o;
  }
  
@@@ -508,10 -501,6 +508,10 @@@ void raw_object_store_clear(struct raw_
        oidmap_free(o->replace_map, 1);
        FREE_AND_NULL(o->replace_map);
  
 +      free_commit_graph(o->commit_graph);
 +      o->commit_graph = NULL;
 +      o->commit_graph_attempted = 0;
 +
        free_alt_odbs(o);
        o->alt_odb_tail = NULL;
  
@@@ -548,9 -537,6 +548,9 @@@ void parsed_object_pool_clear(struct pa
        FREE_AND_NULL(o->obj_hash);
        o->obj_hash_size = 0;
  
 +      free_commit_buffer_slab(o->buffer_slab);
 +      o->buffer_slab = NULL;
 +
        clear_alloc_state(o->blob_state);
        clear_alloc_state(o->tree_state);
        clear_alloc_state(o->commit_state);
diff --combined reflog-walk.c
index 3561a8b955811c52de697647d413e33b4aa70cc2,e0048a88d8f343839100d6e87bc5316ed3de85f1..3a25b27d8f8dbd49b4c33c81cb6af3c92f59759d
@@@ -128,7 -128,7 +128,7 @@@ int add_reflog_for_walk(struct reflog_w
        enum selector_type selector = SELECTOR_NONE;
  
        if (commit->object.flags & UNINTERESTING)
-               die ("Cannot walk reflogs for %s", name);
+               die("cannot walk reflogs for %s", name);
  
        branch = xstrdup(name);
        if (at && at[1] == '{') {
                        free(branch);
                        branch = resolve_refdup("HEAD", 0, NULL, NULL);
                        if (!branch)
-                               die ("No current branch");
+                               die("no current branch");
  
                }
                reflogs = read_complete_reflog(branch);
@@@ -305,8 -305,7 +305,8 @@@ static struct commit *next_reflog_commi
  {
        for (; log->recno >= 0; log->recno--) {
                struct reflog_info *entry = &log->reflogs->items[log->recno];
 -              struct object *obj = parse_object(&entry->noid);
 +              struct object *obj = parse_object(the_repository,
 +                                                &entry->noid);
  
                if (obj && obj->type == OBJ_COMMIT)
                        return (struct commit *)obj;
diff --combined refs.c
index 457fb78057a9375eb2b2cda44214a1705a28fc1e,becb78e44179518cf26e38b72972a43df48eb032..5b412c61efb94cfd4549c68ac561b596dbf0463e
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -9,7 -9,6 +9,7 @@@
  #include "iterator.h"
  #include "refs.h"
  #include "refs/refs-internal.h"
 +#include "object-store.h"
  #include "object.h"
  #include "tag.h"
  #include "submodule.h"
@@@ -189,7 -188,7 +189,7 @@@ int ref_resolves_to_object(const char *
        if (flags & REF_ISBROKEN)
                return 0;
        if (!has_sha1_file(oid->hash)) {
-               error("%s does not point to a valid object!", refname);
+               error(_("%s does not point to a valid object!"), refname);
                return 0;
        }
        return 1;
@@@ -305,7 -304,7 +305,7 @@@ enum peel_status peel_object(const stru
  
        if (o->type == OBJ_NONE) {
                int type = oid_object_info(the_repository, name, NULL);
 -              if (type < 0 || !object_as_type(o, type, 0))
 +              if (type < 0 || !object_as_type(the_repository, o, type, 0))
                        return PEEL_INVALID;
        }
  
@@@ -568,9 -567,9 +568,9 @@@ int expand_ref(const char *str, int len
                        if (!warn_ambiguous_refs)
                                break;
                } else if ((flag & REF_ISSYMREF) && strcmp(fullref.buf, "HEAD")) {
-                       warning("ignoring dangling symref %s.", fullref.buf);
+                       warning(_("ignoring dangling symref %s"), fullref.buf);
                } else if ((flag & REF_ISBROKEN) && strchr(fullref.buf, '/')) {
-                       warning("ignoring broken ref %s.", fullref.buf);
+                       warning(_("ignoring broken ref %s"), fullref.buf);
                }
        }
        strbuf_release(&fullref);
@@@ -674,7 -673,7 +674,7 @@@ static int write_pseudoref(const char *
        fd = hold_lock_file_for_update_timeout(&lock, filename, 0,
                                               get_files_ref_lock_timeout_ms());
        if (fd < 0) {
-               strbuf_addf(err, "could not open '%s' for writing: %s",
+               strbuf_addf(err, _("could not open '%s' for writing: %s"),
                            filename, strerror(errno));
                goto done;
        }
  
                if (read_ref(pseudoref, &actual_old_oid)) {
                        if (!is_null_oid(old_oid)) {
-                               strbuf_addf(err, "could not read ref '%s'",
+                               strbuf_addf(err, _("could not read ref '%s'"),
                                            pseudoref);
                                rollback_lock_file(&lock);
                                goto done;
                        }
                } else if (is_null_oid(old_oid)) {
-                       strbuf_addf(err, "ref '%s' already exists",
+                       strbuf_addf(err, _("ref '%s' already exists"),
                                    pseudoref);
                        rollback_lock_file(&lock);
                        goto done;
                } else if (oidcmp(&actual_old_oid, old_oid)) {
-                       strbuf_addf(err, "unexpected object ID when writing '%s'",
+                       strbuf_addf(err, _("unexpected object ID when writing '%s'"),
                                    pseudoref);
                        rollback_lock_file(&lock);
                        goto done;
        }
  
        if (write_in_full(fd, buf.buf, buf.len) < 0) {
-               strbuf_addf(err, "could not write to '%s'", filename);
+               strbuf_addf(err, _("could not write to '%s'"), filename);
                rollback_lock_file(&lock);
                goto done;
        }
@@@ -735,9 -734,9 +735,9 @@@ static int delete_pseudoref(const char 
                        return -1;
                }
                if (read_ref(pseudoref, &actual_old_oid))
-                       die("could not read ref '%s'", pseudoref);
+                       die(_("could not read ref '%s'"), pseudoref);
                if (oidcmp(&actual_old_oid, old_oid)) {
-                       error("unexpected object ID when deleting '%s'",
+                       error(_("unexpected object ID when deleting '%s'"),
                              pseudoref);
                        rollback_lock_file(&lock);
                        return -1;
@@@ -787,21 -786,25 +787,21 @@@ int delete_ref(const char *msg, const c
                               old_oid, flags);
  }
  
 -int copy_reflog_msg(char *buf, const char *msg)
 +void copy_reflog_msg(struct strbuf *sb, const char *msg)
  {
 -      char *cp = buf;
        char c;
        int wasspace = 1;
  
 -      *cp++ = '\t';
 +      strbuf_addch(sb, '\t');
        while ((c = *msg++)) {
                if (wasspace && isspace(c))
                        continue;
                wasspace = isspace(c);
                if (wasspace)
                        c = ' ';
 -              *cp++ = c;
 +              strbuf_addch(sb, c);
        }
 -      while (buf < cp && isspace(cp[-1]))
 -              cp--;
 -      *cp++ = '\n';
 -      return cp - buf;
 +      strbuf_rtrim(sb);
  }
  
  int should_autocreate_reflog(const char *refname)
@@@ -868,13 -871,13 +868,13 @@@ static int read_ref_at_ent(struct objec
                if (!is_null_oid(&cb->ooid)) {
                        oidcpy(cb->oid, noid);
                        if (oidcmp(&cb->ooid, noid))
-                               warning("Log for ref %s has gap after %s.",
+                               warning(_("log for ref %s has gap after %s"),
                                        cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
                }
                else if (cb->date == cb->at_time)
                        oidcpy(cb->oid, noid);
                else if (oidcmp(noid, cb->oid))
-                       warning("Log for ref %s unexpectedly ended on %s.",
+                       warning(_("log for ref %s unexpectedly ended on %s"),
                                cb->refname, show_date(cb->date, cb->tz,
                                                       DATE_MODE(RFC2822)));
                oidcpy(&cb->ooid, ooid);
@@@ -932,7 -935,7 +932,7 @@@ int read_ref_at(const char *refname, un
                if (flags & GET_OID_QUIETLY)
                        exit(128);
                else
-                       die("Log for %s is empty.", refname);
+                       die(_("log for %s is empty"), refname);
        }
        if (cb.found_it)
                return 0;
@@@ -1024,7 -1027,7 +1024,7 @@@ int ref_transaction_update(struct ref_t
        if ((new_oid && !is_null_oid(new_oid)) ?
            check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :
            !refname_is_safe(refname)) {
-               strbuf_addf(err, "refusing to update ref with bad name '%s'",
+               strbuf_addf(err, _("refusing to update ref with bad name '%s'"),
                            refname);
                return -1;
        }
@@@ -1100,7 -1103,7 +1100,7 @@@ int refs_update_ref(struct ref_store *r
                }
        }
        if (ret) {
-               const char *str = "update_ref failed for ref '%s': %s";
+               const char *str = _("update_ref failed for ref '%s': %s");
  
                switch (onerr) {
                case UPDATE_REFS_MSG_ON_ERR:
@@@ -1842,7 -1845,7 +1842,7 @@@ int ref_update_reject_duplicates(struc
  
                if (!cmp) {
                        strbuf_addf(err,
-                                   "multiple updates for ref '%s' not allowed.",
+                                   _("multiple updates for ref '%s' not allowed"),
                                    refnames->items[i].string);
                        return 1;
                } else if (cmp > 0) {
@@@ -1970,13 -1973,13 +1970,13 @@@ int refs_verify_refname_available(struc
                        continue;
  
                if (!refs_read_raw_ref(refs, dirname.buf, &oid, &referent, &type)) {
-                       strbuf_addf(err, "'%s' exists; cannot create '%s'",
+                       strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
                                    dirname.buf, refname);
                        goto cleanup;
                }
  
                if (extras && string_list_has_string(extras, dirname.buf)) {
-                       strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
+                       strbuf_addf(err, _("cannot process '%s' and '%s' at the same time"),
                                    refname, dirname.buf);
                        goto cleanup;
                }
                    string_list_has_string(skip, iter->refname))
                        continue;
  
-               strbuf_addf(err, "'%s' exists; cannot create '%s'",
+               strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
                            iter->refname, refname);
                ref_iterator_abort(iter);
                goto cleanup;
  
        extra_refname = find_descendant_ref(dirname.buf, extras, skip);
        if (extra_refname)
-               strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
+               strbuf_addf(err, _("cannot process '%s' and '%s' at the same time"),
                            refname, extra_refname);
        else
                ret = 0;
diff --combined replace-object.c
index 4162df6324a8ec76a2704245db4a2d707179d9d7,ddc1546b8c03c857bef2864e0d06653a36875832..4ec77ce41848311a912256046bd2bf8dc9ee63c0
@@@ -17,7 -17,7 +17,7 @@@ static int register_replace_ref(const c
  
        if (get_oid_hex(hash, &repl_obj->original.oid)) {
                free(repl_obj);
-               warning("bad replace ref name: %s", refname);
+               warning(_("bad replace ref name: %s"), refname);
                return 0;
        }
  
@@@ -26,7 -26,7 +26,7 @@@
  
        /* Register new object */
        if (oidmap_put(the_repository->objects->replace_map, repl_obj))
-               die("duplicate replace ref: %s", refname);
+               die(_("duplicate replace ref: %s"), refname);
  
        return 0;
  }
@@@ -51,7 -51,7 +51,7 @@@ static void prepare_replace_object(stru
   * replacement object's name (replaced recursively, if necessary).
   * The return value is either oid or a pointer to a
   * permanently-allocated value.  This function always respects replace
 - * references, regardless of the value of check_replace_refs.
 + * references, regardless of the value of read_replace_refs.
   */
  const struct object_id *do_lookup_replace_object(struct repository *r,
                                                 const struct object_id *oid)
@@@ -69,5 -69,5 +69,5 @@@
                        return cur;
                cur = &repl_obj->replacement;
        }
-       die("replace depth too high for object %s", oid_to_hex(oid));
+       die(_("replace depth too high for object %s"), oid_to_hex(oid));
  }
diff --combined sequencer.c
index 31038472fdc0f13e820c43b32cf2e1448b54a543,f7c2f2422d8f3d34a50aef5449e9bd8c7406fe4e..af204d0cf118070b037120eec3a02c6ac2a59ca8
@@@ -2,7 -2,6 +2,7 @@@
  #include "config.h"
  #include "lockfile.h"
  #include "dir.h"
 +#include "object-store.h"
  #include "object.h"
  #include "commit.h"
  #include "sequencer.h"
@@@ -63,12 -62,12 +63,12 @@@ static GIT_PATH_FUNC(rebase_path_done, 
   * The file to keep track of how many commands were already processed (e.g.
   * for the prompt).
   */
 -static GIT_PATH_FUNC(rebase_path_msgnum, "rebase-merge/msgnum");
 +static GIT_PATH_FUNC(rebase_path_msgnum, "rebase-merge/msgnum")
  /*
   * The file to keep track of how many commands are to be processed in total
   * (e.g. for the prompt).
   */
 -static GIT_PATH_FUNC(rebase_path_msgtotal, "rebase-merge/end");
 +static GIT_PATH_FUNC(rebase_path_msgtotal, "rebase-merge/end")
  /*
   * The commit message that is planned to be used for any changes that
   * need to be committed following a user interaction.
@@@ -307,7 -306,7 +307,7 @@@ static const char *action_name(const st
        case REPLAY_INTERACTIVE_REBASE:
                return N_("rebase -i");
        }
-       die(_("Unknown action: %d"), opts->action);
+       die(_("unknown action: %d"), opts->action);
  }
  
  struct commit_message {
@@@ -358,7 -357,7 +358,7 @@@ static void print_advice(int show_hint
                 * (typically rebase --interactive) wants to take care
                 * of the commit itself so remove CHERRY_PICK_HEAD
                 */
 -              unlink(git_path_cherry_pick_head());
 +              unlink(git_path_cherry_pick_head(the_repository));
                return;
        }
  
@@@ -433,7 -432,7 +433,7 @@@ static int read_oneliner(struct strbuf 
  
  static struct tree *empty_tree(void)
  {
 -      return lookup_tree(the_hash_algo->empty_tree);
 +      return lookup_tree(the_repository, the_repository->hash_algo->empty_tree);
  }
  
  static int error_dirty_index(struct replay_opts *opts)
@@@ -594,7 -593,7 +594,7 @@@ static int is_index_unchanged(void
        if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
                return error(_("could not resolve HEAD commit"));
  
 -      head_commit = lookup_commit(&head_oid);
 +      head_commit = lookup_commit(the_repository, &head_oid);
  
        /*
         * If head_commit is NULL, check_commit, called from
@@@ -717,7 -716,7 +717,7 @@@ static const char *read_author_ident(st
        /* dequote values and construct ident line in-place */
        for (in = out = buf->buf; i < 3 && in - buf->buf < buf->len; i++) {
                if (!skip_prefix(in, keys[i], (const char **)&in)) {
-                       warning("could not parse '%s' (looking for '%s'",
+                       warning(_("could not parse '%s' (looking for '%s'"),
                                rebase_path_author_script(), keys[i]);
                        return NULL;
                }
        }
  
        if (i < 3) {
-               warning("could not parse '%s' (looking for '%s')",
+               warning(_("could not parse '%s' (looking for '%s')"),
                        rebase_path_author_script(), keys[i]);
                return NULL;
        }
@@@ -1101,7 -1100,7 +1101,7 @@@ void print_commit_summary(const char *p
        struct strbuf author_ident = STRBUF_INIT;
        struct strbuf committer_ident = STRBUF_INIT;
  
 -      commit = lookup_commit(oid);
 +      commit = lookup_commit(the_repository, oid);
        if (!commit)
                die(_("couldn't look up newly created commit"));
        if (parse_commit(commit))
@@@ -1176,7 -1175,7 +1176,7 @@@ static int parse_head(struct commit **h
        if (get_oid("HEAD", &oid)) {
                current_head = NULL;
        } else {
 -              current_head = lookup_commit_reference(&oid);
 +              current_head = lookup_commit_reference(the_repository, &oid);
                if (!current_head)
                        return error(_("could not parse HEAD"));
                if (oidcmp(&oid, &current_head->object.oid)) {
@@@ -1325,8 -1324,8 +1325,8 @@@ static int do_commit(const char *msg_fi
                                    &oid);
                strbuf_release(&sb);
                if (!res) {
 -                      unlink(git_path_cherry_pick_head());
 -                      unlink(git_path_merge_msg());
 +                      unlink(git_path_cherry_pick_head(the_repository));
 +                      unlink(git_path_merge_msg(the_repository));
                        if (!is_rebase_i(opts))
                                print_commit_summary(NULL, &oid,
                                                SUMMARY_SHOW_AUTHOR_DATE);
@@@ -1445,7 -1444,7 +1445,7 @@@ static const char *command_to_string(co
  {
        if (command < TODO_COMMENT)
                return todo_command_info[command].str;
-       die("Unknown command: %d", command);
+       die(_("unknown command: %d"), command);
  }
  
  static char command_to_char(const enum todo_command command)
@@@ -1511,7 -1510,7 +1511,7 @@@ static int update_squash_messages(enum 
  
                if (get_oid("HEAD", &head))
                        return error(_("need a HEAD to fixup"));
 -              if (!(head_commit = lookup_commit_reference(&head)))
 +              if (!(head_commit = lookup_commit_reference(the_repository, &head)))
                        return error(_("could not read HEAD"));
                if (!(head_message = get_commit_buffer(head_commit, NULL)))
                        return error(_("could not read HEAD's commit message"));
@@@ -1614,7 -1613,7 +1614,7 @@@ static int do_pick_commit(enum todo_com
                struct replay_opts *opts, int final_fixup)
  {
        unsigned int flags = opts->edit ? EDIT_MSG : 0;
 -      const char *msg_file = opts->edit ? NULL : git_path_merge_msg();
 +      const char *msg_file = opts->edit ? NULL : git_path_merge_msg(the_repository);
        struct object_id head;
        struct commit *base, *next, *parent;
        const char *base_label, *next_label;
                        flags |= CLEANUP_MSG;
                        msg_file = rebase_path_fixup_msg();
                } else {
 -                      const char *dest = git_path_squash_msg();
 +                      const char *dest = git_path_squash_msg(the_repository);
                        unlink(dest);
                        if (copy_file(dest, rebase_path_squash_msg(), 0666))
                                return error(_("could not rename '%s' to '%s'"),
                                             rebase_path_squash_msg(), dest);
 -                      unlink(git_path_merge_msg());
 +                      unlink(git_path_merge_msg(the_repository));
                        msg_file = dest;
                        flags |= EDIT_MSG;
                }
                        goto leave;
  
                res |= write_message(msgbuf.buf, msgbuf.len,
 -                                   git_path_merge_msg(), 0);
 +                                   git_path_merge_msg(the_repository), 0);
        } else {
                struct commit_list *common = NULL;
                struct commit_list *remotes = NULL;
  
                res = write_message(msgbuf.buf, msgbuf.len,
 -                                  git_path_merge_msg(), 0);
 +                                  git_path_merge_msg(the_repository), 0);
  
                commit_list_insert(base, &common);
                commit_list_insert(next, &remotes);
@@@ -1864,6 -1863,8 +1864,6 @@@ static int prepare_revs(struct replay_o
        if (prepare_revision_walk(opts->revs))
                return error(_("revision walk setup failed"));
  
 -      if (!opts->revs->commits)
 -              return error(_("empty commit set passed"));
        return 0;
  }
  
@@@ -2007,7 -2008,7 +2007,7 @@@ static int parse_insn_line(struct todo_
        if (status < 0)
                return -1;
  
 -      item->commit = lookup_commit_reference(&commit_oid);
 +      item->commit = lookup_commit_reference(the_repository, &commit_oid);
        return !item->commit;
  }
  
@@@ -2205,7 -2206,6 +2205,7 @@@ static int populate_opts_cb(const char 
  static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
  {
        int i;
 +      char *strategy_opts_string;
  
        strbuf_reset(buf);
        if (!read_oneliner(buf, rebase_path_strategy(), 0))
        if (!read_oneliner(buf, rebase_path_strategy_opts(), 0))
                return;
  
 -      opts->xopts_nr = split_cmdline(buf->buf, (const char ***)&opts->xopts);
 +      strategy_opts_string = buf->buf;
 +      if (*strategy_opts_string == ' ')
 +              strategy_opts_string++;
 +      opts->xopts_nr = split_cmdline(strategy_opts_string,
 +                                     (const char ***)&opts->xopts);
        for (i = 0; i < opts->xopts_nr; i++) {
                const char *arg = opts->xopts[i];
  
@@@ -2321,10 -2317,6 +2321,10 @@@ static int walk_revs_populate_todo(stru
                        short_commit_name(commit), subject_len, subject);
                unuse_commit_buffer(commit, commit_buffer);
        }
 +
 +      if (!todo_list->nr)
 +              return error(_("empty commit set passed"));
 +
        return 0;
  }
  
@@@ -2402,8 -2394,8 +2402,8 @@@ static int rollback_single_pick(void
  {
        struct object_id head_oid;
  
 -      if (!file_exists(git_path_cherry_pick_head()) &&
 -          !file_exists(git_path_revert_head()))
 +      if (!file_exists(git_path_cherry_pick_head(the_repository)) &&
 +          !file_exists(git_path_revert_head(the_repository)))
                return error(_("no cherry-pick or revert in progress"));
        if (read_ref_full("HEAD", 0, &head_oid, NULL))
                return error(_("cannot resolve HEAD"));
@@@ -2608,15 -2600,17 +2608,17 @@@ static int error_with_patch(struct comm
                if (intend_to_amend())
                        return -1;
  
-               fprintf(stderr, "You can amend the commit now, with\n"
-                       "\n"
-                       "  git commit --amend %s\n"
-                       "\n"
-                       "Once you are satisfied with your changes, run\n"
-                       "\n"
-                       "  git rebase --continue\n", gpg_sign_opt_quoted(opts));
+               fprintf(stderr,
+                       _("You can amend the commit now, with\n"
+                         "\n"
+                         "  git commit --amend %s\n"
+                         "\n"
+                         "Once you are satisfied with your changes, run\n"
+                         "\n"
+                         "  git rebase --continue\n"),
+                       gpg_sign_opt_quoted(opts));
        } else if (exit_code)
-               fprintf(stderr, "Could not apply %s... %.*s\n",
+               fprintf_ln(stderr, _("Could not apply %s... %.*s"),
                        short_commit_name(commit), subject_len, subject);
  
        return exit_code;
@@@ -2628,11 -2622,10 +2630,11 @@@ static int error_failed_squash(struct c
        if (copy_file(rebase_path_message(), rebase_path_squash_msg(), 0666))
                return error(_("could not copy '%s' to '%s'"),
                        rebase_path_squash_msg(), rebase_path_message());
 -      unlink(git_path_merge_msg());
 -      if (copy_file(git_path_merge_msg(), rebase_path_message(), 0666))
 +      unlink(git_path_merge_msg(the_repository));
 +      if (copy_file(git_path_merge_msg(the_repository), rebase_path_message(), 0666))
                return error(_("could not copy '%s' to '%s'"),
 -                           rebase_path_message(), git_path_merge_msg());
 +                           rebase_path_message(),
 +                           git_path_merge_msg(the_repository));
        return error_with_patch(commit, subject, subject_len, opts, 1, 0);
  }
  
@@@ -2645,8 -2638,6 +2647,8 @@@ static int do_exec(const char *command_
        fprintf(stderr, "Executing: %s\n", command_line);
        child_argv[0] = command_line;
        argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
 +      argv_array_pushf(&child_env, "GIT_WORK_TREE=%s",
 +                       absolute_path(get_git_work_tree()));
        status = run_command_v_opt_cd_env(child_argv, RUN_USING_SHELL, NULL,
                                          child_env.argv);
  
@@@ -2730,7 -2721,7 +2732,7 @@@ static int do_label(const char *name, i
        struct object_id head_oid;
  
        if (len == 1 && *name == '#')
-               return error("Illegal label name: '%.*s'", len, name);
+               return error(_("illegal label name: '%.*s'"), len, name);
  
        strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name);
        strbuf_addf(&msg, "rebase -i (label) '%.*s'", len, name);
@@@ -2852,26 -2843,6 +2854,26 @@@ static int do_reset(const char *name, i
        return ret;
  }
  
 +static struct commit *lookup_label(const char *label, int len,
 +                                 struct strbuf *buf)
 +{
 +      struct commit *commit;
 +
 +      strbuf_reset(buf);
 +      strbuf_addf(buf, "refs/rewritten/%.*s", len, label);
 +      commit = lookup_commit_reference_by_name(buf->buf);
 +      if (!commit) {
 +              /* fall back to non-rewritten ref or commit */
 +              strbuf_splice(buf, 0, strlen("refs/rewritten/"), "", 0);
 +              commit = lookup_commit_reference_by_name(buf->buf);
 +      }
 +
 +      if (!commit)
 +              error(_("could not resolve '%s'"), buf->buf);
 +
 +      return commit;
 +}
 +
  static int do_merge(struct commit *commit, const char *arg, int arg_len,
                    int flags, struct replay_opts *opts)
  {
        struct strbuf ref_name = STRBUF_INIT;
        struct commit *head_commit, *merge_commit, *i;
        struct commit_list *bases, *j, *reversed = NULL;
 +      struct commit_list *to_merge = NULL, **tail = &to_merge;
        struct merge_options o;
 -      int merge_arg_len, oneline_offset, can_fast_forward, ret;
 +      int merge_arg_len, oneline_offset, can_fast_forward, ret, k;
        static struct lock_file lock;
        const char *p;
  
                goto leave_merge;
        }
  
 -      oneline_offset = arg_len;
 -      merge_arg_len = strcspn(arg, " \t\n");
 -      p = arg + merge_arg_len;
 -      p += strspn(p, " \t\n");
 -      if (*p == '#' && (!p[1] || isspace(p[1]))) {
 -              p += 1 + strspn(p + 1, " \t\n");
 -              oneline_offset = p - arg;
 -      } else if (p - arg < arg_len)
 -              BUG("octopus merges are not supported yet: '%s'", p);
 -
 -      strbuf_addf(&ref_name, "refs/rewritten/%.*s", merge_arg_len, arg);
 -      merge_commit = lookup_commit_reference_by_name(ref_name.buf);
 -      if (!merge_commit) {
 -              /* fall back to non-rewritten ref or commit */
 -              strbuf_splice(&ref_name, 0, strlen("refs/rewritten/"), "", 0);
 -              merge_commit = lookup_commit_reference_by_name(ref_name.buf);
 +      /*
 +       * For octopus merges, the arg starts with the list of revisions to be
 +       * merged. The list is optionally followed by '#' and the oneline.
 +       */
 +      merge_arg_len = oneline_offset = arg_len;
 +      for (p = arg; p - arg < arg_len; p += strspn(p, " \t\n")) {
 +              if (!*p)
 +                      break;
 +              if (*p == '#' && (!p[1] || isspace(p[1]))) {
 +                      p += 1 + strspn(p + 1, " \t\n");
 +                      oneline_offset = p - arg;
 +                      break;
 +              }
 +              k = strcspn(p, " \t\n");
 +              if (!k)
 +                      continue;
 +              merge_commit = lookup_label(p, k, &ref_name);
 +              if (!merge_commit) {
 +                      ret = error(_("unable to parse '%.*s'"), k, p);
 +                      goto leave_merge;
 +              }
 +              tail = &commit_list_insert(merge_commit, tail)->next;
 +              p += k;
 +              merge_arg_len = p - arg;
        }
  
 -      if (!merge_commit) {
 -              ret = error(_("could not resolve '%s'"), ref_name.buf);
 +      if (!to_merge) {
 +              ret = error(_("nothing to merge: '%.*s'"), arg_len, arg);
                goto leave_merge;
        }
  
                 * "[new root]", let's simply fast-forward to the merge head.
                 */
                rollback_lock_file(&lock);
 -              ret = fast_forward_to(&merge_commit->object.oid,
 -                                     &head_commit->object.oid, 0, opts);
 +              if (to_merge->next)
 +                      ret = error(_("octopus merge cannot be executed on "
 +                                    "top of a [new root]"));
 +              else
 +                      ret = fast_forward_to(&to_merge->item->object.oid,
 +                                            &head_commit->object.oid, 0,
 +                                            opts);
                goto leave_merge;
        }
  
                write_author_script(message);
                find_commit_subject(message, &body);
                len = strlen(body);
 -              ret = write_message(body, len, git_path_merge_msg(), 0);
 +              ret = write_message(body, len, git_path_merge_msg(the_repository), 0);
                unuse_commit_buffer(commit, message);
                if (ret) {
                        error_errno(_("could not write '%s'"),
 -                                  git_path_merge_msg());
 +                                  git_path_merge_msg(the_repository));
                        goto leave_merge;
                }
        } else {
                        p = arg + oneline_offset;
                        len = arg_len - oneline_offset;
                } else {
 -                      strbuf_addf(&buf, "Merge branch '%.*s'",
 +                      strbuf_addf(&buf, "Merge %s '%.*s'",
 +                                  to_merge->next ? "branches" : "branch",
                                    merge_arg_len, arg);
                        p = buf.buf;
                        len = buf.len;
                }
  
 -              ret = write_message(p, len, git_path_merge_msg(), 0);
 +              ret = write_message(p, len, git_path_merge_msg(the_repository), 0);
                strbuf_release(&buf);
                if (ret) {
                        error_errno(_("could not write '%s'"),
 -                                  git_path_merge_msg());
 +                                  git_path_merge_msg(the_repository));
                        goto leave_merge;
                }
        }
                        &head_commit->object.oid);
  
        /*
 -       * If the merge head is different from the original one, we cannot
 +       * If any merge head is different from the original one, we cannot
         * fast-forward.
         */
        if (can_fast_forward) {
 -              struct commit_list *second_parent = commit->parents->next;
 +              struct commit_list *p = commit->parents->next;
  
 -              if (second_parent && !second_parent->next &&
 -                  oidcmp(&merge_commit->object.oid,
 -                         &second_parent->item->object.oid))
 +              for (j = to_merge; j && p; j = j->next, p = p->next)
 +                      if (oidcmp(&j->item->object.oid,
 +                                 &p->item->object.oid)) {
 +                              can_fast_forward = 0;
 +                              break;
 +                      }
 +              /*
 +               * If the number of merge heads differs from the original merge
 +               * commit, we cannot fast-forward.
 +               */
 +              if (j || p)
                        can_fast_forward = 0;
        }
  
 -      if (can_fast_forward && commit->parents->next &&
 -          !commit->parents->next->next &&
 -          !oidcmp(&commit->parents->next->item->object.oid,
 -                  &merge_commit->object.oid)) {
 +      if (can_fast_forward) {
                rollback_lock_file(&lock);
                ret = fast_forward_to(&commit->object.oid,
                                      &head_commit->object.oid, 0, opts);
                goto leave_merge;
        }
  
 +      if (to_merge->next) {
 +              /* Octopus merge */
 +              struct child_process cmd = CHILD_PROCESS_INIT;
 +
 +              if (read_env_script(&cmd.env_array)) {
 +                      const char *gpg_opt = gpg_sign_opt_quoted(opts);
 +
 +                      ret = error(_(staged_changes_advice), gpg_opt, gpg_opt);
 +                      goto leave_merge;
 +              }
 +
 +              cmd.git_cmd = 1;
 +              argv_array_push(&cmd.args, "merge");
 +              argv_array_push(&cmd.args, "-s");
 +              argv_array_push(&cmd.args, "octopus");
 +              argv_array_push(&cmd.args, "--no-edit");
 +              argv_array_push(&cmd.args, "--no-ff");
 +              argv_array_push(&cmd.args, "--no-log");
 +              argv_array_push(&cmd.args, "--no-stat");
 +              argv_array_push(&cmd.args, "-F");
 +              argv_array_push(&cmd.args, git_path_merge_msg(the_repository));
 +              if (opts->gpg_sign)
 +                      argv_array_push(&cmd.args, opts->gpg_sign);
 +
 +              /* Add the tips to be merged */
 +              for (j = to_merge; j; j = j->next)
 +                      argv_array_push(&cmd.args,
 +                                      oid_to_hex(&j->item->object.oid));
 +
 +              strbuf_release(&ref_name);
 +              unlink(git_path_cherry_pick_head(the_repository));
 +              rollback_lock_file(&lock);
 +
 +              rollback_lock_file(&lock);
 +              ret = run_command(&cmd);
 +
 +              /* force re-reading of the cache */
 +              if (!ret && (discard_cache() < 0 || read_cache() < 0))
 +                      ret = error(_("could not read index"));
 +              goto leave_merge;
 +      }
 +
 +      merge_commit = to_merge->item;
        write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ,
 -                    git_path_merge_head(), 0);
 -      write_message("no-ff", 5, git_path_merge_mode(), 0);
 +                    git_path_merge_head(the_repository), 0);
 +      write_message("no-ff", 5, git_path_merge_mode(the_repository), 0);
  
        bases = get_merge_bases(head_commit, merge_commit);
        if (bases && !oidcmp(&merge_commit->object.oid,
                 * value (a negative one would indicate that the `merge`
                 * command needs to be rescheduled).
                 */
 -              ret = !!run_git_commit(git_path_merge_msg(), opts,
 +              ret = !!run_git_commit(git_path_merge_msg(the_repository), opts,
                                     run_commit_flags);
  
  leave_merge:
        strbuf_release(&ref_name);
        rollback_lock_file(&lock);
 +      free_commit_list(to_merge);
        return ret;
  }
  
@@@ -3312,27 -3219,10 +3314,27 @@@ static int pick_commits(struct todo_lis
                                        intend_to_amend();
                                return error_failed_squash(item->commit, opts,
                                        item->arg_len, item->arg);
 -                      } else if (res && is_rebase_i(opts) && item->commit)
 +                      } else if (res && is_rebase_i(opts) && item->commit) {
 +                              int to_amend = 0;
 +                              struct object_id oid;
 +
 +                              /*
 +                               * If we are rewording and have either
 +                               * fast-forwarded already, or are about to
 +                               * create a new root commit, we want to amend,
 +                               * otherwise we do not.
 +                               */
 +                              if (item->command == TODO_REWORD &&
 +                                  !get_oid("HEAD", &oid) &&
 +                                  (!oidcmp(&item->commit->object.oid, &oid) ||
 +                                   (opts->have_squash_onto &&
 +                                    !oidcmp(&opts->squash_onto, &oid))))
 +                                      to_amend = 1;
 +
                                return res | error_with_patch(item->commit,
 -                                      item->arg, item->arg_len, opts, res,
 -                                      item->command == TODO_REWORD);
 +                                              item->arg, item->arg_len, opts,
 +                                              res, to_amend);
 +                      }
                } else if (item->command == TODO_EXEC) {
                        char *end_of_arg = (char *)(item->arg + item->arg_len);
                        int saved = *end_of_arg;
@@@ -3513,8 -3403,8 +3515,8 @@@ static int continue_single_pick(void
  {
        const char *argv[] = { "commit", NULL };
  
 -      if (!file_exists(git_path_cherry_pick_head()) &&
 -          !file_exists(git_path_revert_head()))
 +      if (!file_exists(git_path_cherry_pick_head(the_repository)) &&
 +          !file_exists(git_path_revert_head(the_repository)))
                return error(_("no cherry-pick or revert in progress"));
        return run_command_v_opt(argv, RUN_GIT_CMD);
  }
@@@ -3617,7 -3507,7 +3619,7 @@@ static int commit_staged_changes(struc
        }
  
        if (is_clean) {
 -              const char *cherry_pick_head = git_path_cherry_pick_head();
 +              const char *cherry_pick_head = git_path_cherry_pick_head(the_repository);
  
                if (file_exists(cherry_pick_head) && unlink(cherry_pick_head))
                        return error(_("could not remove CHERRY_PICK_HEAD"));
@@@ -3667,8 -3557,8 +3669,8 @@@ int sequencer_continue(struct replay_op
  
        if (!is_rebase_i(opts)) {
                /* Verify that the conflict has been resolved */
 -              if (file_exists(git_path_cherry_pick_head()) ||
 -                  file_exists(git_path_revert_head())) {
 +              if (file_exists(git_path_cherry_pick_head(the_repository)) ||
 +                  file_exists(git_path_revert_head(the_repository))) {
                        res = continue_single_pick();
                        if (res)
                                goto release_todo_list;
@@@ -3720,7 -3610,7 +3722,7 @@@ int sequencer_pick_revisions(struct rep
                        continue;
  
                if (!get_oid(name, &oid)) {
 -                      if (!lookup_commit_reference_gently(&oid, 1)) {
 +                      if (!lookup_commit_reference_gently(the_repository, &oid, 1)) {
                                enum object_type type = oid_object_info(the_repository,
                                                                        &oid,
                                                                        NULL);
                if (prepare_revision_walk(opts->revs))
                        return error(_("revision walk setup failed"));
                cmit = get_revision(opts->revs);
 -              if (!cmit || get_revision(opts->revs))
 -                      return error("BUG: expected exactly one commit from walk");
 +              if (!cmit)
 +                      return error(_("empty commit set passed"));
 +              if (get_revision(opts->revs))
 +                      BUG("unexpected extra commit from walk");
                return single_pick(cmit, opts);
        }
  
@@@ -3991,6 -3879,7 +3993,6 @@@ static int make_script_with_merges(stru
         */
        while ((commit = get_revision(revs))) {
                struct commit_list *to_merge;
 -              int is_octopus;
                const char *p1, *p2;
                struct object_id *oid;
                int is_empty;
                        continue;
                }
  
 -              is_octopus = to_merge && to_merge->next;
 -
 -              if (is_octopus)
 -                      BUG("Octopus merges not yet supported");
 -
                /* Create a label */
                strbuf_reset(&label);
                if (skip_prefix(oneline.buf, "Merge ", &p1) &&
                strbuf_addf(&buf, "%s -C %s",
                            cmd_merge, oid_to_hex(&commit->object.oid));
  
 -              /* label the tip of merged branch */
 -              oid = &to_merge->item->object.oid;
 -              strbuf_addch(&buf, ' ');
 +              /* label the tips of merged branches */
 +              for (; to_merge; to_merge = to_merge->next) {
 +                      oid = &to_merge->item->object.oid;
 +                      strbuf_addch(&buf, ' ');
 +
 +                      if (!oidset_contains(&interesting, oid)) {
 +                              strbuf_addstr(&buf, label_oid(oid, NULL,
 +                                                            &state));
 +                              continue;
 +                      }
  
 -              if (!oidset_contains(&interesting, oid))
 -                      strbuf_addstr(&buf, label_oid(oid, NULL, &state));
 -              else {
                        tips_tail = &commit_list_insert(to_merge->item,
                                                        tips_tail)->next;
  
                entry = oidmap_get(&state.commit2label, &commit->object.oid);
  
                if (entry)
 -                      fprintf(out, "\n# Branch %s\n", entry->string);
 +                      fprintf(out, "\n%c Branch %s\n", comment_line_char, entry->string);
                else
                        fprintf(out, "\n");
  
diff --combined sha1-file.c
index dfa8a35d68d9b40d4fa30cff15c1f027a201192e,92c27583db03251fdfdfa9e9b0b19a3c64a9ac11..c6ca960eb2aa6b70841350d894bfda77856d980a
@@@ -71,17 -71,17 +71,17 @@@ static void git_hash_sha1_final(unsigne
  
  static void git_hash_unknown_init(git_hash_ctx *ctx)
  {
-       die("trying to init unknown hash");
+       BUG("trying to init unknown hash");
  }
  
  static void git_hash_unknown_update(git_hash_ctx *ctx, const void *data, size_t len)
  {
-       die("trying to update unknown hash");
+       BUG("trying to update unknown hash");
  }
  
  static void git_hash_unknown_final(unsigned char *hash, git_hash_ctx *ctx)
  {
-       die("trying to finalize unknown hash");
+       BUG("trying to finalize unknown hash");
  }
  
  const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
@@@ -336,7 -336,7 +336,7 @@@ out
  static void fill_sha1_path(struct strbuf *buf, const unsigned char *sha1)
  {
        int i;
 -      for (i = 0; i < 20; i++) {
 +      for (i = 0; i < the_hash_algo->rawsz; i++) {
                static char hex[] = "0123456789abcdef";
                unsigned int val = sha1[i];
                strbuf_addch(buf, hex[val >> 4]);
@@@ -378,8 -378,8 +378,8 @@@ static int alt_odb_usable(struct raw_ob
  
        /* Detect cases where alternate disappeared */
        if (!is_directory(path->buf)) {
-               error("object directory %s does not exist; "
-                     "check .git/objects/info/alternates.",
+               error(_("object directory %s does not exist; "
+                       "check .git/objects/info/alternates"),
                      path->buf);
                return 0;
        }
@@@ -429,7 -429,7 +429,7 @@@ static int link_alt_odb_entry(struct re
        strbuf_addstr(&pathbuf, entry);
  
        if (strbuf_normalize_path(&pathbuf) < 0 && relative_base) {
-               error("unable to normalize alternate object path: %s",
+               error(_("unable to normalize alternate object path: %s"),
                      pathbuf.buf);
                strbuf_release(&pathbuf);
                return -1;
@@@ -500,14 -500,14 +500,14 @@@ static void link_alt_odb_entries(struc
                return;
  
        if (depth > 5) {
-               error("%s: ignoring alternate object stores, nesting too deep.",
+               error(_("%s: ignoring alternate object stores, nesting too deep"),
                                relative_base);
                return;
        }
  
        strbuf_add_absolute_path(&objdirbuf, r->objects->objectdir);
        if (strbuf_normalize_path(&objdirbuf) < 0)
-               die("unable to normalize object directory: %s",
+               die(_("unable to normalize object directory: %s"),
                    objdirbuf.buf);
  
        while (*alt) {
@@@ -562,7 -562,7 +562,7 @@@ void add_to_alternates_file(const char 
        hold_lock_file_for_update(&lock, alts, LOCK_DIE_ON_ERROR);
        out = fdopen_lock_file(&lock, "w");
        if (!out)
-               die_errno("unable to fdopen alternates lockfile");
+               die_errno(_("unable to fdopen alternates lockfile"));
  
        in = fopen(alts, "r");
        if (in) {
                fclose(in);
        }
        else if (errno != ENOENT)
-               die_errno("unable to read alternates file");
+               die_errno(_("unable to read alternates file"));
  
        if (found) {
                rollback_lock_file(&lock);
        } else {
                fprintf_or_die(out, "%s\n", reference);
                if (commit_lock_file(&lock))
-                       die_errno("unable to move new alternates file into place");
+                       die_errno(_("unable to move new alternates file into place"));
                if (the_repository->objects->alt_odb_tail)
                        link_alt_odb_entries(the_repository, reference,
                                             '\n', NULL, 0);
@@@ -778,7 -778,7 +778,7 @@@ static void mmap_limit_check(size_t len
                        limit = SIZE_MAX;
        }
        if (length > limit)
-               die("attempting to mmap %"PRIuMAX" over limit %"PRIuMAX,
+               die(_("attempting to mmap %"PRIuMAX" over limit %"PRIuMAX),
                    (uintmax_t)length, (uintmax_t)limit);
  }
  
@@@ -803,7 -803,7 +803,7 @@@ void *xmmap(void *start, size_t length
  {
        void *ret = xmmap_gently(start, length, prot, flags, fd, offset);
        if (ret == MAP_FAILED)
-               die_errno("mmap failed");
+               die_errno(_("mmap failed"));
        return ret;
  }
  
@@@ -970,7 -970,7 +970,7 @@@ static void *map_sha1_file_1(struct rep
                        *size = xsize_t(st.st_size);
                        if (!*size) {
                                /* mmap() is forbidden on empty files */
-                               error("object file %s is empty", path);
+                               error(_("object file %s is empty"), path);
                                return NULL;
                        }
                        map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
@@@ -1090,9 -1090,9 +1090,9 @@@ static void *unpack_sha1_rest(git_zstre
        }
  
        if (status < 0)
-               error("corrupt loose object '%s'", sha1_to_hex(sha1));
+               error(_("corrupt loose object '%s'"), sha1_to_hex(sha1));
        else if (stream->avail_in)
-               error("garbage at end of loose object '%s'",
+               error(_("garbage at end of loose object '%s'"),
                      sha1_to_hex(sha1));
        free(buf);
        return NULL;
@@@ -1134,7 -1134,7 +1134,7 @@@ static int parse_sha1_header_extended(c
        if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE) && (type < 0))
                type = 0;
        else if (type < 0)
-               die("invalid object type");
+               die(_("invalid object type"));
        if (oi->typep)
                *oi->typep = type;
  
@@@ -1216,19 -1216,19 +1216,19 @@@ static int sha1_loose_object_info(struc
                *oi->disk_sizep = mapsize;
        if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE)) {
                if (unpack_sha1_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
-                       status = error("unable to unpack %s header with --allow-unknown-type",
+                       status = error(_("unable to unpack %s header with --allow-unknown-type"),
                                       sha1_to_hex(sha1));
        } else if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
-               status = error("unable to unpack %s header",
+               status = error(_("unable to unpack %s header"),
                               sha1_to_hex(sha1));
        if (status < 0)
                ; /* Do nothing */
        else if (hdrbuf.len) {
                if ((status = parse_sha1_header_extended(hdrbuf.buf, oi, flags)) < 0)
-                       status = error("unable to parse %s header with --allow-unknown-type",
+                       status = error(_("unable to parse %s header with --allow-unknown-type"),
                                       sha1_to_hex(sha1));
        } else if ((status = parse_sha1_header_extended(hdr, oi, flags)) < 0)
-               status = error("unable to parse %s header", sha1_to_hex(sha1));
+               status = error(_("unable to parse %s header"), sha1_to_hex(sha1));
  
        if (status >= 0 && oi->contentp) {
                *oi->contentp = unpack_sha1_rest(&stream, hdr,
@@@ -1419,19 -1419,19 +1419,19 @@@ void *read_object_file_extended(const s
                return data;
  
        if (errno && errno != ENOENT)
-               die_errno("failed to read object %s", oid_to_hex(oid));
+               die_errno(_("failed to read object %s"), oid_to_hex(oid));
  
        /* die if we replaced an object with one that does not exist */
        if (repl != oid)
-               die("replacement %s not found for %s",
+               die(_("replacement %s not found for %s"),
                    oid_to_hex(repl), oid_to_hex(oid));
  
        if (!stat_sha1_file(the_repository, repl->hash, &st, &path))
-               die("loose object %s (stored in %s) is corrupt",
+               die(_("loose object %s (stored in %s) is corrupt"),
                    oid_to_hex(repl), path);
  
        if ((p = has_packed_and_bad(repl->hash)) != NULL)
-               die("packed object %s (stored in %s) is corrupt",
+               die(_("packed object %s (stored in %s) is corrupt"),
                    oid_to_hex(repl), p->pack_name);
  
        return NULL;
@@@ -1473,7 -1473,7 +1473,7 @@@ void *read_object_with_reference(const 
                }
                ref_length = strlen(ref_type);
  
 -              if (ref_length + GIT_SHA1_HEXSZ > isize ||
 +              if (ref_length + the_hash_algo->hexsz > isize ||
                    memcmp(buffer, ref_type, ref_length) ||
                    get_oid_hex((char *) buffer + ref_length, &actual_oid)) {
                        free(buffer);
@@@ -1533,21 -1533,21 +1533,21 @@@ int finalize_object_file(const char *tm
        unlink_or_warn(tmpfile);
        if (ret) {
                if (ret != EEXIST) {
-                       return error_errno("unable to write sha1 filename %s", filename);
+                       return error_errno(_("unable to write sha1 filename %s"), filename);
                }
                /* FIXME!!! Collision check here ? */
        }
  
  out:
        if (adjust_shared_perm(filename))
-               return error("unable to set permission to '%s'", filename);
+               return error(_("unable to set permission to '%s'"), filename);
        return 0;
  }
  
  static int write_buffer(int fd, const void *buf, size_t len)
  {
        if (write_in_full(fd, buf, len) < 0)
-               return error_errno("file write error");
+               return error_errno(_("file write error"));
        return 0;
  }
  
@@@ -1566,7 -1566,7 +1566,7 @@@ static void close_sha1_file(int fd
        if (fsync_object_files)
                fsync_or_die(fd, "sha1 file");
        if (close(fd) != 0)
-               die_errno("error when closing sha1 file");
+               die_errno(_("error when closing sha1 file"));
  }
  
  /* Size of directory component, including the ending '/' */
@@@ -1632,9 -1632,9 +1632,9 @@@ static int write_loose_object(const str
        fd = create_tmpfile(&tmp_file, filename.buf);
        if (fd < 0) {
                if (errno == EACCES)
-                       return error("insufficient permission for adding an object to repository database %s", get_object_directory());
+                       return error(_("insufficient permission for adding an object to repository database %s"), get_object_directory());
                else
-                       return error_errno("unable to create temporary file");
+                       return error_errno(_("unable to create temporary file"));
        }
  
        /* Set it up */
                ret = git_deflate(&stream, Z_FINISH);
                the_hash_algo->update_fn(&c, in0, stream.next_in - in0);
                if (write_buffer(fd, compressed, stream.next_out - compressed) < 0)
-                       die("unable to write sha1 file");
+                       die(_("unable to write sha1 file"));
                stream.next_out = compressed;
                stream.avail_out = sizeof(compressed);
        } while (ret == Z_OK);
  
        if (ret != Z_STREAM_END)
-               die("unable to deflate new object %s (%d)", oid_to_hex(oid),
+               die(_("unable to deflate new object %s (%d)"), oid_to_hex(oid),
                    ret);
        ret = git_deflate_end_gently(&stream);
        if (ret != Z_OK)
-               die("deflateEnd on object %s failed (%d)", oid_to_hex(oid),
+               die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid),
                    ret);
        the_hash_algo->final_fn(parano_oid.hash, &c);
        if (oidcmp(oid, &parano_oid) != 0)
-               die("confused by unstable object source data for %s",
+               die(_("confused by unstable object source data for %s"),
                    oid_to_hex(oid));
  
        close_sha1_file(fd);
                utb.actime = mtime;
                utb.modtime = mtime;
                if (utime(tmp_file.buf, &utb) < 0)
-                       warning_errno("failed utime() on %s", tmp_file.buf);
+                       warning_errno(_("failed utime() on %s"), tmp_file.buf);
        }
  
        return finalize_object_file(tmp_file.buf, filename.buf);
@@@ -1757,7 -1757,7 +1757,7 @@@ int force_object_loose(const struct obj
                return 0;
        buf = read_object(oid->hash, &type, &len);
        if (!buf)
-               return error("cannot read sha1_file for %s", oid_to_hex(oid));
+               return error(_("cannot read sha1_file for %s"), oid_to_hex(oid));
        hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(type), len) + 1;
        ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime);
        free(buf);
@@@ -1801,16 -1801,16 +1801,16 @@@ static void check_commit(const void *bu
  {
        struct commit c;
        memset(&c, 0, sizeof(c));
 -      if (parse_commit_buffer(&c, buf, size, 0))
 +      if (parse_commit_buffer(the_repository, &c, buf, size, 0))
-               die("corrupt commit");
+               die(_("corrupt commit"));
  }
  
  static void check_tag(const void *buf, size_t size)
  {
        struct tag t;
        memset(&t, 0, sizeof(t));
 -      if (parse_tag_buffer(&t, buf, size))
 +      if (parse_tag_buffer(the_repository, &t, buf, size))
-               die("corrupt tag");
+               die(_("corrupt tag"));
  }
  
  static int index_mem(struct object_id *oid, void *buf, size_t size,
@@@ -1903,10 -1903,10 +1903,10 @@@ static int index_core(struct object_id 
                char *buf = xmalloc(size);
                ssize_t read_result = read_in_full(fd, buf, size);
                if (read_result < 0)
-                       ret = error_errno("read error while indexing %s",
+                       ret = error_errno(_("read error while indexing %s"),
                                          path ? path : "<unknown>");
                else if (read_result != size)
-                       ret = error("short read while indexing %s",
+                       ret = error(_("short read while indexing %s"),
                                    path ? path : "<unknown>");
                else
                        ret = index_mem(oid, buf, size, type, path, flags);
@@@ -1977,7 -1977,7 +1977,7 @@@ int index_path(struct object_id *oid, c
                if (fd < 0)
                        return error_errno("open(\"%s\")", path);
                if (index_fd(oid, fd, st, OBJ_BLOB, path, flags) < 0)
-                       return error("%s: failed to insert into database",
+                       return error(_("%s: failed to insert into database"),
                                     path);
                break;
        case S_IFLNK:
                if (!(flags & HASH_WRITE_OBJECT))
                        hash_object_file(sb.buf, sb.len, blob_type, oid);
                else if (write_object_file(sb.buf, sb.len, blob_type, oid))
-                       rc = error("%s: failed to insert into database", path);
+                       rc = error(_("%s: failed to insert into database"), path);
                strbuf_release(&sb);
                break;
        case S_IFDIR:
                return resolve_gitlink_ref(path, "HEAD", oid);
        default:
-               return error("%s: unsupported file type", path);
+               return error(_("%s: unsupported file type"), path);
        }
        return rc;
  }
@@@ -2016,9 -2016,9 +2016,9 @@@ void assert_oid_type(const struct objec
  {
        enum object_type type = oid_object_info(the_repository, oid, NULL);
        if (type < 0)
-               die("%s is not a valid object", oid_to_hex(oid));
+               die(_("%s is not a valid object"), oid_to_hex(oid));
        if (type != expect)
-               die("%s is not a valid '%s' object", oid_to_hex(oid),
+               die(_("%s is not a valid '%s' object"), oid_to_hex(oid),
                    type_name(expect));
  }
  
@@@ -2045,7 -2045,7 +2045,7 @@@ int for_each_file_in_obj_subdir(unsigne
        dir = opendir(path->buf);
        if (!dir) {
                if (errno != ENOENT)
-                       r = error_errno("unable to open %s", path->buf);
+                       r = error_errno(_("unable to open %s"), path->buf);
                strbuf_setlen(path, origlen);
                return r;
        }
                namelen = strlen(de->d_name);
                strbuf_setlen(path, baselen);
                strbuf_add(path, de->d_name, namelen);
 -              if (namelen == GIT_SHA1_HEXSZ - 2 &&
 +              if (namelen == the_hash_algo->hexsz - 2 &&
                    !hex_to_bytes(oid.hash + 1, de->d_name,
 -                                GIT_SHA1_RAWSZ - 1)) {
 +                                the_hash_algo->rawsz - 1)) {
                        if (obj_cb) {
                                r = obj_cb(&oid, path->buf, data);
                                if (r)
@@@ -2202,18 -2202,18 +2202,18 @@@ static int check_stream_sha1(git_zstrea
        git_inflate_end(stream);
  
        if (status != Z_STREAM_END) {
-               error("corrupt loose object '%s'", sha1_to_hex(expected_sha1));
+               error(_("corrupt loose object '%s'"), sha1_to_hex(expected_sha1));
                return -1;
        }
        if (stream->avail_in) {
-               error("garbage at end of loose object '%s'",
+               error(_("garbage at end of loose object '%s'"),
                      sha1_to_hex(expected_sha1));
                return -1;
        }
  
        the_hash_algo->final_fn(real_sha1, &c);
        if (hashcmp(expected_sha1, real_sha1)) {
-               error("sha1 mismatch for %s (expected %s)", path,
+               error(_("sha1 mismatch for %s (expected %s)"), path,
                      sha1_to_hex(expected_sha1));
                return -1;
        }
@@@ -2237,18 -2237,18 +2237,18 @@@ int read_loose_object(const char *path
  
        map = map_sha1_file_1(the_repository, path, NULL, &mapsize);
        if (!map) {
-               error_errno("unable to mmap %s", path);
+               error_errno(_("unable to mmap %s"), path);
                goto out;
        }
  
        if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) {
-               error("unable to unpack header of %s", path);
+               error(_("unable to unpack header of %s"), path);
                goto out;
        }
  
        *type = parse_sha1_header(hdr, size);
        if (*type < 0) {
-               error("unable to parse header of %s", path);
+               error(_("unable to parse header of %s"), path);
                git_inflate_end(&stream);
                goto out;
        }
        } else {
                *contents = unpack_sha1_rest(&stream, hdr, *size, expected_oid->hash);
                if (!*contents) {
-                       error("unable to unpack contents of %s", path);
+                       error(_("unable to unpack contents of %s"), path);
                        git_inflate_end(&stream);
                        goto out;
                }
                if (check_object_signature(expected_oid, *contents,
                                         *size, type_name(*type))) {
-                       error("sha1 mismatch for %s (expected %s)", path,
+                       error(_("sha1 mismatch for %s (expected %s)"), path,
                              oid_to_hex(expected_oid));
                        free(*contents);
                        goto out;
diff --combined t/t0021-conversion.sh
index 6a213608cc10fc29691f8bf293b0a34ce1f93c5e,306b862d7f2220580cdf2c37a9cd6b00364b8e28..308cd28f3bd7304a63628e8a64014e8d20faa82f
@@@ -583,7 -583,7 +583,7 @@@ test_expect_success PERL 'process filte
                git checkout --quiet --no-progress . 2>git-stderr.log &&
  
                grep "smudge write error at" git-stderr.log &&
-               grep "error: external filter" git-stderr.log &&
+               test_i18ngrep "error: external filter" git-stderr.log &&
  
                cat >expected.log <<-EOF &&
                        START
@@@ -785,7 -785,7 +785,7 @@@ test_expect_success PERL 'missing file 
                cd repo &&
                git init &&
                echo "*.a filter=bug" >.gitattributes &&
 -              cp "$TEST_ROOT/test.o" missing-delay.a
 +              cp "$TEST_ROOT/test.o" missing-delay.a &&
                git add . &&
                git commit -m "test commit"
        ) &&
@@@ -807,7 -807,7 +807,7 @@@ test_expect_success PERL 'invalid file 
                git init &&
                echo "*.a filter=bug" >.gitattributes &&
                cp "$TEST_ROOT/test.o" invalid-delay.a &&
 -              cp "$TEST_ROOT/test.o" unfiltered
 +              cp "$TEST_ROOT/test.o" unfiltered &&
                git add . &&
                git commit -m "test commit"
        ) &&
diff --combined t/t3210-pack-refs.sh
index 724b4b9bc037a229ec4fae9d6e49e0cf47188070,7e95713f9e6390a0f87b2befab542a7779dda025..7333d7d5459179ab306d29fc04e7d088d75412af
@@@ -186,7 -186,7 +186,7 @@@ test_expect_success 'notice d/f conflic
  
  test_expect_success 'existing directory reports concrete ref' '
        test_must_fail git branch foo 2>stderr &&
-       grep refs/heads/foo/bar/baz stderr
+       test_i18ngrep refs/heads/foo/bar/baz stderr
  '
  
  test_expect_success 'notice d/f conflict with existing ref' '
@@@ -231,9 -231,9 +231,9 @@@ test_expect_success 'timeout if packed-
  test_expect_success 'retry acquiring packed-refs.lock' '
        LOCK=.git/packed-refs.lock &&
        >"$LOCK" &&
 -      test_when_finished "wait; rm -f $LOCK" &&
 +      test_when_finished "wait && rm -f $LOCK" &&
        {
 -              ( sleep 1 ; rm -f $LOCK ) &
 +              ( sleep 1 && rm -f $LOCK ) &
        } &&
        git -c core.packedrefstimeout=3000 pack-refs --all --prune
  '
diff --combined t/t5500-fetch-pack.sh
index fa03f56a2026b712519f932a8b4fd4a01bee80cc,d2d27f9b54ecafccc530df0e77e1aadeb0fcbccc..8f945235e3a94156de4dadaff5e944751f056372
@@@ -259,7 -259,7 +259,7 @@@ test_expect_success 'clone shallow obje
  test_expect_success 'pull in shallow repo with missing merge base' '
        (
                cd shallow &&
 -              git fetch --depth 4 .. A
 +              git fetch --depth 4 .. A &&
                test_must_fail git merge --allow-unrelated-histories FETCH_HEAD
        )
  '
@@@ -403,7 -403,7 +403,7 @@@ test_expect_success 'fetch creating ne
                git fetch --depth=1 --progress 2>actual &&
                # This should fetch only the empty commit, no tree or
                # blob objects
-               grep "remote: Total 1" actual
+               test_i18ngrep "remote: Total 1" actual
        )
  '
  
@@@ -533,26 -533,19 +533,26 @@@ test_expect_success 'test --all wrt ta
        # are reachable only via created tag references.
        blob=$(echo "hello blob" | git hash-object -t blob -w --stdin) &&
        git tag -a -m "tag -> blob" tag-to-blob $blob &&
 - \
 +
        tree=$(printf "100644 blob $blob\tfile" | git mktree) &&
        git tag -a -m "tag -> tree" tag-to-tree $tree &&
 - \
 +
        tree2=$(printf "100644 blob $blob\tfile2" | git mktree) &&
        commit=$(git commit-tree -m "hello commit" $tree) &&
        git tag -a -m "tag -> commit" tag-to-commit $commit &&
 - \
 +
        blob2=$(echo "hello blob2" | git hash-object -t blob -w --stdin) &&
 -      tag=$(printf "object $blob2\ntype blob\ntag tag-to-blob2\n\
 -tagger author A U Thor <author@example.com> 0 +0000\n\nhello tag" | git mktag) &&
 +      tag=$(git mktag <<-EOF
 +              object $blob2
 +              type blob
 +              tag tag-to-blob2
 +              tagger author A U Thor <author@example.com> 0 +0000
 +
 +              hello tag
 +      EOF
 +      ) &&
        git tag -a -m "tag -> tag" tag-to-tag $tag &&
 - \
 +
        # `fetch-pack --all` should succeed fetching all those objects.
        mkdir fetchall &&
        (
@@@ -814,39 -807,6 +814,39 @@@ test_expect_success 'fetching deepen' 
        )
  '
  
 +test_expect_success 'use ref advertisement to prune "have" lines sent' '
 +      rm -rf server client &&
 +      git init server &&
 +      test_commit -C server both_have_1 &&
 +      git -C server tag -d both_have_1 &&
 +      test_commit -C server both_have_2 &&
 +
 +      git clone server client &&
 +      test_commit -C server server_has &&
 +      test_commit -C client client_has &&
 +
 +      # In both protocol v0 and v2, ensure that the parent of both_have_2 is
 +      # not sent as a "have" line. The client should know that the server has
 +      # both_have_2, so it only needs to inform the server that it has
 +      # both_have_2, and the server can infer the rest.
 +
 +      rm -f trace &&
 +      cp -r client clientv0 &&
 +      GIT_TRACE_PACKET="$(pwd)/trace" git -C clientv0 \
 +              fetch origin server_has both_have_2 &&
 +      grep "have $(git -C client rev-parse client_has)" trace &&
 +      grep "have $(git -C client rev-parse both_have_2)" trace &&
 +      ! grep "have $(git -C client rev-parse both_have_2^)" trace &&
 +
 +      rm -f trace &&
 +      cp -r client clientv2 &&
 +      GIT_TRACE_PACKET="$(pwd)/trace" git -C clientv2 -c protocol.version=2 \
 +              fetch origin server_has both_have_2 &&
 +      grep "have $(git -C client rev-parse client_has)" trace &&
 +      grep "have $(git -C client rev-parse both_have_2)" trace &&
 +      ! grep "have $(git -C client rev-parse both_have_2^)" trace
 +'
 +
  test_expect_success 'filtering by size' '
        rm -rf server client &&
        test_create_repo server &&
diff --combined t/t5505-remote.sh
index 11e14a1e0fd591c053e3cb50a1a40e49b2b93e09,ca4c222743782d036c30255c838dd5f4cad020e5..a6856e052b8f9e33a98a869d0b37c5977d93418f
@@@ -348,13 -348,17 +348,13 @@@ URL: $(pwd)/on
  EOF
  
  test_expect_success 'prune --dry-run' '
 -      (
 -              cd one &&
 -              git branch -m side2 side) &&
 +      git -C one branch -m side2 side &&
 +      test_when_finished "git -C one branch -m side side2" &&
        (
                cd test &&
                git remote prune --dry-run origin >output &&
                git rev-parse refs/remotes/origin/side2 &&
                test_must_fail git rev-parse refs/remotes/origin/side &&
 -      (
 -              cd ../one &&
 -              git branch -m side side2) &&
                test_i18ncmp expect output
        )
  '
@@@ -844,7 -848,7 +844,7 @@@ test_expect_success 'migrate a remote f
                git remote rename origin origin &&
                test_path_is_missing .git/branches/origin &&
                test "$(git config remote.origin.url)" = "quux" &&
 -              test "$(git config remote.origin.fetch)" = "refs/heads/foom:refs/heads/origin"
 +              test "$(git config remote.origin.fetch)" = "refs/heads/foom:refs/heads/origin" &&
                test "$(git config remote.origin.push)" = "HEAD:refs/heads/foom"
        )
  '
@@@ -872,7 -876,7 +872,7 @@@ test_expect_success 'remote prune to ca
                cd eight &&
                test_must_fail git branch nomore origin
        ) 2>err &&
-       grep "dangling symref" err
+       test_i18ngrep "dangling symref" err
  '
  
  test_expect_success 'show empty remote' '
index ee5757966f597637a3f9f1602a9ef4bd7ffd908d,e3bc53b0c748d9911a3065b34a521cf3ba742ef4..aaaa722ccab016cc5847d5b6bbc5a3879a0b3fbc
@@@ -96,7 -96,7 +96,7 @@@ test_expect_success 'push new branch wi
  
  test_expect_success 'push new branch with HEAD:new refspec' '
        (cd local &&
 -       git checkout new-name
 +       git checkout new-name &&
         git push origin HEAD:new-refspec-2
        ) &&
        compare_refs local HEAD server refs/heads/new-refspec-2
@@@ -126,7 -126,7 +126,7 @@@ test_expect_success 'forced push' 
  test_expect_success 'cloning without refspec' '
        GIT_REMOTE_TESTGIT_REFSPEC="" \
        git clone "testgit::${PWD}/server" local2 2>error &&
-       grep "This remote helper should implement refspec capability" error &&
+       test_i18ngrep "this remote helper should implement refspec capability" error &&
        compare_refs local2 HEAD server HEAD
  '
  
@@@ -134,7 -134,7 +134,7 @@@ test_expect_success 'pulling without re
        (cd local2 &&
        git reset --hard &&
        GIT_REMOTE_TESTGIT_REFSPEC="" git pull 2>../error) &&
-       grep "This remote helper should implement refspec capability" error &&
+       test_i18ngrep "this remote helper should implement refspec capability" error &&
        compare_refs local2 HEAD server HEAD
  '
  
@@@ -146,7 -146,7 +146,7 @@@ test_expect_success 'pushing without re
        GIT_REMOTE_TESTGIT_REFSPEC="" &&
        export GIT_REMOTE_TESTGIT_REFSPEC &&
        test_must_fail git push 2>../error) &&
-       grep "remote-helper doesn.t support push; refspec needed" error
+       test_i18ngrep "remote-helper doesn.t support push; refspec needed" error
  '
  
  test_expect_success 'pulling without marks' '
@@@ -246,7 -246,7 +246,7 @@@ test_expect_success 'proper failure che
        (cd local &&
        test_must_fail env GIT_REMOTE_TESTGIT_FAILURE=1 git fetch 2>error &&
        cat error &&
-       grep -q "Error while running fast-import" error
+       test_i18ngrep -q "error while running fast-import" error
        )
  '
  
index 2c2c97e144172a54319ac4d988884407f4186243,d6853e94bed56ade8711e86e662063cb99f5755a..2b71e62ec2c26e6b1bbbcf71e69c5e5b784dc2ba
@@@ -171,13 -171,12 +171,13 @@@ test_expect_success 'submodule add to .
  test_expect_success 'submodule add to reconfigure existing submodule with --force' '
        (
                cd addtest-ignore &&
 -              git submodule add --force bogus-url submod &&
 -              git submodule add -b initial "$submodurl" submod-branch &&
 -              test "bogus-url" = "$(git config -f .gitmodules submodule.submod.url)" &&
 -              test "bogus-url" = "$(git config submodule.submod.url)" &&
 +              bogus_url="$(pwd)/bogus-url" &&
 +              git submodule add --force "$bogus_url" submod &&
 +              git submodule add --force -b initial "$submodurl" submod-branch &&
 +              test "$bogus_url" = "$(git config -f .gitmodules submodule.submod.url)" &&
 +              test "$bogus_url" = "$(git config submodule.submod.url)" &&
                # Restore the url
 -              git submodule add --force "$submodurl" submod
 +              git submodule add --force "$submodurl" submod &&
                test "$submodurl" = "$(git config -f .gitmodules submodule.submod.url)" &&
                test "$submodurl" = "$(git config submodule.submod.url)"
        )
@@@ -378,7 -377,7 +378,7 @@@ test_expect_success 'init should regist
  
  test_failure_with_unknown_submodule () {
        test_must_fail git submodule $1 no-such-submodule 2>output.err &&
-       grep "^error: .*no-such-submodule" output.err
+       test_i18ngrep "^error: .*no-such-submodule" output.err
  }
  
  test_expect_success 'init should fail with unknown submodule' '
@@@ -819,7 -818,7 +819,7 @@@ test_expect_success '../bar/a/b/c work
                cp pristine-.git-config .git/config &&
                cp pristine-.gitmodules .gitmodules &&
                mkdir -p a/b/c &&
 -              (cd a/b/c; git init) &&
 +              (cd a/b/c && git init) &&
                git config remote.origin.url ../foo/bar.git &&
                git submodule add ../bar/a/b/c ./a/b/c &&
                git submodule init &&
@@@ -994,11 -993,6 +994,11 @@@ test_expect_success 'submodule deinit s
        rmdir init
  '
  
 +test_expect_success 'submodule deinit should unset core.worktree' '
 +      test_path_is_file .git/modules/example/config &&
 +      test_must_fail git config -f .git/modules/example/config core.worktree
 +'
 +
  test_expect_success 'submodule deinit from subdirectory' '
        git submodule update --init &&
        git config submodule.example.foo bar &&
diff --combined transport-helper.c
index eab7f47565089538fa7fb28d3046148be39b4763,84a10661cc06ab9bb103a61dfdc1bb02536d7816..0a7192910505cee35347daf2115690bb02dfbaa4
@@@ -48,7 -48,7 +48,7 @@@ static void sendline(struct helper_dat
        if (debug)
                fprintf(stderr, "Debug: Remote helper: -> %s", buffer->buf);
        if (write_in_full(helper->helper->in, buffer->buf, buffer->len) < 0)
-               die_errno("Full write to remote helper failed");
+               die_errno(_("full write to remote helper failed"));
  }
  
  static int recvline_fh(FILE *helper, struct strbuf *buffer)
@@@ -77,7 -77,7 +77,7 @@@ static void write_constant(int fd, cons
        if (debug)
                fprintf(stderr, "Debug: Remote helper: -> %s", str);
        if (write_in_full(fd, str, strlen(str)) < 0)
-               die_errno("Full write to remote helper failed");
+               die_errno(_("full write to remote helper failed"));
  }
  
  static const char *remove_ext_force(const char *url)
@@@ -129,7 -129,7 +129,7 @@@ static struct child_process *get_helper
  
        code = start_command(helper);
        if (code < 0 && errno == ENOENT)
-               die("Unable to find remote helper for '%s'", data->name);
+               die(_("unable to find remote helper for '%s'"), data->name);
        else if (code != 0)
                exit(code);
  
         */
        duped = dup(helper->out);
        if (duped < 0)
-               die_errno("Can't dup helper output fd");
+               die_errno(_("can't dup helper output fd"));
        data->out = xfdopen(duped, "r");
  
        write_constant(helper->in, "capabilities\n");
                } else if (starts_with(capname, "no-private-update")) {
                        data->no_private_update = 1;
                } else if (mandatory) {
-                       die("Unknown mandatory capability %s. This remote "
-                           "helper probably needs newer version of Git.",
+                       die(_("unknown mandatory capability %s; this remote "
+                             "helper probably needs newer version of Git"),
                            capname);
                }
        }
        if (!data->rs.nr && (data->import || data->bidi_import || data->export)) {
-               warning("This remote helper should implement refspec capability.");
+               warning(_("this remote helper should implement refspec capability"));
        }
        strbuf_release(&buf);
        if (debug)
@@@ -269,7 -269,7 +269,7 @@@ static int strbuf_set_helper_option(str
        else if (!strcmp(buf->buf, "unsupported"))
                ret = 1;
        else {
-               warning("%s unexpectedly said: '%s'", data->name, buf->buf);
+               warning(_("%s unexpectedly said: '%s'"), data->name, buf->buf);
                ret = 1;
        }
        return ret;
@@@ -398,7 -398,7 +398,7 @@@ static int fetch_with_fetch(struct tran
                if (starts_with(buf.buf, "lock ")) {
                        const char *name = buf.buf + 5;
                        if (transport->pack_lockfile)
-                               warning("%s also locked %s", data->name, name);
+                               warning(_("%s also locked %s"), data->name, name);
                        else
                                transport->pack_lockfile = xstrdup(name);
                }
                else if (!buf.len)
                        break;
                else
-                       warning("%s unexpectedly said: '%s'", data->name, buf.buf);
+                       warning(_("%s unexpectedly said: '%s'"), data->name, buf.buf);
        }
        strbuf_release(&buf);
        return 0;
@@@ -476,7 -476,7 +476,7 @@@ static int fetch_with_import(struct tra
        get_helper(transport);
  
        if (get_importer(transport, &fastimport))
-               die("Couldn't run fast-import");
+               die(_("couldn't run fast-import"));
  
        for (i = 0; i < nr_heads; i++) {
                posn = to_fetch[i];
         */
  
        if (finish_command(&fastimport))
-               die("Error while running fast-import");
+               die(_("error while running fast-import"));
  
        /*
         * The fast-import stream of a remote helper that advertises
                        private = xstrdup(name);
                if (private) {
                        if (read_ref(private, &posn->old_oid) < 0)
-                               die("Could not read ref %s", private);
+                               die(_("could not read ref %s"), private);
                        free(private);
                }
        }
@@@ -554,7 -554,7 +554,7 @@@ static int run_connect(struct transpor
         */
        duped = dup(helper->out);
        if (duped < 0)
-               die_errno("Can't dup helper output fd");
+               die_errno(_("can't dup helper output fd"));
        input = xfdopen(duped, "r");
        setvbuf(input, NULL, _IONBF, 0);
  
                        fprintf(stderr, "Debug: Falling back to dumb "
                                "transport.\n");
        } else {
-               die("Unknown response to connect: %s",
-                       cmdbuf->buf);
+               die(_(_("unknown response to connect: %s")),
+                   cmdbuf->buf);
        }
  
        fclose(input);
@@@ -595,9 -595,9 +595,9 @@@ static int process_connect_service(stru
        if (strcmp(name, exec)) {
                int r = set_helper_option(transport, "servpath", exec);
                if (r > 0)
-                       warning("Setting remote service path not supported by protocol.");
+                       warning(_("setting remote service path not supported by protocol"));
                else if (r < 0)
-                       warning("Invalid remote service path.");
+                       warning(_("invalid remote service path"));
        }
  
        if (data->connect) {
@@@ -640,10 -640,10 +640,10 @@@ static int connect_helper(struct transp
        /* Get_helper so connect is inited. */
        get_helper(transport);
        if (!data->connect)
-               die("Operation not supported by protocol.");
+               die(_("operation not supported by protocol"));
  
        if (!process_connect_service(transport, name, exec))
-               die("Can't connect to subservice %s.", name);
+               die(_("can't connect to subservice %s"), name);
  
        fd[0] = data->helper->out;
        fd[1] = data->helper->in;
  }
  
  static int fetch(struct transport *transport,
 -               int nr_heads, struct ref **to_fetch)
 +               int nr_heads, struct ref **to_fetch,
 +               struct ref **fetched_refs)
  {
        struct helper_data *data = transport->data;
        int i, count;
  
        if (process_connect(transport, 0)) {
                do_take_over(transport);
 -              return transport->vtable->fetch(transport, nr_heads, to_fetch);
 +              return transport->vtable->fetch(transport, nr_heads, to_fetch,
 +                                              fetched_refs);
        }
  
        count = 0;
                        transport, "filter",
                        data->transport_options.filter_options.filter_spec);
  
 +      if (data->transport_options.negotiation_tips)
 +              warning("Ignoring --negotiation-tip because the protocol does not support it.");
 +
        if (data->fetch)
                return fetch_with_fetch(transport, nr_heads, to_fetch);
  
@@@ -712,7 -707,7 +712,7 @@@ static int push_update_ref_status(struc
                status = REF_STATUS_REMOTE_REJECT;
                refname = buf->buf + 6;
        } else
-               die("expected ok/error, helper said '%s'", buf->buf);
+               die(_("expected ok/error, helper said '%s'"), buf->buf);
  
        msg = strchr(refname, ' ');
        if (msg) {
        if (!*ref)
                *ref = find_ref_by_name(remote_refs, refname);
        if (!*ref) {
-               warning("helper reported unexpected status of %s", refname);
+               warning(_("helper reported unexpected status of %s"), refname);
                return 1;
        }
  
@@@ -826,20 -821,20 +826,20 @@@ static void set_common_push_options(str
  {
        if (flags & TRANSPORT_PUSH_DRY_RUN) {
                if (set_helper_option(transport, "dry-run", "true") != 0)
-                       die("helper %s does not support dry-run", name);
+                       die(_("helper %s does not support dry-run"), name);
        } else if (flags & TRANSPORT_PUSH_CERT_ALWAYS) {
                if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "true") != 0)
-                       die("helper %s does not support --signed", name);
+                       die(_("helper %s does not support --signed"), name);
        } else if (flags & TRANSPORT_PUSH_CERT_IF_ASKED) {
                if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "if-asked") != 0)
-                       die("helper %s does not support --signed=if-asked", name);
+                       die(_("helper %s does not support --signed=if-asked"), name);
        }
  
        if (flags & TRANSPORT_PUSH_OPTIONS) {
                struct string_list_item *item;
                for_each_string_list_item(item, transport->push_options)
                        if (set_helper_option(transport, "push-option", item->string) != 0)
-                               die("helper %s does not support 'push-option'", name);
+                               die(_("helper %s does not support 'push-option'"), name);
        }
  }
  
@@@ -931,12 -926,12 +931,12 @@@ static int push_refs_with_export(struc
        struct strbuf buf = STRBUF_INIT;
  
        if (!data->rs.nr)
-               die("remote-helper doesn't support push; refspec needed");
+               die(_("remote-helper doesn't support push; refspec needed"));
  
        set_common_push_options(transport, data->name, flags);
        if (flags & TRANSPORT_PUSH_FORCE) {
                if (set_helper_option(transport, "force", "true") != 0)
-                       warning("helper %s does not support 'force'", data->name);
+                       warning(_("helper %s does not support 'force'"), data->name);
        }
  
        helper = get_helper(transport);
        }
  
        if (get_exporter(transport, &exporter, &revlist_args))
-               die("Couldn't run fast-export");
+               die(_("couldn't run fast-export"));
  
        string_list_clear(&revlist_args, 1);
  
        if (finish_command(&exporter))
-               die("Error while running fast-export");
+               die(_("error while running fast-export"));
        if (push_update_refs_status(data, remote_refs, flags))
                return 1;
  
@@@ -1012,8 -1007,9 +1012,9 @@@ static int push_refs(struct transport *
        }
  
        if (!remote_refs) {
-               fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
-                       "Perhaps you should specify a branch such as 'master'.\n");
+               fprintf(stderr,
+                       _("No refs in common and none specified; doing nothing.\n"
+                         "Perhaps you should specify a branch such as 'master'.\n"));
                return 0;
        }
  
@@@ -1075,7 -1071,7 +1076,7 @@@ static struct ref *get_refs_list(struc
  
                eov = strchr(buf.buf, ' ');
                if (!eov)
-                       die("Malformed response in ref list: %s", buf.buf);
+                       die(_("malformed response in ref list: %s"), buf.buf);
                eon = strchr(eov + 1, ' ');
                *eov = '\0';
                if (eon)
                        if (has_attribute(eon + 1, "unchanged")) {
                                (*tail)->status |= REF_STATUS_UPTODATE;
                                if (read_ref((*tail)->name, &(*tail)->old_oid) < 0)
-                                       die(_("Could not read ref %s"),
+                                       die(_("could not read ref %s"),
                                            (*tail)->name);
                        }
                }
@@@ -1228,7 -1224,7 +1229,7 @@@ static int udt_do_read(struct unidirect
        bytes = read(t->src, t->buf + t->bufuse, BUFFERSIZE - t->bufuse);
        if (bytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN &&
                errno != EINTR) {
-               error_errno("read(%s) failed", t->src_name);
+               error_errno(_("read(%s) failed"), t->src_name);
                return -1;
        } else if (bytes == 0) {
                transfer_debug("%s EOF (with %i bytes in buffer)",
@@@ -1255,7 -1251,7 +1256,7 @@@ static int udt_do_write(struct unidirec
        transfer_debug("%s is writable", t->dest_name);
        bytes = xwrite(t->dest, t->buf, t->bufuse);
        if (bytes < 0 && errno != EWOULDBLOCK) {
-               error_errno("write(%s) failed", t->dest_name);
+               error_errno(_("write(%s) failed"), t->dest_name);
                return -1;
        } else if (bytes > 0) {
                t->bufuse -= bytes;
@@@ -1304,11 -1300,11 +1305,11 @@@ static int tloop_join(pthread_t thread
        void *tret;
        err = pthread_join(thread, &tret);
        if (!tret) {
-               error("%s thread failed", name);
+               error(_("%s thread failed"), name);
                return 1;
        }
        if (err) {
-               error("%s thread failed to join: %s", name, strerror(err));
+               error(_("%s thread failed to join: %s"), name, strerror(err));
                return 1;
        }
        return 0;
@@@ -1327,11 -1323,11 +1328,11 @@@ static int tloop_spawnwait_tasks(struc
        err = pthread_create(&gtp_thread, NULL, udt_copy_task_routine,
                &s->gtp);
        if (err)
-               die("Can't start thread for copying data: %s", strerror(err));
+               die(_("can't start thread for copying data: %s"), strerror(err));
        err = pthread_create(&ptg_thread, NULL, udt_copy_task_routine,
                &s->ptg);
        if (err)
-               die("Can't start thread for copying data: %s", strerror(err));
+               die(_("can't start thread for copying data: %s"), strerror(err));
  
        ret |= tloop_join(gtp_thread, "Git to program copy");
        ret |= tloop_join(ptg_thread, "Program to git copy");
@@@ -1368,11 -1364,11 +1369,11 @@@ static int tloop_join(pid_t pid, const 
  {
        int tret;
        if (waitpid(pid, &tret, 0) < 0) {
-               error_errno("%s process failed to wait", name);
+               error_errno(_("%s process failed to wait"), name);
                return 1;
        }
        if (!WIFEXITED(tret) || WEXITSTATUS(tret)) {
-               error("%s process failed", name);
+               error(_("%s process failed"), name);
                return 1;
        }
        return 0;
@@@ -1390,7 -1386,7 +1391,7 @@@ static int tloop_spawnwait_tasks(struc
        /* Fork thread #1: git to program. */
        pid1 = fork();
        if (pid1 < 0)
-               die_errno("Can't start thread for copying data");
+               die_errno(_("can't start thread for copying data"));
        else if (pid1 == 0) {
                udt_kill_transfer(&s->ptg);
                exit(udt_copy_task_routine(&s->gtp) ? 0 : 1);
        /* Fork thread #2: program to git. */
        pid2 = fork();
        if (pid2 < 0)
-               die_errno("Can't start thread for copying data");
+               die_errno(_("can't start thread for copying data"));
        else if (pid2 == 0) {
                udt_kill_transfer(&s->gtp);
                exit(udt_copy_task_routine(&s->ptg) ? 0 : 1);
diff --combined transport.c
index b64b7bcb86f3c807d6a0dcd1dce26c7ee7fbb966,516a83b7f67afb830b069ba3c9007d236e292393..64c38bdeed3d7363c3ef6291bb6ce7ae6805f30e
@@@ -139,7 -139,7 +139,7 @@@ static struct ref *get_refs_from_bundle
                close(data->fd);
        data->fd = read_bundle_header(transport->url, &data->header);
        if (data->fd < 0)
-               die ("Could not read bundle '%s'.", transport->url);
+               die(_("could not read bundle '%s'"), transport->url);
        for (i = 0; i < data->header.references.nr; i++) {
                struct ref_list_entry *e = data->header.references.list + i;
                struct ref *ref = alloc_ref(e->name);
  }
  
  static int fetch_refs_from_bundle(struct transport *transport,
 -                             int nr_heads, struct ref **to_fetch)
 +                             int nr_heads, struct ref **to_fetch,
 +                             struct ref **fetched_refs)
  {
        struct bundle_transport_data *data = transport->data;
        return unbundle(&data->header, data->fd,
@@@ -288,8 -287,7 +288,8 @@@ static struct ref *get_refs_via_connect
  }
  
  static int fetch_refs_via_pack(struct transport *transport,
 -                             int nr_heads, struct ref **to_fetch)
 +                             int nr_heads, struct ref **to_fetch,
 +                             struct ref **fetched_refs)
  {
        int ret = 0;
        struct git_transport_data *data = transport->data;
        args.filter_options = data->options.filter_options;
        args.stateless_rpc = transport->stateless_rpc;
        args.server_options = transport->server_options;
 +      args.negotiation_tips = data->options.negotiation_tips;
  
        if (!data->got_remote_heads)
                refs_tmp = get_refs_via_connect(transport, 0, NULL);
        data->got_remote_heads = 0;
        data->options.self_contained_and_connected =
                args.self_contained_and_connected;
 +      data->options.connectivity_checked = args.connectivity_checked;
  
        if (refs == NULL)
                ret = -1;
        if (report_unmatched_refs(to_fetch, nr_heads))
                ret = -1;
  
 +      if (fetched_refs)
 +              *fetched_refs = refs;
 +      else
 +              free_refs(refs);
 +
        free_refs(refs_tmp);
 -      free_refs(refs);
        free(dest);
        return ret;
  }
@@@ -662,7 -654,7 +662,7 @@@ static int git_transport_push(struct tr
  
        switch (data->version) {
        case protocol_v2:
-               die("support for protocol v2 not implemented yet");
+               die(_("support for protocol v2 not implemented yet"));
                break;
        case protocol_v1:
        case protocol_v0:
@@@ -788,7 -780,7 +788,7 @@@ static enum protocol_allow_config parse
        else if (!strcasecmp(value, "user"))
                return PROTOCOL_ALLOW_USER_ONLY;
  
-       die("unknown value for config '%s': %s", key, value);
+       die(_("unknown value for config '%s': %s"), key, value);
  }
  
  static enum protocol_allow_config get_protocol_config(const char *type)
@@@ -854,7 -846,7 +854,7 @@@ int is_transport_allowed(const char *ty
  void transport_check_allowed(const char *type)
  {
        if (!is_transport_allowed(type, -1))
-               die("transport '%s' not allowed", type);
+               die(_("transport '%s' not allowed"), type);
  }
  
  static struct transport_vtable bundle_vtable = {
@@@ -883,7 -875,7 +883,7 @@@ struct transport *transport_get(struct 
        ret->progress = isatty(2);
  
        if (!remote)
-               die("No remote provided to transport_get()");
+               BUG("No remote provided to transport_get()");
  
        ret->got_remote_refs = 0;
        ret->remote = remote;
        if (helper) {
                transport_helper_init(ret, helper);
        } else if (starts_with(url, "rsync:")) {
-               die("git-over-rsync is no longer supported");
+               die(_("git-over-rsync is no longer supported"));
        } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) {
                struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
                transport_check_allowed("file");
@@@ -1151,7 -1143,7 +1151,7 @@@ int transport_push(struct transport *tr
                                                      transport->push_options,
                                                      pretend)) {
                                oid_array_clear(&commits);
-                               die("Failed to push all needed submodules!");
+                               die(_("failed to push all needed submodules"));
                        }
                        oid_array_clear(&commits);
                }
@@@ -1223,31 -1215,19 +1223,31 @@@ const struct ref *transport_get_remote_
        return transport->remote_refs;
  }
  
 -int transport_fetch_refs(struct transport *transport, struct ref *refs)
 +int transport_fetch_refs(struct transport *transport, struct ref *refs,
 +                       struct ref **fetched_refs)
  {
        int rc;
        int nr_heads = 0, nr_alloc = 0, nr_refs = 0;
        struct ref **heads = NULL;
 +      struct ref *nop_head = NULL, **nop_tail = &nop_head;
        struct ref *rm;
  
        for (rm = refs; rm; rm = rm->next) {
                nr_refs++;
                if (rm->peer_ref &&
                    !is_null_oid(&rm->old_oid) &&
 -                  !oidcmp(&rm->peer_ref->old_oid, &rm->old_oid))
 +                  !oidcmp(&rm->peer_ref->old_oid, &rm->old_oid)) {
 +                      /*
 +                       * These need to be reported as fetched, but we don't
 +                       * actually need to fetch them.
 +                       */
 +                      if (fetched_refs) {
 +                              struct ref *nop_ref = copy_ref(rm);
 +                              *nop_tail = nop_ref;
 +                              nop_tail = &nop_ref->next;
 +                      }
                        continue;
 +              }
                ALLOC_GROW(heads, nr_heads + 1, nr_alloc);
                heads[nr_heads++] = rm;
        }
                        heads[nr_heads++] = rm;
        }
  
 -      rc = transport->vtable->fetch(transport, nr_heads, heads);
 +      rc = transport->vtable->fetch(transport, nr_heads, heads, fetched_refs);
 +      if (fetched_refs && nop_head) {
 +              *nop_tail = *fetched_refs;
 +              *fetched_refs = nop_head;
 +      }
  
        free(heads);
        return rc;
@@@ -1289,7 -1265,7 +1289,7 @@@ int transport_connect(struct transport 
        if (transport->vtable->connect)
                return transport->vtable->connect(transport, name, exec, fd);
        else
-               die("Operation not supported by protocol");
+               die(_("operation not supported by protocol"));
  }
  
  int transport_disconnect(struct transport *transport)
@@@ -1371,7 -1347,7 +1371,7 @@@ static void read_alternate_refs(const c
  
                if (get_oid_hex(line.buf, &oid) ||
                    line.buf[GIT_SHA1_HEXSZ] != ' ') {
-                       warning("invalid line while parsing alternate refs: %s",
+                       warning(_("invalid line while parsing alternate refs: %s"),
                                line.buf);
                        break;
                }