Merge branch 'ab/i18n-st'
authorJunio C Hamano <gitster@pobox.com>
Sat, 2 Apr 2011 00:55:55 +0000 (17:55 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 2 Apr 2011 00:55:55 +0000 (17:55 -0700)
* ab/i18n-st: (69 commits)
i18n: git-shortlog basic messages
i18n: git-revert split up "could not revert/apply" message
i18n: git-revert literal "me" messages
i18n: git-revert "Your local changes" message
i18n: git-revert basic messages
i18n: git-notes GIT_NOTES_REWRITE_MODE error message
i18n: git-notes basic commands
i18n: git-gc "Auto packing the repository" message
i18n: git-gc basic messages
i18n: git-describe basic messages
i18n: git-clean clean.requireForce messages
i18n: git-clean basic messages
i18n: git-bundle basic messages
i18n: git-archive basic messages
i18n: git-status "renamed: " message
i18n: git-status "Initial commit" message
i18n: git-status "Changes to be committed" message
i18n: git-status shortstatus messages
i18n: git-status "nothing to commit" messages
i18n: git-status basic messages
...

Conflicts:
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/grep.c
builtin/merge.c
builtin/push.c
builtin/revert.c
t/t3507-cherry-pick-conflict.sh
t/t7607-merge-overwrite.sh

27 files changed:
1  2 
builtin/add.c
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/describe.c
builtin/diff.c
builtin/fetch.c
builtin/grep.c
builtin/init-db.c
builtin/log.c
builtin/merge.c
builtin/notes.c
builtin/push.c
builtin/reset.c
builtin/revert.c
builtin/tag.c
t/t0001-init.sh
t/t3200-branch.sh
t/t3507-cherry-pick-conflict.sh
t/t4014-format-patch.sh
t/t5601-clone.sh
t/t6040-tracking-info.sh
t/t7201-co.sh
t/t7500-commit.sh
t/t7607-merge-overwrite.sh
wt-status.c
diff --combined builtin/add.c
index e127d5a68b5c28497a3e640760e4c597fbaa59d5,a512597a5c9c0b630f62dc50e3c9ad54950228bb..d39a6ab930adf2e3cd716d3e9925350befed8947
@@@ -21,7 -21,8 +21,7 @@@ static const char * const builtin_add_u
  static int patch_interactive, add_interactive, edit_interactive;
  static int take_worktree_changes;
  
 -struct update_callback_data
 -{
 +struct update_callback_data {
        int flags;
        int add_errors;
  };
@@@ -37,7 -38,7 +37,7 @@@ static void update_callback(struct diff
                const char *path = p->one->path;
                switch (p->status) {
                default:
-                       die("unexpected diff status %c", p->status);
+                       die(_("unexpected diff status %c"), p->status);
                case DIFF_STATUS_UNMERGED:
                        /*
                         * ADD_CACHE_IGNORE_REMOVAL is unset if "git
@@@ -63,7 -64,7 +63,7 @@@
                case DIFF_STATUS_TYPE_CHANGED:
                        if (add_file_to_index(&the_index, path, data->flags)) {
                                if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
-                                       die("updating files failed");
+                                       die(_("updating files failed"));
                                data->add_errors++;
                        }
                        break;
@@@ -73,7 -74,7 +73,7 @@@
                        if (!(data->flags & ADD_CACHE_PRETEND))
                                remove_file_from_index(&the_index, path);
                        if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
-                               printf("remove '%s'\n", path);
+                               printf(_("remove '%s'\n"), path);
                        break;
                }
        }
@@@ -85,7 -86,7 +85,7 @@@ int add_files_to_cache(const char *pref
        struct rev_info rev;
        init_revisions(&rev, prefix);
        setup_revisions(0, NULL, &rev, NULL);
 -      rev.prune_data = pathspec;
 +      init_pathspec(&rev.prune_data, pathspec);
        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = update_callback;
        data.flags = flags;
@@@ -171,7 -172,7 +171,7 @@@ static void treat_gitlinks(const char *
                                        /* strip trailing slash */
                                        pathspec[j] = xstrndup(ce->name, len);
                                else
-                                       die ("Path '%s' is in submodule '%.*s'",
+                                       die (_("Path '%s' is in submodule '%.*s'"),
                                                pathspec[j], len, ce->name);
                        }
                }
@@@ -187,10 -188,10 +187,10 @@@ static void refresh(int verbose, const 
                /* nothing */;
        seen = xcalloc(specs, 1);
        refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
-                     pathspec, seen, "Unstaged changes after refreshing the index:");
+                     pathspec, seen, _("Unstaged changes after refreshing the index:"));
        for (i = 0; i < specs; i++) {
                if (!seen[i])
-                       die("pathspec '%s' did not match any files", pathspec[i]);
+                       die(_("pathspec '%s' did not match any files"), pathspec[i]);
        }
          free(seen);
  }
@@@ -204,7 -205,7 +204,7 @@@ static const char **validate_pathspec(i
                for (p = pathspec; *p; p++) {
                        if (has_symlink_leading_path(*p, strlen(*p))) {
                                int len = prefix ? strlen(prefix) : 0;
-                               die("'%s' is beyond a symbolic link", *p + len);
+                               die(_("'%s' is beyond a symbolic link"), *p + len);
                        }
                }
        }
@@@ -271,7 -272,7 +271,7 @@@ static int edit_patch(int argc, const c
        git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
  
        if (read_cache() < 0)
-               die ("Could not read the index");
+               die (_("Could not read the index"));
  
        init_revisions(&rev, prefix);
        rev.diffopt.context = 7;
        rev.diffopt.output_format = DIFF_FORMAT_PATCH;
        out = open(file, O_CREAT | O_WRONLY, 0644);
        if (out < 0)
-               die ("Could not open '%s' for writing.", file);
+               die (_("Could not open '%s' for writing."), file);
        rev.diffopt.file = xfdopen(out, "w");
        rev.diffopt.close_file = 1;
        if (run_diff_files(&rev, 0))
-               die ("Could not write patch");
+               die (_("Could not write patch"));
  
        launch_editor(file, NULL, NULL);
  
        if (stat(file, &st))
-               die_errno("Could not stat '%s'", file);
+               die_errno(_("Could not stat '%s'"), file);
        if (!st.st_size)
-               die("Empty patch. Aborted.");
+               die(_("Empty patch. Aborted."));
  
        memset(&child, 0, sizeof(child));
        child.git_cmd = 1;
        child.argv = apply_argv;
        if (run_command(&child))
-               die ("Could not apply '%s'", file);
+               die (_("Could not apply '%s'"), file);
  
        unlink(file);
        return 0;
  static struct lock_file lock_file;
  
  static const char ignore_error[] =
"The following paths are ignored by one of your .gitignore files:\n";
N_("The following paths are ignored by one of your .gitignore files:\n");
  
  static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
  static int ignore_add_errors, addremove, intent_to_add, ignore_missing = 0;
@@@ -321,7 -322,7 +321,7 @@@ static struct option builtin_add_option
        OPT__FORCE(&ignored_too, "allow adding otherwise ignored files"),
        OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
        OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
 -      OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"),
 +      OPT_BOOLEAN('A', "all", &addremove, "add changes from all tracked and untracked files"),
        OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
        OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
        OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, "check if - even missing - files are ignored in dry run"),
@@@ -343,17 -344,17 +343,17 @@@ static int add_files(struct dir_struct 
        int i, exit_status = 0;
  
        if (dir->ignored_nr) {
-               fprintf(stderr, ignore_error);
+               fprintf(stderr, _(ignore_error));
                for (i = 0; i < dir->ignored_nr; i++)
                        fprintf(stderr, "%s\n", dir->ignored[i]->name);
-               fprintf(stderr, "Use -f if you really want to add them.\n");
-               die("no files added");
+               fprintf(stderr, _("Use -f if you really want to add them.\n"));
+               die(_("no files added"));
        }
  
        for (i = 0; i < dir->nr; i++)
                if (add_file_to_cache(dir->entries[i]->name, flags)) {
                        if (!ignore_add_errors)
-                               die("adding files failed");
+                               die(_("adding files failed"));
                        exit_status = 1;
                }
        return exit_status;
@@@ -385,9 -386,9 +385,9 @@@ int cmd_add(int argc, const char **argv
        argv++;
  
        if (addremove && take_worktree_changes)
-               die("-A and -u are mutually incompatible");
+               die(_("-A and -u are mutually incompatible"));
        if (!show_only && ignore_missing)
-               die("Option --ignore-missing can only be used together with --dry-run");
+               die(_("Option --ignore-missing can only be used together with --dry-run"));
        if ((addremove || take_worktree_changes) && !argc) {
                static const char *here[2] = { ".", NULL };
                argc = 1;
                  ? ADD_CACHE_IGNORE_REMOVAL : 0));
  
        if (require_pathspec && argc == 0) {
-               fprintf(stderr, "Nothing specified, nothing added.\n");
-               fprintf(stderr, "Maybe you wanted to say 'git add .'?\n");
+               fprintf(stderr, _("Nothing specified, nothing added.\n"));
+               fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
                return 0;
        }
        pathspec = validate_pathspec(argc, argv, prefix);
  
        if (read_cache() < 0)
-               die("index file corrupt");
+               die(_("index file corrupt"));
        treat_gitlinks(pathspec);
  
        if (add_new_files) {
                                        if (excluded(&dir, pathspec[i], &dtype))
                                                dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i]));
                                } else
-                                       die("pathspec '%s' did not match any files",
+                                       die(_("pathspec '%s' did not match any files"),
                                            pathspec[i]);
                        }
                }
        if (active_cache_changed) {
                if (write_cache(newfd, active_cache, active_nr) ||
                    commit_locked_index(&lock_file))
-                       die("Unable to write new index file");
+                       die(_("Unable to write new index file"));
        }
  
        return exit_status;
diff --combined builtin/branch.c
index b9ba011f7b3f37a9448afae909d743249c3d8e1f,244589e73657bf1f2eaa1450c36f59869c0a44d6..9cca1b9afc20caf6333d0269386249f41fa8746f
@@@ -133,12 -133,12 +133,12 @@@ static int branch_merged(int kind, cons
        if ((head_rev != reference_rev) &&
            in_merge_bases(rev, &head_rev, 1) != merged) {
                if (merged)
-                       warning("deleting branch '%s' that has been merged to\n"
-                               "         '%s', but not yet been merged to HEAD.",
+                       warning(_("deleting branch '%s' that has been merged to\n"
 -                              "         '%s', but it is not yet merged to HEAD."),
++                              "         '%s', but not yet merged to HEAD."),
                                name, reference_name);
                else
-                       warning("not deleting branch '%s' that is not yet merged to\n"
-                               "         '%s', even though it is merged to HEAD.",
+                       warning(_("not deleting branch '%s' that is not yet merged to\n"
+                               "         '%s', even though it is merged to HEAD."),
                                name, reference_name);
        }
        return merged;
@@@ -157,7 -157,8 +157,8 @@@ static int delete_branches(int argc, co
        switch (kinds) {
        case REF_REMOTE_BRANCH:
                fmt = "refs/remotes/%s";
-               remote = "remote ";
+               /* TRANSLATORS: This is "remote " in "remote branch '%s' not found" */
+               remote = _("remote ");
                force = 1;
                break;
        case REF_LOCAL_BRANCH:
                remote = "";
                break;
        default:
-               die("cannot use -a with -d");
+               die(_("cannot use -a with -d"));
        }
  
        if (!force) {
                head_rev = lookup_commit_reference(head_sha1);
                if (!head_rev)
-                       die("Couldn't look up commit object for HEAD");
+                       die(_("Couldn't look up commit object for HEAD"));
        }
        for (i = 0; i < argc; i++, strbuf_release(&bname)) {
                strbuf_branchname(&bname, argv[i]);
                if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
-                       error("Cannot delete the branch '%s' "
-                             "which you are currently on.", bname.buf);
+                       error(_("Cannot delete the branch '%s' "
+                             "which you are currently on."), bname.buf);
                        ret = 1;
                        continue;
                }
  
                name = xstrdup(mkpath(fmt, bname.buf));
                if (!resolve_ref(name, sha1, 1, NULL)) {
-                       error("%sbranch '%s' not found.",
+                       error(_("%sbranch '%s' not found."),
                                        remote, bname.buf);
                        ret = 1;
                        continue;
  
                rev = lookup_commit_reference(sha1);
                if (!rev) {
-                       error("Couldn't look up commit object for '%s'", name);
+                       error(_("Couldn't look up commit object for '%s'"), name);
                        ret = 1;
                        continue;
                }
  
                if (!force && !branch_merged(kinds, bname.buf, rev, head_rev)) {
-                       error("The branch '%s' is not fully merged.\n"
+                       error(_("The branch '%s' is not fully merged.\n"
                              "If you are sure you want to delete it, "
-                             "run 'git branch -D %s'.", bname.buf, bname.buf);
+                             "run 'git branch -D %s'."), bname.buf, bname.buf);
                        ret = 1;
                        continue;
                }
  
                if (delete_ref(name, sha1, 0)) {
-                       error("Error deleting %sbranch '%s'", remote,
+                       error(_("Error deleting %sbranch '%s'"), remote,
                              bname.buf);
                        ret = 1;
                } else {
                        struct strbuf buf = STRBUF_INIT;
-                       printf("Deleted %sbranch %s (was %s).\n", remote,
+                       printf(_("Deleted %sbranch %s (was %s).\n"), remote,
                               bname.buf,
                               find_unique_abbrev(sha1, DEFAULT_ABBREV));
                        strbuf_addf(&buf, "branch.%s", bname.buf);
                        if (git_config_rename_section(buf.buf, NULL) < 0)
-                               warning("Update of config-file failed");
+                               warning(_("Update of config-file failed"));
                        strbuf_release(&buf);
                }
        }
@@@ -300,7 -301,7 +301,7 @@@ static int append_ref(const char *refna
        if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {
                commit = lookup_commit_reference_gently(sha1, 1);
                if (!commit) {
-                       cb->ret = error("branch '%s' does not point at a commit", refname);
+                       cb->ret = error(_("branch '%s' does not point at a commit"), refname);
                        return 0;
                }
  
@@@ -372,11 -373,11 +373,11 @@@ static void fill_tracking_info(struct s
                strbuf_addf(stat, "%s: ",
                        shorten_unambiguous_ref(branch->merge[0]->dst, 0));
        if (!ours)
-               strbuf_addf(stat, "behind %d] ", theirs);
+               strbuf_addf(stat, _("behind %d] "), theirs);
        else if (!theirs)
-               strbuf_addf(stat, "ahead %d] ", ours);
+               strbuf_addf(stat, _("ahead %d] "), ours);
        else
-               strbuf_addf(stat, "ahead %d, behind %d] ", ours, theirs);
+               strbuf_addf(stat, _("ahead %d, behind %d] "), ours, theirs);
  }
  
  static int matches_merge_filter(struct commit *commit)
        return (is_merged == (merge_filter == SHOW_MERGED));
  }
  
 +static void add_verbose_info(struct strbuf *out, struct ref_item *item,
 +                           int verbose, int abbrev)
 +{
 +      struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
 +      const char *sub = " **** invalid ref ****";
 +      struct commit *commit = item->commit;
 +
 +      if (commit && !parse_commit(commit)) {
 +              struct pretty_print_context ctx = {0};
 +              pretty_print_commit(CMIT_FMT_ONELINE, commit,
 +                                  &subject, &ctx);
 +              sub = subject.buf;
 +      }
 +
 +      if (item->kind == REF_LOCAL_BRANCH)
 +              fill_tracking_info(&stat, item->name, verbose > 1);
 +
 +      strbuf_addf(out, " %s %s%s",
 +              find_unique_abbrev(item->commit->object.sha1, abbrev),
 +              stat.buf, sub);
 +      strbuf_release(&stat);
 +      strbuf_release(&subject);
 +}
 +
  static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
                           int abbrev, int current, char *prefix)
  {
  
        if (item->dest)
                strbuf_addf(&out, " -> %s", item->dest);
 -      else if (verbose) {
 -              struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
 -              const char *sub = " **** invalid ref ****";
 -
 -              commit = item->commit;
 -              if (commit && !parse_commit(commit)) {
 -                      struct pretty_print_context ctx = {0};
 -                      pretty_print_commit(CMIT_FMT_ONELINE, commit,
 -                                          &subject, &ctx);
 -                      sub = subject.buf;
 -              }
 -
 -              if (item->kind == REF_LOCAL_BRANCH)
 -                      fill_tracking_info(&stat, item->name, verbose > 1);
 -
 -              strbuf_addf(&out, " %s %s%s",
 -                      find_unique_abbrev(item->commit->object.sha1, abbrev),
 -                      stat.buf, sub);
 -              strbuf_release(&stat);
 -              strbuf_release(&subject);
 -      }
 +      else if (verbose)
 +              /* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
 +              add_verbose_info(&out, item, verbose, abbrev);
        printf("%s\n", out.buf);
        strbuf_release(&name);
        strbuf_release(&out);
@@@ -481,7 -476,7 +482,7 @@@ static void show_detached(struct ref_li
  
        if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {
                struct ref_item item;
-               item.name = xstrdup("(no branch)");
+               item.name = xstrdup(_("(no branch)"));
                item.len = strlen(item.name);
                item.kind = REF_LOCAL_BRANCH;
                item.dest = NULL;
@@@ -541,7 -536,7 +542,7 @@@ static int print_ref_list(int kinds, in
        free_ref_list(&ref_list);
  
        if (cb.ret)
-               error("some refs could not be read");
+               error(_("some refs could not be read"));
  
        return cb.ret;
  }
@@@ -554,7 -549,7 +555,7 @@@ static void rename_branch(const char *o
        int recovery = 0;
  
        if (!oldname)
-               die("cannot rename the current branch while not on any.");
+               die(_("cannot rename the current branch while not on any."));
  
        if (strbuf_check_branch_ref(&oldref, oldname)) {
                /*
                if (resolve_ref(oldref.buf, sha1, 1, NULL))
                        recovery = 1;
                else
-                       die("Invalid branch name: '%s'", oldname);
+                       die(_("Invalid branch name: '%s'"), oldname);
        }
  
        if (strbuf_check_branch_ref(&newref, newname))
-               die("Invalid branch name: '%s'", newname);
+               die(_("Invalid branch name: '%s'"), newname);
  
        if (resolve_ref(newref.buf, sha1, 1, NULL) && !force)
-               die("A branch named '%s' already exists.", newref.buf + 11);
+               die(_("A branch named '%s' already exists."), newref.buf + 11);
  
        strbuf_addf(&logmsg, "Branch: renamed %s to %s",
                 oldref.buf, newref.buf);
  
        if (rename_ref(oldref.buf, newref.buf, logmsg.buf))
-               die("Branch rename failed");
+               die(_("Branch rename failed"));
        strbuf_release(&logmsg);
  
        if (recovery)
-               warning("Renamed a misnamed branch '%s' away", oldref.buf + 11);
+               warning(_("Renamed a misnamed branch '%s' away"), oldref.buf + 11);
  
        /* no need to pass logmsg here as HEAD didn't really move */
        if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL))
-               die("Branch renamed to %s, but HEAD is not updated!", newname);
+               die(_("Branch renamed to %s, but HEAD is not updated!"), newname);
  
        strbuf_addf(&oldsection, "branch.%s", oldref.buf + 11);
        strbuf_release(&oldref);
        strbuf_addf(&newsection, "branch.%s", newref.buf + 11);
        strbuf_release(&newref);
        if (git_config_rename_section(oldsection.buf, newsection.buf) < 0)
-               die("Branch is renamed, but update of config-file failed");
+               die(_("Branch is renamed, but update of config-file failed"));
        strbuf_release(&oldsection);
        strbuf_release(&newsection);
  }
@@@ -607,7 -602,7 +608,7 @@@ static int opt_parse_merge_filter(cons
        if (!arg)
                arg = "HEAD";
        if (get_sha1(arg, merge_filter_ref))
-               die("malformed object name %s", arg);
+               die(_("malformed object name %s"), arg);
        return 0;
  }
  
@@@ -681,13 -676,13 +682,13 @@@ int cmd_branch(int argc, const char **a
  
        head = resolve_ref("HEAD", head_sha1, 0, NULL);
        if (!head)
-               die("Failed to resolve HEAD as a valid ref.");
+               die(_("Failed to resolve HEAD as a valid ref."));
        head = xstrdup(head);
        if (!strcmp(head, "HEAD")) {
                detached = 1;
        } else {
                if (prefixcmp(head, "refs/heads/"))
-                       die("HEAD not found below refs/heads!");
+                       die(_("HEAD not found below refs/heads!"));
                head += 11;
        }
        hashcpy(merge_filter_ref, head_sha1);
                rename_branch(argv[0], argv[1], rename > 1);
        else if (argc <= 2) {
                if (kinds != REF_LOCAL_BRANCH)
-                       die("-a and -r options to 'git branch' do not make sense with a branch name");
+                       die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
                create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
                              force_create, reflog, track);
        } else
diff --combined builtin/checkout.c
index 686d0ffd300e3e23cfd31b12d4267b5930787317,9f8e41e37c271f7c76ac2ec58265414ef8334c39..eece5d6ac0f48ae76dc76c0f2ebda633cc0ded58
@@@ -30,7 -30,6 +30,7 @@@ struct checkout_opts 
        int quiet;
        int merge;
        int force;
 +      int force_detach;
        int writeout_stage;
        int writeout_error;
  
@@@ -104,9 -103,10 +104,10 @@@ static int check_stage(int stage, struc
                        return 0;
                pos++;
        }
-       return error("path '%s' does not have %s version",
-                    ce->name,
-                    (stage == 2) ? "our" : "their");
+       if (stage == 2)
+               return error(_("path '%s' does not have our version"), ce->name);
+       else
+               return error(_("path '%s' does not have their version"), ce->name);
  }
  
  static int check_all_stages(struct cache_entry *ce, int pos)
            ce_stage(active_cache[pos+1]) != 2 ||
            strcmp(active_cache[pos+2]->name, ce->name) ||
            ce_stage(active_cache[pos+2]) != 3)
-               return error("path '%s' does not have all three versions",
+               return error(_("path '%s' does not have all three versions"),
                             ce->name);
        return 0;
  }
@@@ -131,9 -131,10 +132,10 @@@ static int checkout_stage(int stage, st
                        return checkout_entry(active_cache[pos], state, NULL);
                pos++;
        }
-       return error("path '%s' does not have %s version",
-                    ce->name,
-                    (stage == 2) ? "our" : "their");
+       if (stage == 2)
+               return error(_("path '%s' does not have our version"), ce->name);
+       else
+               return error(_("path '%s' does not have their version"), ce->name);
  }
  
  static int checkout_merged(int pos, struct checkout *state)
            ce_stage(active_cache[pos+1]) != 2 ||
            strcmp(active_cache[pos+2]->name, path) ||
            ce_stage(active_cache[pos+2]) != 3)
-               return error("path '%s' does not have all 3 versions", path);
+               return error(_("path '%s' does not have all 3 versions"), path);
  
        read_mmblob(&ancestor, active_cache[pos]->sha1);
        read_mmblob(&ours, active_cache[pos+1]->sha1);
        free(theirs.ptr);
        if (status < 0 || !result_buf.ptr) {
                free(result_buf.ptr);
-               return error("path '%s': cannot merge", path);
+               return error(_("path '%s': cannot merge"), path);
        }
  
        /*
         */
        if (write_sha1_file(result_buf.ptr, result_buf.size,
                            blob_type, sha1))
-               die("Unable to add merge result for '%s'", path);
+               die(_("Unable to add merge result for '%s'"), path);
        ce = make_cache_entry(create_ce_mode(active_cache[pos+1]->ce_mode),
                              sha1,
                              path, 2, 0);
        if (!ce)
-               die("make_cache_entry failed for path '%s'", path);
+               die(_("make_cache_entry failed for path '%s'"), path);
        status = checkout_entry(ce, state, NULL);
        return status;
  }
@@@ -212,7 -213,7 +214,7 @@@ static int checkout_paths(struct tree *
  
        newfd = hold_locked_index(lock_file, 1);
        if (read_cache_preload(pathspec) < 0)
-               return error("corrupt index file");
+               return error(_("corrupt index file"));
  
        if (source_tree)
                read_tree_some(source_tree, pathspec);
                        if (!ce_stage(ce))
                                continue;
                        if (opts->force) {
-                               warning("path '%s' is unmerged", ce->name);
+                               warning(_("path '%s' is unmerged"), ce->name);
                        } else if (stage) {
                                errs |= check_stage(stage, ce, pos);
                        } else if (opts->merge) {
                                errs |= check_all_stages(ce, pos);
                        } else {
                                errs = 1;
-                               error("path '%s' is unmerged", ce->name);
+                               error(_("path '%s' is unmerged"), ce->name);
                        }
                        pos = skip_same_name(ce, pos) - 1;
                }
  
        if (write_cache(newfd, active_cache, active_nr) ||
            commit_locked_index(lock_file))
-               die("unable to write new index file");
+               die(_("unable to write new index file"));
  
        resolve_ref("HEAD", rev, 0, &flag);
        head = lookup_commit_reference_gently(rev, 1);
@@@ -293,7 -294,7 +295,7 @@@ static void show_local_changes(struct o
        rev.diffopt.flags = opts->flags;
        rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
        if (diff_setup_done(&rev.diffopt) < 0)
-               die("diff_setup_done failed");
+               die(_("diff_setup_done failed"));
        add_pending_object(&rev, head, NULL);
        run_diff_index(&rev, 0);
  }
@@@ -367,7 -368,7 +369,7 @@@ static int merge_working_tree(struct ch
        int newfd = hold_locked_index(lock_file, 1);
  
        if (read_cache_preload(NULL) < 0)
-               return error("corrupt index file");
+               return error(_("corrupt index file"));
  
        resolve_undo_clear();
        if (opts->force) {
                refresh_cache(REFRESH_QUIET);
  
                if (unmerged_cache()) {
-                       error("you need to resolve your current index first");
+                       error(_("you need to resolve your current index first"));
                        return 1;
                }
  
  
        if (write_cache(newfd, active_cache, active_nr) ||
            commit_locked_index(lock_file))
-               die("unable to write new index file");
+               die(_("unable to write new index file"));
  
        if (!opts->force && !opts->quiet)
                show_local_changes(&new->commit->object, &opts->diff_options);
@@@ -520,7 -521,7 +522,7 @@@ static void update_refs_for_switch(stru
                                temp = log_all_ref_updates;
                                log_all_ref_updates = 1;
                                if (log_ref_setup(ref_name, log_file, sizeof(log_file))) {
-                                       fprintf(stderr, "Can not do reflog for '%s'\n",
+                                       fprintf(stderr, _("Can not do reflog for '%s'\n"),
                                            opts->new_orphan_branch);
                                        log_all_ref_updates = temp;
                                        return;
        strbuf_addf(&msg, "checkout: moving from %s to %s",
                    old_desc ? old_desc : "(invalid)", new->name);
  
 -      if (new->path) {
 +      if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
 +              /* Nothing to do. */
 +      } else if (opts->force_detach || !new->path) {  /* No longer on any branch. */
 +              update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
 +                         REF_NODEREF, DIE_ON_ERR);
 +              if (!opts->quiet) {
 +                      if (old->path && advice_detached_head)
 +                              detach_advice(old->path, new->name);
-                       describe_detached_head("HEAD is now at", new->commit);
++                      describe_detached_head(_("HEAD is now at"), new->commit);
 +              }
 +      } else if (new->path) { /* Switch branches. */
                create_symref("HEAD", new->path, msg.buf);
                if (!opts->quiet) {
-                       if (old->path && !strcmp(new->path, old->path))
-                               fprintf(stderr, "Already on '%s'\n",
-                                       new->name);
-                       else if (opts->new_branch)
-                               fprintf(stderr, "Switched to%s branch '%s'\n",
-                                       opts->branch_exists ? " and reset" : " a new",
+                       if (old->path && !strcmp(new->path, old->path)) {
+                               fprintf(stderr, _("Already on '%s'\n"),
                                        new->name);
-                       else
-                               fprintf(stderr, "Switched to branch '%s'\n",
+                       } else if (opts->new_branch) {
+                               if (opts->branch_exists)
+                                       fprintf(stderr, _("Switched to and reset branch '%s'\n"), new->name);
+                               else
+                                       fprintf(stderr, _("Switched to a new branch '%s'\n"), new->name);
+                       } else {
+                               fprintf(stderr, _("Switched to branch '%s'\n"),
                                        new->name);
+                       }
                }
                if (old->path && old->name) {
                        char log_file[PATH_MAX], ref_file[PATH_MAX];
                        if (!file_exists(ref_file) && file_exists(log_file))
                                remove_path(log_file);
                }
 -      } else if (strcmp(new->name, "HEAD")) {
 -              update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
 -                         REF_NODEREF, DIE_ON_ERR);
 -              if (!opts->quiet) {
 -                      if (old->path && advice_detached_head)
 -                              detach_advice(old->path, new->name);
 -                      describe_detached_head(_("HEAD is now at"), new->commit);
 -              }
        }
        remove_branch_state();
        strbuf_release(&msg);
 -      if (!opts->quiet && (new->path || !strcmp(new->name, "HEAD")))
 +      if (!opts->quiet &&
 +          (new->path || (!opts->force_detach && !strcmp(new->name, "HEAD"))))
                report_tracking(new);
  }
  
-               die("internal error: only -- alone should have been left");
 +struct rev_list_args {
 +      int argc;
 +      int alloc;
 +      const char **argv;
 +};
 +
 +static void add_one_rev_list_arg(struct rev_list_args *args, const char *s)
 +{
 +      ALLOC_GROW(args->argv, args->argc + 1, args->alloc);
 +      args->argv[args->argc++] = s;
 +}
 +
 +static int add_one_ref_to_rev_list_arg(const char *refname,
 +                                     const unsigned char *sha1,
 +                                     int flags,
 +                                     void *cb_data)
 +{
 +      add_one_rev_list_arg(cb_data, refname);
 +      return 0;
 +}
 +
 +static int clear_commit_marks_from_one_ref(const char *refname,
 +                                    const unsigned char *sha1,
 +                                    int flags,
 +                                    void *cb_data)
 +{
 +      struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 +      if (commit)
 +              clear_commit_marks(commit, -1);
 +      return 0;
 +}
 +
 +static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
 +{
 +      struct pretty_print_context ctx = { 0 };
 +
 +      parse_commit(commit);
 +      strbuf_addstr(sb, "  ");
 +      strbuf_addstr(sb,
 +              find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
 +      strbuf_addch(sb, ' ');
 +      pretty_print_commit(CMIT_FMT_ONELINE, commit, sb, &ctx);
 +      strbuf_addch(sb, '\n');
 +}
 +
 +#define ORPHAN_CUTOFF 4
 +static void suggest_reattach(struct commit *commit, struct rev_info *revs)
 +{
 +      struct commit *c, *last = NULL;
 +      struct strbuf sb = STRBUF_INIT;
 +      int lost = 0;
 +      while ((c = get_revision(revs)) != NULL) {
 +              if (lost < ORPHAN_CUTOFF)
 +                      describe_one_orphan(&sb, c);
 +              last = c;
 +              lost++;
 +      }
 +      if (ORPHAN_CUTOFF < lost) {
 +              int more = lost - ORPHAN_CUTOFF;
 +              if (more == 1)
 +                      describe_one_orphan(&sb, last);
 +              else
 +                      strbuf_addf(&sb, " ... and %d more.\n", more);
 +      }
 +
 +      fprintf(stderr,
 +              "Warning: you are leaving %d commit%s behind, "
 +              "not connected to\n"
 +              "any of your branches:\n\n"
 +              "%s\n"
 +              "If you want to keep them by creating a new branch, "
 +              "this may be a good time\nto do so with:\n\n"
 +              " git branch new_branch_name %s\n\n",
 +              lost, ((1 < lost) ? "s" : ""),
 +              sb.buf,
 +              sha1_to_hex(commit->object.sha1));
 +      strbuf_release(&sb);
 +}
 +
 +/*
 + * We are about to leave commit that was at the tip of a detached
 + * HEAD.  If it is not reachable from any ref, this is the last chance
 + * for the user to do so without resorting to reflog.
 + */
 +static void orphaned_commit_warning(struct commit *commit)
 +{
 +      struct rev_list_args args = { 0, 0, NULL };
 +      struct rev_info revs;
 +
 +      add_one_rev_list_arg(&args, "(internal)");
 +      add_one_rev_list_arg(&args, sha1_to_hex(commit->object.sha1));
 +      add_one_rev_list_arg(&args, "--not");
 +      for_each_ref(add_one_ref_to_rev_list_arg, &args);
 +      add_one_rev_list_arg(&args, "--");
 +      add_one_rev_list_arg(&args, NULL);
 +
 +      init_revisions(&revs, NULL);
 +      if (setup_revisions(args.argc - 1, args.argv, &revs, NULL) != 1)
-               die("internal error in revision walk");
++              die(_("internal error: only -- alone should have been left"));
 +      if (prepare_revision_walk(&revs))
-               describe_detached_head("Previous HEAD position was", commit);
++              die(_("internal error in revision walk"));
 +      if (!(commit->object.flags & UNINTERESTING))
 +              suggest_reattach(commit, &revs);
 +      else
++              describe_detached_head(_("Previous HEAD position was"), commit);
 +
 +      clear_commit_marks(commit, -1);
 +      for_each_ref(clear_commit_marks_from_one_ref, NULL);
 +}
 +
  static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
  {
        int ret = 0;
                new->name = "HEAD";
                new->commit = old.commit;
                if (!new->commit)
-                       die("You are on a branch yet to be born");
+                       die(_("You are on a branch yet to be born"));
                parse_commit(new->commit);
        }
  
        if (ret)
                return ret;
  
 -      /*
 -       * If we were on a detached HEAD, but have now moved to
 -       * a new commit, we want to mention the old commit once more
 -       * to remind the user that it might be lost.
 -       */
        if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
 -              describe_detached_head(_("Previous HEAD position was"), old.commit);
 +              orphaned_commit_warning(old.commit);
  
        update_refs_for_switch(opts, &old, new);
  
@@@ -784,123 -679,11 +788,123 @@@ static const char *unique_tracking_name
        return NULL;
  }
  
-                       die("invalid reference: %s", arg);
 +static int parse_branchname_arg(int argc, const char **argv,
 +                              int dwim_new_local_branch_ok,
 +                              struct branch_info *new,
 +                              struct tree **source_tree,
 +                              unsigned char rev[20],
 +                              const char **new_branch)
 +{
 +      int argcount = 0;
 +      unsigned char branch_rev[20];
 +      const char *arg;
 +      int has_dash_dash;
 +
 +      /*
 +       * case 1: git checkout <ref> -- [<paths>]
 +       *
 +       *   <ref> must be a valid tree, everything after the '--' must be
 +       *   a path.
 +       *
 +       * case 2: git checkout -- [<paths>]
 +       *
 +       *   everything after the '--' must be paths.
 +       *
 +       * case 3: git checkout <something> [<paths>]
 +       *
 +       *   With no paths, if <something> is a commit, that is to
 +       *   switch to the branch or detach HEAD at it.  As a special case,
 +       *   if <something> is A...B (missing A or B means HEAD but you can
 +       *   omit at most one side), and if there is a unique merge base
 +       *   between A and B, A...B names that merge base.
 +       *
 +       *   With no paths, if <something> is _not_ a commit, no -t nor -b
 +       *   was given, and there is a tracking branch whose name is
 +       *   <something> in one and only one remote, then this is a short-hand
 +       *   to fork local <something> from that remote-tracking branch.
 +       *
 +       *   Otherwise <something> shall not be ambiguous.
 +       *   - If it's *only* a reference, treat it like case (1).
 +       *   - If it's only a path, treat it like case (2).
 +       *   - else: fail.
 +       *
 +       */
 +      if (!argc)
 +              return 0;
 +
 +      if (!strcmp(argv[0], "--"))     /* case (2) */
 +              return 1;
 +
 +      arg = argv[0];
 +      has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
 +
 +      if (!strcmp(arg, "-"))
 +              arg = "@{-1}";
 +
 +      if (get_sha1_mb(arg, rev)) {
 +              if (has_dash_dash)          /* case (1) */
-               die("reference is not a tree: %s", arg);
++                      die(_("invalid reference: %s"), arg);
 +              if (dwim_new_local_branch_ok &&
 +                  !check_filename(NULL, arg) &&
 +                  argc == 1) {
 +                      const char *remote = unique_tracking_name(arg);
 +                      if (!remote || get_sha1(remote, rev))
 +                              return argcount;
 +                      *new_branch = arg;
 +                      arg = remote;
 +                      /* DWIMmed to create local branch */
 +              } else {
 +                      return argcount;
 +              }
 +      }
 +
 +      /* we can't end up being in (2) anymore, eat the argument */
 +      argcount++;
 +      argv++;
 +      argc--;
 +
 +      new->name = arg;
 +      setup_branch_path(new);
 +
 +      if (check_ref_format(new->path) == CHECK_REF_FORMAT_OK &&
 +          resolve_ref(new->path, branch_rev, 1, NULL))
 +              hashcpy(rev, branch_rev);
 +      else
 +              new->path = NULL; /* not an existing branch */
 +
 +      new->commit = lookup_commit_reference_gently(rev, 1);
 +      if (!new->commit) {
 +              /* not a commit */
 +              *source_tree = parse_tree_indirect(rev);
 +      } else {
 +              parse_commit(new->commit);
 +              *source_tree = new->commit->tree;
 +      }
 +
 +      if (!*source_tree)                   /* case (1): want a tree */
++              die(_("reference is not a tree: %s"), arg);
 +      if (!has_dash_dash) {/* case (3 -> 1) */
 +              /*
 +               * Do not complain the most common case
 +               *      git checkout branch
 +               * even if there happen to be a file called 'branch';
 +               * it would be extremely annoying.
 +               */
 +              if (argc)
 +                      verify_non_filename(NULL, arg);
 +      } else {
 +              argcount++;
 +              argv++;
 +              argc--;
 +      }
 +
 +      return argcount;
 +}
 +
  int cmd_checkout(int argc, const char **argv, const char *prefix)
  {
        struct checkout_opts opts;
        unsigned char rev[20];
 -      const char *arg;
        struct branch_info new;
        struct tree *source_tree = NULL;
        char *conflict_style = NULL;
                OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
                           "create/reset and checkout a branch"),
                OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"),
 +              OPT_BOOLEAN(0, "detach", &opts.force_detach, "detach the HEAD at named commit"),
                OPT_SET_INT('t', "track",  &opts.track, "set upstream info for new branch",
                        BRANCH_TRACK_EXPLICIT),
                OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
                  PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
                OPT_END(),
        };
 -      int has_dash_dash;
  
        memset(&opts, 0, sizeof(opts));
        memset(&new, 0, sizeof(new));
  
        /* we can assume from now on new_branch = !new_branch_force */
        if (opts.new_branch && opts.new_branch_force)
-               die("-B cannot be used with -b");
+               die(_("-B cannot be used with -b"));
  
        /* copy -B over to -b, so that we can just check the latter */
        if (opts.new_branch_force)
                opts.new_branch = opts.new_branch_force;
  
        if (patch_mode && (opts.track > 0 || opts.new_branch
 -                         || opts.new_branch_log || opts.merge || opts.force))
 +                         || opts.new_branch_log || opts.merge || opts.force
 +                         || opts.force_detach))
-               die ("--patch is incompatible with all other options");
+               die (_("--patch is incompatible with all other options"));
  
 +      if (opts.force_detach && (opts.new_branch || opts.new_orphan_branch))
 +              die("--detach cannot be used with -b/-B/--orphan");
 +      if (opts.force_detach && 0 < opts.track)
 +              die("--detach cannot be used with -t");
 +
        /* --track without -b should DWIM */
        if (0 < opts.track && !opts.new_branch) {
                const char *argv0 = argv[0];
                if (!argc || !strcmp(argv0, "--"))
-                       die ("--track needs a branch name");
+                       die (_("--track needs a branch name"));
                if (!prefixcmp(argv0, "refs/"))
                        argv0 += 5;
                if (!prefixcmp(argv0, "remotes/"))
                        argv0 += 8;
                argv0 = strchr(argv0, '/');
                if (!argv0 || !argv0[1])
-                       die ("Missing branch name; try -b");
+                       die (_("Missing branch name; try -b"));
                opts.new_branch = argv0 + 1;
        }
  
        if (opts.new_orphan_branch) {
                if (opts.new_branch)
-                       die("--orphan and -b|-B are mutually exclusive");
+                       die(_("--orphan and -b|-B are mutually exclusive"));
                if (opts.track > 0)
-                       die("--orphan cannot be used with -t");
+                       die(_("--orphan cannot be used with -t"));
                opts.new_branch = opts.new_orphan_branch;
        }
  
        }
  
        if (opts.force && opts.merge)
-               die("git checkout: -f and -m are incompatible");
+               die(_("git checkout: -f and -m are incompatible"));
  
        /*
 -       * case 1: git checkout <ref> -- [<paths>]
 +       * Extract branch name from command line arguments, so
 +       * all that is left is pathspecs.
         *
 -       *   <ref> must be a valid tree, everything after the '--' must be
 -       *   a path.
 -       *
 -       * case 2: git checkout -- [<paths>]
 -       *
 -       *   everything after the '--' must be paths.
 -       *
 -       * case 3: git checkout <something> [<paths>]
 -       *
 -       *   With no paths, if <something> is a commit, that is to
 -       *   switch to the branch or detach HEAD at it.  As a special case,
 -       *   if <something> is A...B (missing A or B means HEAD but you can
 -       *   omit at most one side), and if there is a unique merge base
 -       *   between A and B, A...B names that merge base.
 -       *
 -       *   With no paths, if <something> is _not_ a commit, no -t nor -b
 -       *   was given, and there is a remote-tracking branch whose name is
 -       *   <something> in one and only one remote, then this is a short-hand
 -       *   to fork local <something> from that remote-tracking branch.
 +       * Handle
         *
 -       *   Otherwise <something> shall not be ambiguous.
 -       *   - If it's *only* a reference, treat it like case (1).
 -       *   - If it's only a path, treat it like case (2).
 -       *   - else: fail.
 +       *  1) git checkout <tree> -- [<paths>]
 +       *  2) git checkout -- [<paths>]
 +       *  3) git checkout <something> [<paths>]
         *
 +       * including "last branch" syntax and DWIM-ery for names of
 +       * remote branches, erroring out for invalid or ambiguous cases.
         */
        if (argc) {
 -              if (!strcmp(argv[0], "--")) {       /* case (2) */
 -                      argv++;
 -                      argc--;
 -                      goto no_reference;
 -              }
 -
 -              arg = argv[0];
 -              has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
 -
 -              if (!strcmp(arg, "-"))
 -                      arg = "@{-1}";
 -
 -              if (get_sha1_mb(arg, rev)) {
 -                      if (has_dash_dash)          /* case (1) */
 -                              die(_("invalid reference: %s"), arg);
 -                      if (!patch_mode &&
 -                          dwim_new_local_branch &&
 -                          opts.track == BRANCH_TRACK_UNSPECIFIED &&
 -                          !opts.new_branch &&
 -                          !check_filename(NULL, arg) &&
 -                          argc == 1) {
 -                              const char *remote = unique_tracking_name(arg);
 -                              if (!remote || get_sha1(remote, rev))
 -                                      goto no_reference;
 -                              opts.new_branch = arg;
 -                              arg = remote;
 -                              /* DWIMmed to create local branch */
 -                      }
 -                      else
 -                              goto no_reference;
 -              }
 -
 -              /* we can't end up being in (2) anymore, eat the argument */
 -              argv++;
 -              argc--;
 -
 -              new.name = arg;
 -              if ((new.commit = lookup_commit_reference_gently(rev, 1))) {
 -                      setup_branch_path(&new);
 -
 -                      if ((check_ref_format(new.path) == CHECK_REF_FORMAT_OK) &&
 -                          resolve_ref(new.path, rev, 1, NULL))
 -                              ;
 -                      else
 -                              new.path = NULL;
 -                      parse_commit(new.commit);
 -                      source_tree = new.commit->tree;
 -              } else
 -                      source_tree = parse_tree_indirect(rev);
 -
 -              if (!source_tree)                   /* case (1): want a tree */
 -                      die(_("reference is not a tree: %s"), arg);
 -              if (!has_dash_dash) {/* case (3 -> 1) */
 -                      /*
 -                       * Do not complain the most common case
 -                       *      git checkout branch
 -                       * even if there happen to be a file called 'branch';
 -                       * it would be extremely annoying.
 -                       */
 -                      if (argc)
 -                              verify_non_filename(NULL, arg);
 -              }
 -              else {
 -                      argv++;
 -                      argc--;
 -              }
 +              int dwim_ok =
 +                      !patch_mode &&
 +                      dwim_new_local_branch &&
 +                      opts.track == BRANCH_TRACK_UNSPECIFIED &&
 +                      !opts.new_branch;
 +              int n = parse_branchname_arg(argc, argv, dwim_ok,
 +                              &new, &source_tree, rev, &opts.new_branch);
 +              argv += n;
 +              argc -= n;
        }
  
 -no_reference:
 -
        if (opts.track == BRANCH_TRACK_UNSPECIFIED)
                opts.track = git_branch_track;
  
                const char **pathspec = get_pathspec(prefix, argv);
  
                if (!pathspec)
-                       die("invalid path specification");
+                       die(_("invalid path specification"));
  
                if (patch_mode)
                        return interactive_checkout(new.name, pathspec, &opts);
                /* Checkout paths */
                if (opts.new_branch) {
                        if (argc == 1) {
-                               die("git checkout: updating paths is incompatible with switching branches.\nDid you intend to checkout '%s' which can not be resolved as commit?", argv[0]);
+                               die(_("git checkout: updating paths is incompatible with switching branches.\nDid you intend to checkout '%s' which can not be resolved as commit?"), argv[0]);
                        } else {
-                               die("git checkout: updating paths is incompatible with switching branches.");
+                               die(_("git checkout: updating paths is incompatible with switching branches."));
                        }
                }
  
 +              if (opts.force_detach)
 +                      die("git checkout: --detach does not take a path argument");
 +
                if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge)
-                       die("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index.");
+                       die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index."));
  
                return checkout_paths(source_tree, pathspec, &opts);
        }
        if (opts.new_branch) {
                struct strbuf buf = STRBUF_INIT;
                if (strbuf_check_branch_ref(&buf, opts.new_branch))
-                       die("git checkout: we do not like '%s' as a branch name.",
+                       die(_("git checkout: we do not like '%s' as a branch name."),
                            opts.new_branch);
                if (!get_sha1(buf.buf, rev)) {
                        opts.branch_exists = 1;
                        if (!opts.new_branch_force)
-                               die("git checkout: branch %s already exists",
+                               die(_("git checkout: branch %s already exists"),
                                    opts.new_branch);
                }
                strbuf_release(&buf);
        }
  
        if (new.name && !new.commit) {
-               die("Cannot switch branch to a non-commit.");
+               die(_("Cannot switch branch to a non-commit."));
        }
        if (opts.writeout_stage)
-               die("--ours/--theirs is incompatible with switching branches.");
+               die(_("--ours/--theirs is incompatible with switching branches."));
  
        return switch_branches(&opts, &new);
  }
diff --combined builtin/clone.c
index c6e10bb9e916a21ad5c71018d6380ad85540dc65,b9394c41520407379b16297efac35c781cc0475f..0b5601a9b080e079ec077a8a765be24f2bf9bd29
@@@ -8,7 -8,7 +8,7 @@@
   * Clone a repository into a different directory that does not yet exist.
   */
  
 -#include "cache.h"
 +#include "builtin.h"
  #include "parse-options.h"
  #include "fetch-pack.h"
  #include "refs.h"
@@@ -100,7 -100,7 +100,7 @@@ static char *get_repo_path(const char *
                path = mkpath("%s%s", repo, suffix[i]);
                if (is_directory(path)) {
                        *is_bundle = 0;
 -                      return xstrdup(make_nonrelative_path(path));
 +                      return xstrdup(absolute_path(path));
                }
        }
  
                path = mkpath("%s%s", repo, bundle_suffix[i]);
                if (!stat(path, &st) && S_ISREG(st.st_mode)) {
                        *is_bundle = 1;
 -                      return xstrdup(make_nonrelative_path(path));
 +                      return xstrdup(absolute_path(path));
                }
        }
  
@@@ -203,12 -203,12 +203,12 @@@ static void setup_reference(const char 
        struct transport *transport;
        const struct ref *extra;
  
 -      ref_git = make_absolute_path(option_reference);
 +      ref_git = real_path(option_reference);
  
        if (is_directory(mkpath("%s/.git/objects", ref_git)))
                ref_git = mkpath("%s/.git", ref_git);
        else if (!is_directory(mkpath("%s/objects", ref_git)))
-               die("reference repository '%s' is not a local directory.",
+               die(_("reference repository '%s' is not a local directory."),
                    option_reference);
  
        ref_git_copy = xstrdup(ref_git);
@@@ -235,15 -235,15 +235,15 @@@ static void copy_or_link_directory(stru
  
        dir = opendir(src->buf);
        if (!dir)
-               die_errno("failed to open '%s'", src->buf);
+               die_errno(_("failed to open '%s'"), src->buf);
  
        if (mkdir(dest->buf, 0777)) {
                if (errno != EEXIST)
-                       die_errno("failed to create directory '%s'", dest->buf);
+                       die_errno(_("failed to create directory '%s'"), dest->buf);
                else if (stat(dest->buf, &buf))
-                       die_errno("failed to stat '%s'", dest->buf);
+                       die_errno(_("failed to stat '%s'"), dest->buf);
                else if (!S_ISDIR(buf.st_mode))
-                       die("%s exists and is not a directory", dest->buf);
+                       die(_("%s exists and is not a directory"), dest->buf);
        }
  
        strbuf_addch(src, '/');
                strbuf_setlen(dest, dest_len);
                strbuf_addstr(dest, de->d_name);
                if (stat(src->buf, &buf)) {
-                       warning ("failed to stat %s\n", src->buf);
+                       warning (_("failed to stat %s\n"), src->buf);
                        continue;
                }
                if (S_ISDIR(buf.st_mode)) {
                }
  
                if (unlink(dest->buf) && errno != ENOENT)
-                       die_errno("failed to unlink '%s'", dest->buf);
+                       die_errno(_("failed to unlink '%s'"), dest->buf);
                if (!option_no_hardlinks) {
                        if (!link(src->buf, dest->buf))
                                continue;
                        if (option_local)
-                               die_errno("failed to create link '%s'", dest->buf);
+                               die_errno(_("failed to create link '%s'"), dest->buf);
                        option_no_hardlinks = 1;
                }
                if (copy_file_with_time(dest->buf, src->buf, 0666))
-                       die_errno("failed to copy file to '%s'", dest->buf);
+                       die_errno(_("failed to copy file to '%s'"), dest->buf);
        }
        closedir(dir);
  }
@@@ -305,7 -305,7 +305,7 @@@ static const struct ref *clone_local(co
        ret = transport_get_remote_refs(transport);
        transport_disconnect(transport);
        if (0 <= option_verbosity)
-               printf("done.\n");
+               printf(_("done.\n"));
        return ret;
  }
  
@@@ -383,16 -383,15 +383,16 @@@ int cmd_clone(int argc, const char **ar
  
        junk_pid = getpid();
  
 +      packet_trace_identity("clone");
        argc = parse_options(argc, argv, prefix, builtin_clone_options,
                             builtin_clone_usage, 0);
  
        if (argc > 2)
-               usage_msg_opt("Too many arguments.",
+               usage_msg_opt(_("Too many arguments."),
                        builtin_clone_usage, builtin_clone_options);
  
        if (argc == 0)
-               usage_msg_opt("You must specify a repository to clone.",
+               usage_msg_opt(_("You must specify a repository to clone."),
                        builtin_clone_usage, builtin_clone_options);
  
        if (option_mirror)
  
        if (option_bare) {
                if (option_origin)
-                       die("--bare and --origin %s options are incompatible.",
+                       die(_("--bare and --origin %s options are incompatible."),
                            option_origin);
                option_no_checkout = 1;
        }
  
        path = get_repo_path(repo_name, &is_bundle);
        if (path)
 -              repo = xstrdup(make_nonrelative_path(repo_name));
 +              repo = xstrdup(absolute_path(repo_name));
        else if (!strchr(repo_name, ':'))
 -              repo = xstrdup(make_absolute_path(repo_name));
 +              die("repository '%s' does not exist", repo_name);
        else
                repo = repo_name;
        is_local = path && !is_bundle;
        if (is_local && option_depth)
-               warning("--depth is ignored in local clones; use file:// instead.");
+               warning(_("--depth is ignored in local clones; use file:// instead."));
  
        if (argc == 2)
                dir = xstrdup(argv[1]);
  
        dest_exists = !stat(dir, &buf);
        if (dest_exists && !is_empty_dir(dir))
-               die("destination path '%s' already exists and is not "
-                       "an empty directory.", dir);
+               die(_("destination path '%s' already exists and is not "
+                       "an empty directory."), dir);
  
        strbuf_addf(&reflog_msg, "clone: from %s", repo);
  
        else {
                work_tree = getenv("GIT_WORK_TREE");
                if (work_tree && !stat(work_tree, &buf))
-                       die("working tree '%s' already exists.", work_tree);
+                       die(_("working tree '%s' already exists."), work_tree);
        }
  
        if (option_bare || work_tree)
        if (!option_bare) {
                junk_work_tree = work_tree;
                if (safe_create_leading_directories_const(work_tree) < 0)
-                       die_errno("could not create leading directories of '%s'",
+                       die_errno(_("could not create leading directories of '%s'"),
                                  work_tree);
                if (!dest_exists && mkdir(work_tree, 0755))
-                       die_errno("could not create work tree dir '%s'.",
+                       die_errno(_("could not create work tree dir '%s'."),
                                  work_tree);
                set_git_work_tree(work_tree);
        }
        setenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1);
  
        if (safe_create_leading_directories_const(git_dir) < 0)
-               die("could not create leading directories of '%s'", git_dir);
+               die(_("could not create leading directories of '%s'"), git_dir);
 -      set_git_dir(make_absolute_path(git_dir));
 +      set_git_dir(real_path(git_dir));
  
-       if (0 <= option_verbosity)
-               printf("Cloning into %s%s...\n",
-                      option_bare ? "bare repository " : "", dir);
+       if (0 <= option_verbosity) {
+               if (option_bare)
+                       printf(_("Cloning into bare repository %s...\n"), dir);
+               else
+                       printf(_("Cloning into %s...\n"), dir);
+       }
        init_db(option_template, INIT_DB_QUIET);
  
        /*
                transport = transport_get(remote, remote->url[0]);
  
                if (!transport->get_refs_list || !transport->fetch)
-                       die("Don't know how to clone %s", transport->url);
+                       die(_("Don't know how to clone %s"), transport->url);
  
                transport_set_option(transport, TRANS_OPT_KEEP, "yes");
  
                        strbuf_release(&head);
  
                        if (!our_head_points_at) {
-                               warning("Remote branch %s not found in "
-                                       "upstream %s, using HEAD instead",
+                               warning(_("Remote branch %s not found in "
+                                       "upstream %s, using HEAD instead"),
                                        option_branch, option_origin);
                                our_head_points_at = remote_head_points_at;
                        }
                        our_head_points_at = remote_head_points_at;
        }
        else {
-               warning("You appear to have cloned an empty repository.");
+               warning(_("You appear to have cloned an empty repository."));
                our_head_points_at = NULL;
                remote_head_points_at = NULL;
                remote_head = NULL;
        } else {
                /* Nothing to checkout out */
                if (!option_no_checkout)
-                       warning("remote HEAD refers to nonexistent ref, "
-                               "unable to checkout.\n");
+                       warning(_("remote HEAD refers to nonexistent ref, "
+                               "unable to checkout.\n"));
                option_no_checkout = 1;
        }
  
  
                if (write_cache(fd, active_cache, active_nr) ||
                    commit_locked_index(lock_file))
-                       die("unable to write new index file");
+                       die(_("unable to write new index file"));
  
                err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
                                sha1_to_hex(our_head_points_at->old_sha1), "1",
diff --combined builtin/commit.c
index 54b20497b120bc2bf5ee6e4904eca0ca5d83ff4f,271f31127cc338359fddf423d266bc2abba9dc23..67757e999fba514b62767d3351031e9eb6ef8c10
@@@ -38,7 -38,7 +38,7 @@@ static const char * const builtin_statu
  };
  
  static const char implicit_ident_advice[] =
- "Your name and email address were configured automatically based\n"
N_("Your name and email address were configured automatically based\n"
  "on your username and hostname. Please check that they are accurate.\n"
  "You can suppress this message by setting them explicitly:\n"
  "\n"
  "\n"
  "After doing this, you may fix the identity used for this commit with:\n"
  "\n"
- "    git commit --amend --reset-author\n";
+ "    git commit --amend --reset-author\n");
  
  static const char empty_amend_advice[] =
- "You asked to amend the most recent commit, but doing so would make\n"
N_("You asked to amend the most recent commit, but doing so would make\n"
  "it empty. You can repeat your command with --allow-empty, or you can\n"
- "remove the commit entirely with \"git reset HEAD^\".\n";
+ "remove the commit entirely with \"git reset HEAD^\".\n");
  
- "The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
 +static const char empty_cherry_pick_advice[] =
- "Otherwise, please use 'git reset'\n";
++N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
 +"If you wish to commit it anyway, use:\n"
 +"\n"
 +"    git commit --allow-empty\n"
 +"\n"
++"Otherwise, please use 'git reset'\n");
 +
  static unsigned char head_sha1[20];
  
 -static char *use_message_buffer;
 +static const char *use_message_buffer;
  static const char commit_editmsg[] = "COMMIT_EDITMSG";
  static struct lock_file index_lock; /* real index */
  static struct lock_file false_lock; /* used only for partial commits */
@@@ -76,11 -68,6 +76,11 @@@ static enum 
  
  static const char *logfile, *force_author;
  static const char *template_file;
 +/*
 + * The _message variables are commit names from which to take
 + * the commit message and/or authorship.
 + */
 +static const char *author_message, *author_message_buffer;
  static char *edit_message, *use_message;
  static char *fixup_message, *squash_message;
  static int all, edit_flag, also, interactive, only, amend, signoff;
@@@ -101,8 -88,7 +101,8 @@@ static enum 
  } cleanup_mode;
  static char *cleanup_arg;
  
 -static int use_editor = 1, initial_commit, in_merge, include_status = 1;
 +static enum commit_whence whence;
 +static int use_editor = 1, initial_commit, include_status = 1;
  static int show_ignored_in_status;
  static const char *only_include_assumed;
  static struct strbuf message;
@@@ -133,13 -119,13 +133,13 @@@ static struct option builtin_commit_opt
  
        OPT_GROUP("Commit message options"),
        OPT_FILENAME('F', "file", &logfile, "read message from file"),
 -      OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"),
 -      OPT_STRING(0, "date", &force_date, "DATE", "override date for commit"),
 -      OPT_CALLBACK('m', "message", &message, "MESSAGE", "commit message", opt_parse_m),
 -      OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit"),
 -      OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"),
 -      OPT_STRING(0, "fixup", &fixup_message, "COMMIT", "use autosquash formatted message to fixup specified commit"),
 -      OPT_STRING(0, "squash", &squash_message, "COMMIT", "use autosquash formatted message to squash specified commit"),
 +      OPT_STRING(0, "author", &force_author, "author", "override author for commit"),
 +      OPT_STRING(0, "date", &force_date, "date", "override date for commit"),
 +      OPT_CALLBACK('m', "message", &message, "message", "commit message", opt_parse_m),
 +      OPT_STRING('c', "reedit-message", &edit_message, "commit", "reuse and edit message from specified commit"),
 +      OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"),
 +      OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"),
 +      OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"),
        OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C-c/--amend)"),
        OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
        OPT_FILENAME('t', "template", &template_file, "use specified template file"),
        OPT_END()
  };
  
 +static void determine_whence(struct wt_status *s)
 +{
 +      if (file_exists(git_path("MERGE_HEAD")))
 +              whence = FROM_MERGE;
 +      else if (file_exists(git_path("CHERRY_PICK_HEAD")))
 +              whence = FROM_CHERRY_PICK;
 +      else
 +              whence = FROM_COMMIT;
 +      if (s)
 +              s->whence = whence;
 +}
 +
 +static const char *whence_s(void)
 +{
 +      char *s = "";
 +
 +      switch (whence) {
 +      case FROM_COMMIT:
 +              break;
 +      case FROM_MERGE:
 +              s = "merge";
 +              break;
 +      case FROM_CHERRY_PICK:
 +              s = "cherry-pick";
 +              break;
 +      }
 +
 +      return s;
 +}
 +
  static void rollback_index_files(void)
  {
        switch (commit_style) {
@@@ -287,7 -243,7 +287,7 @@@ static void add_remove_files(struct str
  
                if (!lstat(p->string, &st)) {
                        if (add_to_cache(p->string, &st, 0))
-                               die("updating files failed");
+                               die(_("updating files failed"));
                } else
                        remove_file_from_cache(p->string);
        }
@@@ -314,7 -270,7 +314,7 @@@ static void create_base_index(void
        opts.fn = oneway_merge;
        tree = parse_tree_indirect(head_sha1);
        if (!tree)
-               die("failed to unpack HEAD tree object");
+               die(_("failed to unpack HEAD tree object"));
        parse_tree(tree);
        init_tree_desc(&t, tree->buffer, tree->size);
        if (unpack_trees(1, &t, &opts))
@@@ -342,9 -298,9 +342,9 @@@ static char *prepare_index(int argc, co
                refresh_flags |= REFRESH_UNMERGED;
        if (interactive) {
                if (interactive_add(argc, argv, prefix) != 0)
-                       die("interactive add failed");
+                       die(_("interactive add failed"));
                if (read_cache_preload(NULL) < 0)
-                       die("index file corrupt");
+                       die(_("index file corrupt"));
                commit_style = COMMIT_AS_IS;
                return get_index_file();
        }
                pathspec = get_pathspec(prefix, argv);
  
        if (read_cache_preload(pathspec) < 0)
-               die("index file corrupt");
+               die(_("index file corrupt"));
  
        /*
         * Non partial, non as-is commit.
                refresh_cache_or_die(refresh_flags);
                if (write_cache(fd, active_cache, active_nr) ||
                    close_lock_file(&index_lock))
-                       die("unable to write new_index file");
+                       die(_("unable to write new_index file"));
                commit_style = COMMIT_NORMAL;
                return index_lock.filename;
        }
                if (active_cache_changed) {
                        if (write_cache(fd, active_cache, active_nr) ||
                            commit_locked_index(&index_lock))
-                               die("unable to write new_index file");
+                               die(_("unable to write new_index file"));
                } else {
                        rollback_lock_file(&index_lock);
                }
         */
        commit_style = COMMIT_PARTIAL;
  
 -      if (in_merge)
 -              die(_("cannot do a partial commit during a merge."));
 +      if (whence != FROM_COMMIT)
-               die("cannot do a partial commit during a %s.", whence_s());
++              die(_("cannot do a partial commit during a %s."), whence_s());
  
        memset(&partial, 0, sizeof(partial));
        partial.strdup_strings = 1;
  
        discard_cache();
        if (read_cache() < 0)
-               die("cannot read the index");
+               die(_("cannot read the index"));
  
        fd = hold_locked_index(&index_lock, 1);
        add_remove_files(&partial);
        refresh_cache(REFRESH_QUIET);
        if (write_cache(fd, active_cache, active_nr) ||
            close_lock_file(&index_lock))
-               die("unable to write new_index file");
+               die(_("unable to write new_index file"));
  
        fd = hold_lock_file_for_update(&false_lock,
                                       git_path("next-index-%"PRIuMAX,
  
        if (write_cache(fd, active_cache, active_nr) ||
            close_lock_file(&false_lock))
-               die("unable to write temporary index file");
+               die(_("unable to write temporary index file"));
  
        discard_cache();
        read_cache_from(false_lock.filename);
@@@ -499,7 -455,7 +499,7 @@@ static int is_a_merge(const unsigned ch
  {
        struct commit *commit = lookup_commit(sha1);
        if (!commit || parse_commit(commit))
-               die("could not parse HEAD commit");
+               die(_("could not parse HEAD commit"));
        return !!(commit->parents && commit->parents->next);
  }
  
@@@ -513,18 -469,18 +513,18 @@@ static void determine_author_info(struc
        email = getenv("GIT_AUTHOR_EMAIL");
        date = getenv("GIT_AUTHOR_DATE");
  
 -      if (use_message && !renew_authorship) {
 +      if (author_message) {
                const char *a, *lb, *rb, *eol;
  
 -              a = strstr(use_message_buffer, "\nauthor ");
 +              a = strstr(author_message_buffer, "\nauthor ");
                if (!a)
-                       die("invalid commit: %s", author_message);
 -                      die(_("invalid commit: %s"), use_message);
++                      die(_("invalid commit: %s"), author_message);
  
                lb = strchrnul(a + strlen("\nauthor "), '<');
                rb = strchrnul(lb, '>');
                eol = strchrnul(rb, '\n');
                if (!*lb || !*rb || !*eol)
-                       die("invalid commit: %s", author_message);
 -                      die(_("invalid commit: %s"), use_message);
++                      die(_("invalid commit: %s"), author_message);
  
                if (lb == a + strlen("\nauthor "))
                        /* \nauthor <foo@example.com> */
                const char *rb = strchr(force_author, '>');
  
                if (!lb || !rb)
-                       die("malformed --author parameter");
+                       die(_("malformed --author parameter"));
                name = xstrndup(force_author, lb - force_author);
                email = xstrndup(lb + 2, rb - (lb + 2));
        }
@@@ -598,7 -554,7 +598,7 @@@ static char *cut_ident_timestamp_part(c
  {
        char *ket = strrchr(string, '>');
        if (!ket || ket[1] != ' ')
-               die("Malformed ident string: '%s'", string);
+               die(_("Malformed ident string: '%s'"), string);
        *++ket = '\0';
        return ket;
  }
@@@ -631,7 -587,7 +631,7 @@@ static int prepare_to_commit(const cha
                        struct commit *c;
                        c = lookup_commit_reference_by_name(squash_message);
                        if (!c)
-                               die("could not lookup commit %s", squash_message);
+                               die(_("could not lookup commit %s"), squash_message);
                        ctx.output_encoding = get_commit_output_encoding();
                        format_commit_message(c, "squash! %s\n\n", &sb,
                                              &ctx);
                hook_arg1 = "message";
        } else if (logfile && !strcmp(logfile, "-")) {
                if (isatty(0))
-                       fprintf(stderr, "(reading log message from standard input)\n");
+                       fprintf(stderr, _("(reading log message from standard input)\n"));
                if (strbuf_read(&sb, 0, 0) < 0)
-                       die_errno("could not read log from standard input");
+                       die_errno(_("could not read log from standard input"));
                hook_arg1 = "message";
        } else if (logfile) {
                if (strbuf_read_file(&sb, logfile, 0) < 0)
-                       die_errno("could not read log file '%s'",
+                       die_errno(_("could not read log file '%s'"),
                                  logfile);
                hook_arg1 = "message";
        } else if (use_message) {
                buffer = strstr(use_message_buffer, "\n\n");
                if (!buffer || buffer[2] == '\0')
-                       die("commit has empty message");
+                       die(_("commit has empty message"));
                strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
                hook_arg1 = "commit";
                hook_arg2 = use_message;
                struct commit *commit;
                commit = lookup_commit_reference_by_name(fixup_message);
                if (!commit)
-                       die("could not lookup commit %s", fixup_message);
+                       die(_("could not lookup commit %s"), fixup_message);
                ctx.output_encoding = get_commit_output_encoding();
                format_commit_message(commit, "fixup! %s\n\n",
                                      &sb, &ctx);
                hook_arg1 = "message";
        } else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
                if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
-                       die_errno("could not read MERGE_MSG");
+                       die_errno(_("could not read MERGE_MSG"));
                hook_arg1 = "merge";
        } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
                if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
-                       die_errno("could not read SQUASH_MSG");
+                       die_errno(_("could not read SQUASH_MSG"));
                hook_arg1 = "squash";
 -      } else if (template_file && !stat(template_file, &statbuf)) {
 +      } else if (template_file) {
                if (strbuf_read_file(&sb, template_file, 0) < 0)
-                       die_errno("could not read '%s'", template_file);
+                       die_errno(_("could not read '%s'"), template_file);
                hook_arg1 = "template";
        }
  
        /*
 -       * This final case does not modify the template message,
 -       * it just sets the argument to the prepare-commit-msg hook.
 +       * The remaining cases don't modify the template message, but
 +       * just set the argument(s) to the prepare-commit-msg hook.
         */
 -      else if (in_merge)
 +      else if (whence == FROM_MERGE)
                hook_arg1 = "merge";
 +      else if (whence == FROM_CHERRY_PICK) {
 +              hook_arg1 = "commit";
 +              hook_arg2 = "CHERRY_PICK_HEAD";
 +      }
  
        if (squash_message) {
                /*
  
        s->fp = fopen(git_path(commit_editmsg), "w");
        if (s->fp == NULL)
-               die_errno("could not open '%s'", git_path(commit_editmsg));
+               die_errno(_("could not open '%s'"), git_path(commit_editmsg));
  
        if (cleanup_mode != CLEANUP_NONE)
                stripspace(&sb, 0);
        }
  
        if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
-               die_errno("could not write commit template");
+               die_errno(_("could not write commit template"));
  
        strbuf_release(&sb);
  
        strbuf_addstr(&committer_ident, git_committer_info(0));
        if (use_editor && include_status) {
                char *ai_tmp, *ci_tmp;
 -              if (in_merge)
 +              if (whence != FROM_COMMIT)
                        status_printf_ln(s, GIT_COLOR_NORMAL,
-                               "\n"
+                               _("\n"
 -                              "It looks like you may be committing a MERGE.\n"
 +                              "It looks like you may be committing a %s.\n"
                                "If this is not correct, please remove the file\n"
                                "       %s\n"
                                "and try again.\n"
-                               "",
+                               ""),
 -                              git_path("MERGE_HEAD"));
 +                              whence_s(),
 +                              git_path(whence == FROM_MERGE
 +                                       ? "MERGE_HEAD"
 +                                       : "CHERRY_PICK_HEAD"));
  
                fprintf(s->fp, "\n");
                status_printf(s, GIT_COLOR_NORMAL,
-                       "Please enter the commit message for your changes.");
+                       _("Please enter the commit message for your changes."));
                if (cleanup_mode == CLEANUP_ALL)
                        status_printf_more(s, GIT_COLOR_NORMAL,
-                               " Lines starting\n"
+                               _(" Lines starting\n"
                                "with '#' will be ignored, and an empty"
-                               " message aborts the commit.\n");
+                               " message aborts the commit.\n"));
                else /* CLEANUP_SPACE, that is. */
                        status_printf_more(s, GIT_COLOR_NORMAL,
-                               " Lines starting\n"
+                               _(" Lines starting\n"
                                "with '#' will be kept; you may remove them"
                                " yourself if you want to.\n"
-                               "An empty message aborts the commit.\n");
+                               "An empty message aborts the commit.\n"));
                if (only_include_assumed)
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                                        "%s", only_include_assumed);
                ci_tmp = cut_ident_timestamp_part(committer_ident.buf);
                if (strcmp(author_ident->buf, committer_ident.buf))
                        status_printf_ln(s, GIT_COLOR_NORMAL,
-                               "%s"
-                               "Author:    %s",
+                               _("%s"
+                               "Author:    %s"),
                                ident_shown++ ? "" : "\n",
                                author_ident->buf);
  
                if (!user_ident_sufficiently_given())
                        status_printf_ln(s, GIT_COLOR_NORMAL,
-                               "%s"
-                               "Committer: %s",
+                               _("%s"
+                               "Committer: %s"),
                                ident_shown++ ? "" : "\n",
                                committer_ident.buf);
  
                const char *parent = "HEAD";
  
                if (!active_nr && read_cache() < 0)
-                       die("Cannot read index");
+                       die(_("Cannot read index"));
  
                if (amend)
                        parent = "HEAD^1";
  
        fclose(s->fp);
  
 -      if (!commitable && !in_merge && !allow_empty &&
 +      /*
 +       * Reject an attempt to record a non-merge empty commit without
 +       * explicit --allow-empty. In the cherry-pick case, it may be
 +       * empty due to conflict resolution, which the user should okay.
 +       */
 +      if (!commitable && whence != FROM_MERGE && !allow_empty &&
            !(amend && is_a_merge(head_sha1))) {
                run_status(stdout, index_file, prefix, 0, s);
                if (amend)
-                       fputs(empty_amend_advice, stderr);
+                       fputs(_(empty_amend_advice), stderr);
 +              else if (whence == FROM_CHERRY_PICK)
-                       fputs(empty_cherry_pick_advice, stderr);
++                      fputs(_(empty_cherry_pick_advice), stderr);
                return 0;
        }
  
                active_cache_tree = cache_tree();
        if (cache_tree_update(active_cache_tree,
                              active_cache, active_nr, 0, 0) < 0) {
-               error("Error building trees");
+               error(_("Error building trees"));
                return 0;
        }
  
                snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
                if (launch_editor(git_path(commit_editmsg), NULL, env)) {
                        fprintf(stderr,
-                       "Please supply the message using either -m or -F option.\n");
+                       _("Please supply the message using either -m or -F option.\n"));
                        exit(1);
                }
        }
@@@ -938,7 -880,7 +938,7 @@@ static const char *find_author_by_nickn
                format_commit_message(commit, "%an <%ae>", &buf, &ctx);
                return strbuf_detach(&buf, NULL);
        }
-       die("No existing author found with '%s'", name);
+       die(_("No existing author found with '%s'"), name);
  }
  
  
@@@ -953,31 -895,9 +953,31 @@@ static void handle_untracked_files_arg(
        else if (!strcmp(untracked_files_arg, "all"))
                s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
        else
-               die("Invalid untracked files mode '%s'", untracked_files_arg);
+               die(_("Invalid untracked files mode '%s'"), untracked_files_arg);
  }
  
-               die("could not lookup commit %s", name);
 +static const char *read_commit_message(const char *name)
 +{
 +      const char *out_enc, *out;
 +      struct commit *commit;
 +
 +      commit = lookup_commit_reference_by_name(name);
 +      if (!commit)
++              die(_("could not lookup commit %s"), name);
 +      out_enc = get_commit_output_encoding();
 +      out = logmsg_reencode(commit, out_enc);
 +
 +      /*
 +       * If we failed to reencode the buffer, just copy it
 +       * byte for byte so the user can try to fix it up.
 +       * This also handles the case where input and output
 +       * encodings are identical.
 +       */
 +      if (out == NULL)
 +              out = xstrdup(commit->buffer);
 +      return out;
 +}
 +
  static int parse_and_validate_options(int argc, const char *argv[],
                                      const char * const usage[],
                                      const char *prefix,
                force_author = find_author_by_nickname(force_author);
  
        if (force_author && renew_authorship)
-               die("Using both --reset-author and --author does not make sense");
+               die(_("Using both --reset-author and --author does not make sense"));
  
        if (logfile || message.len || use_message || fixup_message)
                use_editor = 0;
  
        /* Sanity check options */
        if (amend && initial_commit)
-               die("You have nothing to amend.");
+               die(_("You have nothing to amend."));
 -      if (amend && in_merge)
 -              die(_("You are in the middle of a merge -- cannot amend."));
 +      if (amend && whence != FROM_COMMIT)
-               die("You are in the middle of a %s -- cannot amend.", whence_s());
++              die(_("You are in the middle of a %s -- cannot amend."), whence_s());
        if (fixup_message && squash_message)
-               die("Options --squash and --fixup cannot be used together");
+               die(_("Options --squash and --fixup cannot be used together"));
        if (use_message)
                f++;
        if (edit_message)
        if (logfile)
                f++;
        if (f > 1)
-               die("Only one of -c/-C/-F/--fixup can be used.");
+               die(_("Only one of -c/-C/-F/--fixup can be used."));
        if (message.len && f > 0)
-               die("Option -m cannot be combined with -c/-C/-F/--fixup.");
+               die((_("Option -m cannot be combined with -c/-C/-F/--fixup.")));
        if (edit_message)
                use_message = edit_message;
        if (amend && !use_message && !fixup_message)
                use_message = "HEAD";
 -      if (!use_message && renew_authorship)
 +      if (!use_message && whence != FROM_CHERRY_PICK && renew_authorship)
-               die("--reset-author can be used only with -C, -c or --amend.");
+               die(_("--reset-author can be used only with -C, -c or --amend."));
        if (use_message) {
 -              const char *out_enc;
 -              struct commit *commit;
 -
 -              commit = lookup_commit_reference_by_name(use_message);
 -              if (!commit)
 -                      die(_("could not lookup commit %s"), use_message);
 -              out_enc = get_commit_output_encoding();
 -              use_message_buffer = logmsg_reencode(commit, out_enc);
 -
 -              /*
 -               * If we failed to reencode the buffer, just copy it
 -               * byte for byte so the user can try to fix it up.
 -               * This also handles the case where input and output
 -               * encodings are identical.
 -               */
 -              if (use_message_buffer == NULL)
 -                      use_message_buffer = xstrdup(commit->buffer);
 +              use_message_buffer = read_commit_message(use_message);
 +              if (!renew_authorship) {
 +                      author_message = use_message;
 +                      author_message_buffer = use_message_buffer;
 +              }
 +      }
 +      if (whence == FROM_CHERRY_PICK && !renew_authorship) {
 +              author_message = "CHERRY_PICK_HEAD";
 +              author_message_buffer = read_commit_message(author_message);
        }
  
        if (!!also + !!only + !!all + !!interactive > 1)
-               die("Only one of --include/--only/--all/--interactive can be used.");
+               die(_("Only one of --include/--only/--all/--interactive can be used."));
        if (argc == 0 && (also || (only && !amend)))
-               die("No paths with --include/--only does not make sense.");
+               die(_("No paths with --include/--only does not make sense."));
        if (argc == 0 && only && amend)
-               only_include_assumed = "Clever... amending the last one with dirty index.";
+               only_include_assumed = _("Clever... amending the last one with dirty index.");
        if (argc > 0 && !also && !only)
-               only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
+               only_include_assumed = _("Explicit paths specified without -i nor -o; assuming --only paths...");
        if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
                cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE;
        else if (!strcmp(cleanup_arg, "verbatim"))
        else if (!strcmp(cleanup_arg, "strip"))
                cleanup_mode = CLEANUP_ALL;
        else
-               die("Invalid cleanup mode %s", cleanup_arg);
+               die(_("Invalid cleanup mode %s"), cleanup_arg);
  
        handle_untracked_files_arg(s);
  
        if (all && argc > 0)
-               die("Paths with -a does not make sense.");
+               die(_("Paths with -a does not make sense."));
        else if (interactive && argc > 0)
-               die("Paths with --interactive does not make sense.");
+               die(_("Paths with --interactive does not make sense."));
  
        if (null_termination && status_format == STATUS_FORMAT_LONG)
                status_format = STATUS_FORMAT_PORCELAIN;
@@@ -1146,7 -1074,7 +1146,7 @@@ static int git_status_config(const cha
                else if (!strcmp(v, "all"))
                        s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
                else
-                       return error("Invalid untracked files mode '%s'", v);
+                       return error(_("Invalid untracked files mode '%s'"), v);
                return 0;
        }
        return git_diff_ui_config(k, v, NULL);
@@@ -1189,7 -1117,7 +1189,7 @@@ int cmd_status(int argc, const char **a
        wt_status_prepare(&s);
        gitmodules_config();
        git_config(git_status_config, &s);
 -      in_merge = file_exists(git_path("MERGE_HEAD"));
 +      determine_whence(&s);
        argc = parse_options(argc, argv, prefix,
                             builtin_status_options,
                             builtin_status_usage, 0);
        refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL);
  
        fd = hold_locked_index(&index_lock, 0);
 -      if (0 <= fd) {
 -              if (active_cache_changed &&
 -                  !write_cache(fd, active_cache, active_nr))
 -                      commit_locked_index(&index_lock);
 -              else
 -                      rollback_lock_file(&index_lock);
 -      }
 +      if (0 <= fd)
 +              update_index_if_able(&the_index, &index_lock);
  
        s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
 -      s.in_merge = in_merge;
        s.ignore_submodule_arg = ignore_submodule_arg;
        wt_status_collect(&s);
  
@@@ -1246,9 -1180,9 +1246,9 @@@ static void print_summary(const char *p
  
        commit = lookup_commit(sha1);
        if (!commit)
-               die("couldn't look up newly created commit");
+               die(_("couldn't look up newly created commit"));
        if (!commit || parse_commit(commit))
-               die("could not parse newly created commit");
+               die(_("could not parse newly created commit"));
  
        strbuf_addstr(&format, "format:%h] %s");
  
                strbuf_addbuf_percentquote(&format, &committer_ident);
                if (advice_implicit_identity) {
                        strbuf_addch(&format, '\n');
-                       strbuf_addstr(&format, implicit_ident_advice);
+                       strbuf_addstr(&format, _(implicit_ident_advice));
                }
        }
        strbuf_release(&author_ident);
        get_commit_format(format.buf, &rev);
        rev.always_show_header = 0;
        rev.diffopt.detect_rename = 1;
 -      rev.diffopt.rename_limit = 100;
        rev.diffopt.break_opt = 0;
        diff_setup_done(&rev.diffopt);
  
                !prefixcmp(head, "refs/heads/") ?
                        head + 11 :
                        !strcmp(head, "HEAD") ?
-                               "detached HEAD" :
+                               _("detached HEAD") :
                                head,
-               initial_commit ? " (root-commit)" : "");
+               initial_commit ? _(" (root-commit)") : "");
  
        if (!log_tree_commit(&rev, commit)) {
                rev.always_show_header = 1;
@@@ -1367,7 -1302,8 +1367,7 @@@ int cmd_commit(int argc, const char **a
  
        wt_status_prepare(&s);
        git_config(git_commit_config, &s);
 -      in_merge = file_exists(git_path("MERGE_HEAD"));
 -      s.in_merge = in_merge;
 +      determine_whence(&s);
  
        if (s.use_color == -1)
                s.use_color = git_use_color_default;
                        reflog_msg = "commit (amend)";
                commit = lookup_commit(head_sha1);
                if (!commit || parse_commit(commit))
-                       die("could not parse HEAD commit");
+                       die(_("could not parse HEAD commit"));
  
                for (c = commit->parents; c; c = c->next)
                        pptr = &commit_list_insert(c->item, pptr)->next;
 -      } else if (in_merge) {
 +      } else if (whence == FROM_MERGE) {
                struct strbuf m = STRBUF_INIT;
                FILE *fp;
  
                pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
                fp = fopen(git_path("MERGE_HEAD"), "r");
                if (fp == NULL)
-                       die_errno("could not open '%s' for reading",
+                       die_errno(_("could not open '%s' for reading"),
                                  git_path("MERGE_HEAD"));
                while (strbuf_getline(&m, fp, '\n') != EOF) {
                        unsigned char sha1[20];
                        if (get_sha1_hex(m.buf, sha1) < 0)
-                               die("Corrupt MERGE_HEAD file (%s)", m.buf);
+                               die(_("Corrupt MERGE_HEAD file (%s)"), m.buf);
                        pptr = &commit_list_insert(lookup_commit(sha1), pptr)->next;
                }
                fclose(fp);
                strbuf_release(&m);
                if (!stat(git_path("MERGE_MODE"), &statbuf)) {
                        if (strbuf_read_file(&sb, git_path("MERGE_MODE"), 0) < 0)
-                               die_errno("could not read MERGE_MODE");
+                               die_errno(_("could not read MERGE_MODE"));
                        if (!strcmp(sb.buf, "no-ff"))
                                allow_fast_forward = 0;
                }
                        parents = reduce_heads(parents);
        } else {
                if (!reflog_msg)
 -                      reflog_msg = "commit";
 +                      reflog_msg = (whence == FROM_CHERRY_PICK)
 +                                      ? "commit (cherry-pick)"
 +                                      : "commit";
                pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
        }
  
        if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
                int saved_errno = errno;
                rollback_index_files();
-               die("could not read commit message: %s", strerror(saved_errno));
+               die(_("could not read commit message: %s"), strerror(saved_errno));
        }
  
        /* Truncate the message just before the diff, if any. */
                stripspace(&sb, cleanup_mode == CLEANUP_ALL);
        if (message_is_empty(&sb) && !allow_empty_message) {
                rollback_index_files();
-               fprintf(stderr, "Aborting commit due to empty commit message.\n");
+               fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
                exit(1);
        }
  
        if (commit_tree(sb.buf, active_cache_tree->sha1, parents, commit_sha1,
                        author_ident.buf)) {
                rollback_index_files();
-               die("failed to write commit object");
+               die(_("failed to write commit object"));
        }
        strbuf_release(&author_ident);
  
  
        if (!ref_lock) {
                rollback_index_files();
-               die("cannot lock HEAD ref");
+               die(_("cannot lock HEAD ref"));
        }
        if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0) {
                rollback_index_files();
-               die("cannot update HEAD ref");
+               die(_("cannot update HEAD ref"));
        }
  
 +      unlink(git_path("CHERRY_PICK_HEAD"));
        unlink(git_path("MERGE_HEAD"));
        unlink(git_path("MERGE_MSG"));
        unlink(git_path("MERGE_MODE"));
        unlink(git_path("SQUASH_MSG"));
  
        if (commit_index_files())
-               die ("Repository has been updated, but unable to write\n"
+               die (_("Repository has been updated, but unable to write\n"
                     "new_index file. Check that disk is not full or quota is\n"
-                    "not exceeded, and then \"git reset HEAD\" to recover.");
+                    "not exceeded, and then \"git reset HEAD\" to recover."));
  
        rerere(0);
        run_hook(get_index_file(), "post-commit", NULL);
diff --combined builtin/describe.c
index 4afd1504a666d670ec71bdbd61b09bc0530ed04b,037691e3d30ef2c6b80b23fa0fbcad67759560e2..66fc291c8a81de71dee7b597c9ab0dc9d70e8e29
@@@ -21,7 -21,7 +21,7 @@@ static int debug;     /* Display lots of ve
  static int all;       /* Any valid ref can be used */
  static int tags;      /* Allow lightweight tags */
  static int longformat;
 -static int abbrev = DEFAULT_ABBREV;
 +static int abbrev = -1; /* unspecified */
  static int max_candidates = 10;
  static struct hash_table names;
  static int have_util;
@@@ -63,7 -63,7 +63,7 @@@ static inline struct commit_name *find_
        return n;
  }
  
 -static int set_util(void *chain)
 +static int set_util(void *chain, void *data)
  {
        struct commit_name *n;
        for (n = chain; n; n = n->next) {
@@@ -231,13 -231,13 +231,13 @@@ static void display_name(struct commit_
        if (n->prio == 2 && !n->tag) {
                n->tag = lookup_tag(n->sha1);
                if (!n->tag || parse_tag(n->tag))
-                       die("annotated tag %s not available", n->path);
+                       die(_("annotated tag %s not available"), n->path);
        }
        if (n->tag && !n->name_checked) {
                if (!n->tag->tag)
-                       die("annotated tag %s has no embedded name", n->path);
+                       die(_("annotated tag %s has no embedded name"), n->path);
                if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
-                       warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
+                       warning(_("tag '%s' is really '%s' here"), n->tag->tag, n->path);
                n->name_checked = 1;
        }
  
@@@ -264,10 -264,10 +264,10 @@@ static void describe(const char *arg, i
        unsigned int unannotated_cnt = 0;
  
        if (get_sha1(arg, sha1))
-               die("Not a valid object name %s", arg);
+               die(_("Not a valid object name %s"), arg);
        cmit = lookup_commit_reference(sha1);
        if (!cmit)
-               die("%s is not a valid '%s' object", arg, commit_type);
+               die(_("%s is not a valid '%s' object"), arg, commit_type);
  
        n = find_commit_name(cmit->object.sha1);
        if (n && (tags || all || n->prio == 2)) {
        }
  
        if (!max_candidates)
-               die("no tag exactly matches '%s'", sha1_to_hex(cmit->object.sha1));
+               die(_("no tag exactly matches '%s'"), sha1_to_hex(cmit->object.sha1));
        if (debug)
-               fprintf(stderr, "searching to describe %s\n", arg);
+               fprintf(stderr, _("searching to describe %s\n"), arg);
  
        if (!have_util) {
 -              for_each_hash(&names, set_util);
 +              for_each_hash(&names, set_util, NULL);
                have_util = 1;
        }
  
                }
                if (annotated_cnt && !list) {
                        if (debug)
-                               fprintf(stderr, "finished search at %s\n",
+                               fprintf(stderr, _("finished search at %s\n"),
                                        sha1_to_hex(c->object.sha1));
                        break;
                }
                        return;
                }
                if (unannotated_cnt)
-                       die("No annotated tags can describe '%s'.\n"
-                           "However, there were unannotated tags: try --tags.",
+                       die(_("No annotated tags can describe '%s'.\n"
+                           "However, there were unannotated tags: try --tags."),
                            sha1_to_hex(sha1));
                else
-                       die("No tags can describe '%s'.\n"
-                           "Try --always, or create some tags.",
+                       die(_("No tags can describe '%s'.\n"
+                           "Try --always, or create some tags."),
                            sha1_to_hex(sha1));
        }
  
                                prio_names[t->name->prio],
                                t->depth, t->name->path);
                }
-               fprintf(stderr, "traversed %lu commits\n", seen_commits);
+               fprintf(stderr, _("traversed %lu commits\n"), seen_commits);
                if (gave_up_on) {
                        fprintf(stderr,
-                               "more than %i tags found; listed %i most recent\n"
-                               "gave up search at %s\n",
+                               _("more than %i tags found; listed %i most recent\n"
+                               "gave up search at %s\n"),
                                max_candidates, max_candidates,
                                sha1_to_hex(gave_up_on->object.sha1));
                }
@@@ -420,11 -420,7 +420,11 @@@ int cmd_describe(int argc, const char *
                OPT_END(),
        };
  
 +      git_config(git_default_config, NULL);
        argc = parse_options(argc, argv, prefix, options, describe_usage, 0);
 +      if (abbrev < 0)
 +              abbrev = DEFAULT_ABBREV;
 +
        if (max_candidates < 0)
                max_candidates = 0;
        else if (max_candidates > MAX_TAGS)
        save_commit_buffer = 0;
  
        if (longformat && abbrev == 0)
-               die("--long is incompatible with --abbrev=0");
+               die(_("--long is incompatible with --abbrev=0"));
  
        if (contains) {
                const char **args = xmalloc((7 + argc) * sizeof(char *));
        init_hash(&names);
        for_each_rawref(get_name, NULL);
        if (!names.nr && !always)
-               die("No names found, cannot describe anything.");
+               die(_("No names found, cannot describe anything."));
  
        if (argc == 0) {
                if (dirty && !cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1, diff_index_args, prefix))
                        dirty = NULL;
                describe("HEAD", 1);
        } else if (dirty) {
-               die("--dirty is incompatible with committishes");
+               die(_("--dirty is incompatible with committishes"));
        } else {
                while (argc-- > 0) {
                        describe(*argv++, argc == 0);
diff --combined builtin/diff.c
index 655a013ed05edd369225aa9ee9f39f347d687172,00342730b651c89d38e3f8af14f350a1077ffde2..717fa1a3414e18cbdd4c6eb1e0785761687688d7
@@@ -71,9 -71,9 +71,9 @@@ static int builtin_diff_b_f(struct rev_
                usage(builtin_diff_usage);
  
        if (lstat(path, &st))
-               die_errno("failed to stat '%s'", path);
+               die_errno(_("failed to stat '%s'"), path);
        if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
-               die("'%s': not a regular file or symlink", path);
+               die(_("'%s': not a regular file or symlink"), path);
  
        diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/");
  
@@@ -135,7 -135,7 +135,7 @@@ static int builtin_diff_index(struct re
            revs->max_count != -1 || revs->min_age != -1 ||
            revs->max_age != -1)
                usage(builtin_diff_usage);
 -      if (read_cache_preload(revs->diffopt.paths) < 0) {
 +      if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
                perror("read_cache_preload");
                return -1;
        }
@@@ -197,7 -197,12 +197,7 @@@ static void refresh_index_quietly(void
        discard_cache();
        read_cache();
        refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
 -
 -      if (active_cache_changed &&
 -          !write_cache(fd, active_cache, active_nr))
 -              commit_locked_index(lock_file);
 -
 -      rollback_lock_file(lock_file);
 +      update_index_if_able(&the_index, lock_file);
  }
  
  static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
                else if (!strcmp(argv[1], "-h"))
                        usage(builtin_diff_usage);
                else
-                       return error("invalid option: %s", argv[1]);
+                       return error(_("invalid option: %s"), argv[1]);
                argv++; argc--;
        }
  
                revs->combine_merges = revs->dense_combined_merges = 1;
  
        setup_work_tree();
 -      if (read_cache_preload(revs->diffopt.paths) < 0) {
 +      if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
                perror("read_cache_preload");
                return -1;
        }
@@@ -294,12 -299,12 +294,12 @@@ int cmd_diff(int argc, const char **arg
        DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
  
        if (nongit)
-               die("Not a git repository");
+               die(_("Not a git repository"));
        argc = setup_revisions(argc, argv, &rev, NULL);
        if (!rev.diffopt.output_format) {
                rev.diffopt.output_format = DIFF_FORMAT_PATCH;
                if (diff_setup_done(&rev.diffopt) < 0)
-                       die("diff_setup_done failed");
+                       die(_("diff_setup_done failed"));
        }
  
        DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
                        obj = parse_object(obj->sha1);
                obj = deref_tag(obj, NULL, 0);
                if (!obj)
-                       die("invalid object '%s' given.", name);
+                       die(_("invalid object '%s' given."), name);
                if (obj->type == OBJ_COMMIT)
                        obj = &((struct commit *)obj)->tree->object;
                if (obj->type == OBJ_TREE) {
                        if (ARRAY_SIZE(ent) <= ents)
-                               die("more than %d trees given: '%s'",
+                               die(_("more than %d trees given: '%s'"),
                                    (int) ARRAY_SIZE(ent), name);
                        obj->flags |= flags;
                        ent[ents].item = obj;
                }
                if (obj->type == OBJ_BLOB) {
                        if (2 <= blobs)
-                               die("more than two blobs given: '%s'", name);
+                               die(_("more than two blobs given: '%s'"), name);
                        hashcpy(blob[blobs].sha1, obj->sha1);
                        blob[blobs].name = name;
                        blob[blobs].mode = list->mode;
                        continue;
  
                }
-               die("unhandled object '%s' given.", name);
+               die(_("unhandled object '%s' given."), name);
        }
 -      if (rev.prune_data) {
 -              const char **pathspec = rev.prune_data;
 -              while (*pathspec) {
 -                      if (!path)
 -                              path = *pathspec;
 -                      paths++;
 -                      pathspec++;
 -              }
 +      if (rev.prune_data.nr) {
 +              if (!path)
 +                      path = rev.prune_data.items[0].match;
 +              paths += rev.prune_data.nr;
        }
  
        /*
diff --combined builtin/fetch.c
index 1b6d4be00207576f612b8d2cf1f5979656a63da7,ee2c5f50ac2aaae60b3faedbaf7946d696cbb13b..6cbb5f69ecf0946f4028b88563347332d54f65bc
@@@ -49,7 -49,7 +49,7 @@@ static struct option builtin_fetch_opti
                    "fetch from all remotes"),
        OPT_BOOLEAN('a', "append", &append,
                    "append to .git/FETCH_HEAD instead of overwriting"),
 -      OPT_STRING(0, "upload-pack", &upload_pack, "PATH",
 +      OPT_STRING(0, "upload-pack", &upload_pack, "path",
                   "path to upload pack on remote end"),
        OPT__FORCE(&force, "force overwrite of local branch"),
        OPT_BOOLEAN('m', "multiple", &multiple,
@@@ -69,9 -69,9 +69,9 @@@
        OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
                    "allow updating of HEAD ref"),
        OPT_BOOLEAN(0, "progress", &progress, "force progress reporting"),
 -      OPT_STRING(0, "depth", &depth, "DEPTH",
 +      OPT_STRING(0, "depth", &depth, "depth",
                   "deepen history of shallow clone"),
 -      { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "DIR",
 +      { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "dir",
                   "prepend this to submodule path output", PARSE_OPT_HIDDEN },
        OPT_END()
  };
@@@ -184,7 -184,7 +184,7 @@@ static struct ref *get_ref_map(struct t
                } else {
                        ref_map = get_remote_ref(remote_refs, "HEAD");
                        if (!ref_map)
-                               die("Couldn't find remote ref HEAD");
+                               die(_("Couldn't find remote ref HEAD"));
                        ref_map->merge = 1;
                        tail = &ref_map->next;
                }
@@@ -237,12 -237,12 +237,12 @@@ static int update_local_ref(struct ref 
        *display = 0;
        type = sha1_object_info(ref->new_sha1, NULL);
        if (type < 0)
-               die("object %s not found", sha1_to_hex(ref->new_sha1));
+               die(_("object %s not found"), sha1_to_hex(ref->new_sha1));
  
        if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
                if (verbosity > 0)
                        sprintf(display, "= %-*s %-*s -> %s", TRANSPORT_SUMMARY_WIDTH,
-                               "[up to date]", REFCOL_WIDTH, remote,
+                               _("[up to date]"), REFCOL_WIDTH, remote,
                                pretty_ref);
                return 0;
        }
                 * If this is the head, and it's not okay to update
                 * the head, and the old value of the head isn't empty...
                 */
-               sprintf(display, "! %-*s %-*s -> %s  (can't fetch in current branch)",
-                       TRANSPORT_SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
+               sprintf(display, _("! %-*s %-*s -> %s  (can't fetch in current branch)"),
+                       TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), REFCOL_WIDTH, remote,
                        pretty_ref);
                return 1;
        }
                int r;
                r = s_update_ref("updating tag", ref, 0);
                sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-',
-                       TRANSPORT_SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote,
-                       pretty_ref, r ? "  (unable to update local ref)" : "");
+                       TRANSPORT_SUMMARY_WIDTH, _("[tag update]"), REFCOL_WIDTH, remote,
+                       pretty_ref, r ? _("  (unable to update local ref)") : "");
                return r;
        }
  
                int r;
                if (!strncmp(ref->name, "refs/tags/", 10)) {
                        msg = "storing tag";
-                       what = "[new tag]";
+                       what = _("[new tag]");
                }
                else {
                        msg = "storing head";
-                       what = "[new branch]";
+                       what = _("[new branch]");
                }
  
                r = s_update_ref(msg, ref, 0);
                sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*',
                        TRANSPORT_SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref,
-                       r ? "  (unable to update local ref)" : "");
+                       r ? _("  (unable to update local ref)") : "");
                return r;
        }
  
                r = s_update_ref("fast-forward", ref, 1);
                sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ',
                        TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
-                       pretty_ref, r ? "  (unable to update local ref)" : "");
+                       pretty_ref, r ? _("  (unable to update local ref)") : "");
                return r;
        } else if (force || ref->force) {
                char quickref[84];
                sprintf(display, "%c %-*s %-*s -> %s  (%s)", r ? '!' : '+',
                        TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
                        pretty_ref,
-                       r ? "unable to update local ref" : "forced update");
+                       r ? _("unable to update local ref") : _("forced update"));
                return r;
        } else {
-               sprintf(display, "! %-*s %-*s -> %s  (non-fast-forward)",
-                       TRANSPORT_SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
-                       pretty_ref);
+               sprintf(display, "! %-*s %-*s -> %s  %s",
+                       TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), REFCOL_WIDTH, remote,
+                       pretty_ref, _("(non-fast-forward)"));
                return 1;
        }
  }
@@@ -337,7 -337,7 +337,7 @@@ static int store_updated_refs(const cha
  
        fp = fopen(filename, "a");
        if (!fp)
-               return error("cannot open %s: %s\n", filename, strerror(errno));
+               return error(_("cannot open %s: %s\n"), filename, strerror(errno));
  
        if (raw_url)
                url = transport_anonymize_url(raw_url);
                                 REFCOL_WIDTH, *what ? what : "HEAD");
                if (*note) {
                        if (verbosity >= 0 && !shown_url) {
-                               fprintf(stderr, "From %.*s\n",
+                               fprintf(stderr, _("From %.*s\n"),
                                                url_len, url);
                                shown_url = 1;
                        }
        free(url);
        fclose(fp);
        if (rc & STORE_REF_ERROR_DF_CONFLICT)
-               error("some local refs could not be updated; try running\n"
+               error(_("some local refs could not be updated; try running\n"
                      " 'git remote prune %s' to remove any old, conflicting "
-                     "branches", remote_name);
+                     "branches"), remote_name);
        return rc;
  }
  
@@@ -476,7 -476,7 +476,7 @@@ static int quickfetch(struct ref *ref_m
  
        err = start_command(&revlist);
        if (err) {
-               error("could not run rev-list");
+               error(_("could not run rev-list"));
                return err;
        }
  
                if (write_in_full(revlist.in, sha1_to_hex(ref->old_sha1), 40) < 0 ||
                    write_str_in_full(revlist.in, "\n") < 0) {
                        if (errno != EPIPE && errno != EINVAL)
-                               error("failed write to rev-list: %s", strerror(errno));
+                               error(_("failed write to rev-list: %s"), strerror(errno));
                        err = -1;
                        break;
                }
        }
  
        if (close(revlist.in)) {
-               error("failed to close rev-list's stdin: %s", strerror(errno));
+               error(_("failed to close rev-list's stdin: %s"), strerror(errno));
                err = -1;
        }
  
@@@ -524,16 -524,16 +524,16 @@@ static int prune_refs(struct transport 
        int result = 0;
        struct ref *ref, *stale_refs = get_stale_heads(transport->remote, ref_map);
        const char *dangling_msg = dry_run
-               ? "   (%s will become dangling)\n"
-               : "   (%s has become dangling)\n";
+               ? _("   (%s will become dangling)\n")
+               : _("   (%s has become dangling)\n");
  
        for (ref = stale_refs; ref; ref = ref->next) {
                if (!dry_run)
                        result |= delete_ref(ref->name, NULL, 0);
                if (verbosity >= 0) {
                        fprintf(stderr, " x %-*s %-*s -> %s\n",
-                               TRANSPORT_SUMMARY_WIDTH, "[deleted]",
-                               REFCOL_WIDTH, "(none)", prettify_refname(ref->name));
+                               TRANSPORT_SUMMARY_WIDTH, _("[deleted]"),
+                               REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name));
                        warn_dangling_symref(stderr, dangling_msg, ref->name);
                }
        }
@@@ -650,8 -650,8 +650,8 @@@ static void check_not_current_branch(st
        for (; ref_map; ref_map = ref_map->next)
                if (ref_map->peer_ref && !strcmp(current_branch->refname,
                                        ref_map->peer_ref->name))
-                       die("Refusing to fetch into current branch %s "
-                           "of non-bare repository", current_branch->refname);
+                       die(_("Refusing to fetch into current branch %s "
+                           "of non-bare repository"), current_branch->refname);
  }
  
  static int truncate_fetch_head(void)
        FILE *fp = fopen(filename, "w");
  
        if (!fp)
-               return error("cannot open %s: %s\n", filename, strerror(errno));
+               return error(_("cannot open %s: %s\n"), filename, strerror(errno));
        fclose(fp);
        return 0;
  }
@@@ -684,7 -684,7 +684,7 @@@ static int do_fetch(struct transport *t
        }
  
        if (!transport->get_refs_list || !transport->fetch)
-               die("Don't know how to fetch from %s", transport->url);
+               die(_("Don't know how to fetch from %s"), transport->url);
  
        /* if not appending, truncate FETCH_HEAD */
        if (!append && !dry_run) {
@@@ -738,10 -738,10 +738,10 @@@ static void set_option(const char *name
  {
        int r = transport_set_option(transport, name, value);
        if (r < 0)
-               die("Option \"%s\" value \"%s\" is not valid for %s",
+               die(_("Option \"%s\" value \"%s\" is not valid for %s"),
                        name, value, transport->url);
        if (r > 0)
-               warning("Option \"%s\" is ignored for %s\n",
+               warning(_("Option \"%s\" is ignored for %s\n"),
                        name, transport->url);
  }
  
@@@ -838,9 -838,9 +838,9 @@@ static int fetch_multiple(struct string
                argv[argc] = name;
                argv[argc + 1] = NULL;
                if (verbosity >= 0)
-                       printf("Fetching %s\n", name);
+                       printf(_("Fetching %s\n"), name);
                if (run_command_v_opt(argv, RUN_GIT_CMD)) {
-                       error("Could not fetch %s", name);
+                       error(_("Could not fetch %s"), name);
                        result = 1;
                }
        }
@@@ -856,8 -856,8 +856,8 @@@ static int fetch_one(struct remote *rem
        int exit_code;
  
        if (!remote)
-               die("No remote repository specified.  Please, specify either a URL or a\n"
-                   "remote name from which new revisions should be fetched.");
+               die(_("No remote repository specified.  Please, specify either a URL or a\n"
+                   "remote name from which new revisions should be fetched."));
  
        transport = transport_get(remote, NULL);
        transport_set_verbosity(transport, verbosity, progress);
                                char *ref;
                                i++;
                                if (i >= argc)
-                                       die("You need to specify a tag name.");
+                                       die(_("You need to specify a tag name."));
                                ref = xmalloc(strlen(argv[i]) * 2 + 22);
                                strcpy(ref, "refs/tags/");
                                strcat(ref, argv[i]);
@@@ -906,8 -906,6 +906,8 @@@ int cmd_fetch(int argc, const char **ar
        struct remote *remote;
        int result = 0;
  
 +      packet_trace_identity("fetch");
 +
        /* Record the command line for the reflog */
        strbuf_addstr(&default_rla, "fetch");
        for (i = 1; i < argc; i++)
  
        if (all) {
                if (argc == 1)
-                       die("fetch --all does not take a repository argument");
+                       die(_("fetch --all does not take a repository argument"));
                else if (argc > 1)
-                       die("fetch --all does not make sense with refspecs");
+                       die(_("fetch --all does not make sense with refspecs"));
                (void) for_each_remote(get_one_remote_for_fetch, &list);
                result = fetch_multiple(&list);
        } else if (argc == 0) {
                /* All arguments are assumed to be remotes or groups */
                for (i = 0; i < argc; i++)
                        if (!add_remote_or_group(argv[i], &list))
-                               die("No such remote or remote group: %s", argv[i]);
+                               die(_("No such remote or remote group: %s"), argv[i]);
                result = fetch_multiple(&list);
        } else {
                /* Single remote or group */
                if (list.nr > 1) {
                        /* More than one remote */
                        if (argc > 1)
-                               die("Fetching a group and specifying refspecs does not make sense");
+                               die(_("Fetching a group and specifying refspecs does not make sense"));
                        result = fetch_multiple(&list);
                } else {
                        /* Zero or one remotes */
diff --combined builtin/grep.c
index 85e9583a1335330f8e852d7937abb10c97798bc0,dfc32fbe6f87cb2959098640d583990552815607..5b8f30d3ed472bb74f1b992b5098a08f5d5377a1
@@@ -40,7 -40,8 +40,7 @@@ enum work_type {WORK_SHA1, WORK_FILE}
   * threads. The producer adds struct work_items to 'todo' and the
   * consumers pick work items from the same array.
   */
 -struct work_item
 -{
 +struct work_item {
        enum work_type type;
        char *name;
  
@@@ -244,7 -245,7 +244,7 @@@ static void start_threads(struct grep_o
                err = pthread_create(&threads[i], NULL, run, o);
  
                if (err)
-                       die("grep: failed to create thread: %s",
+                       die(_("grep: failed to create thread: %s"),
                            strerror(err));
        }
  }
@@@ -328,6 -329,106 +328,6 @@@ static int grep_config(const char *var
        return 0;
  }
  
 -/*
 - * Return non-zero if max_depth is negative or path has no more then max_depth
 - * slashes.
 - */
 -static int accept_subdir(const char *path, int max_depth)
 -{
 -      if (max_depth < 0)
 -              return 1;
 -
 -      while ((path = strchr(path, '/')) != NULL) {
 -              max_depth--;
 -              if (max_depth < 0)
 -                      return 0;
 -              path++;
 -      }
 -      return 1;
 -}
 -
 -/*
 - * Return non-zero if name is a subdirectory of match and is not too deep.
 - */
 -static int is_subdir(const char *name, int namelen,
 -              const char *match, int matchlen, int max_depth)
 -{
 -      if (matchlen > namelen || strncmp(name, match, matchlen))
 -              return 0;
 -
 -      if (name[matchlen] == '\0') /* exact match */
 -              return 1;
 -
 -      if (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/')
 -              return accept_subdir(name + matchlen + 1, max_depth);
 -
 -      return 0;
 -}
 -
 -/*
 - * git grep pathspecs are somewhat different from diff-tree pathspecs;
 - * pathname wildcards are allowed.
 - */
 -static int pathspec_matches(const char **paths, const char *name, int max_depth)
 -{
 -      int namelen, i;
 -      if (!paths || !*paths)
 -              return accept_subdir(name, max_depth);
 -      namelen = strlen(name);
 -      for (i = 0; paths[i]; i++) {
 -              const char *match = paths[i];
 -              int matchlen = strlen(match);
 -              const char *cp, *meta;
 -
 -              if (is_subdir(name, namelen, match, matchlen, max_depth))
 -                      return 1;
 -              if (!fnmatch(match, name, 0))
 -                      return 1;
 -              if (name[namelen-1] != '/')
 -                      continue;
 -
 -              /* We are being asked if the directory ("name") is worth
 -               * descending into.
 -               *
 -               * Find the longest leading directory name that does
 -               * not have metacharacter in the pathspec; the name
 -               * we are looking at must overlap with that directory.
 -               */
 -              for (cp = match, meta = NULL; cp - match < matchlen; cp++) {
 -                      char ch = *cp;
 -                      if (ch == '*' || ch == '[' || ch == '?') {
 -                              meta = cp;
 -                              break;
 -                      }
 -              }
 -              if (!meta)
 -                      meta = cp; /* fully literal */
 -
 -              if (namelen <= meta - match) {
 -                      /* Looking at "Documentation/" and
 -                       * the pattern says "Documentation/howto/", or
 -                       * "Documentation/diff*.txt".  The name we
 -                       * have should match prefix.
 -                       */
 -                      if (!memcmp(match, name, namelen))
 -                              return 1;
 -                      continue;
 -              }
 -
 -              if (meta - match < namelen) {
 -                      /* Looking at "Documentation/howto/" and
 -                       * the pattern says "Documentation/h*";
 -                       * match up to "Do.../h"; this avoids descending
 -                       * into "Documentation/technical/".
 -                       */
 -                      if (!memcmp(match, name, meta - match))
 -                              return 1;
 -                      continue;
 -              }
 -      }
 -      return 0;
 -}
 -
  static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
  {
        void *data;
@@@ -349,7 -450,7 +349,7 @@@ static void *load_sha1(const unsigned c
        void *data = lock_and_read_sha1_file(sha1, &type, size);
  
        if (!data)
-               error("'%s': unable to read %s", name, sha1_to_hex(sha1));
+               error(_("'%s': unable to read %s"), name, sha1_to_hex(sha1));
  
        return data;
  }
@@@ -400,7 -501,7 +400,7 @@@ static void *load_file(const char *file
        if (lstat(filename, &st) < 0) {
        err_ret:
                if (errno != ENOENT)
-                       error("'%s': %s", filename, strerror(errno));
+                       error(_("'%s': %s"), filename, strerror(errno));
                return 0;
        }
        if (!S_ISREG(st.st_mode))
                goto err_ret;
        data = xmalloc(*sz + 1);
        if (st.st_size != read_in_full(i, data, *sz)) {
-               error("'%s': short read %s", filename, strerror(errno));
+               error(_("'%s': short read %s"), filename, strerror(errno));
                close(i);
                free(data);
                return 0;
@@@ -473,14 -574,14 +473,14 @@@ static void run_pager(struct grep_opt *
        argv[path_list->nr] = NULL;
  
        if (prefix && chdir(prefix))
-               die("Failed to chdir: %s", prefix);
+               die(_("Failed to chdir: %s"), prefix);
        status = run_command_v_opt(argv, RUN_USING_SHELL);
        if (status)
                exit(status);
        free(argv);
  }
  
 -static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 +static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)
  {
        int hit = 0;
        int nr;
                struct cache_entry *ce = active_cache[nr];
                if (!S_ISREG(ce->ce_mode))
                        continue;
 -              if (!pathspec_matches(paths, ce->name, opt->max_depth))
 +              if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
                        continue;
                /*
                 * If CE_VALID is on, we assume worktree file and its cache entry
        return hit;
  }
  
 -static int grep_tree(struct grep_opt *opt, const char **paths,
 -                   struct tree_desc *tree,
 -                   const char *tree_name, const char *base)
 +static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 +                   struct tree_desc *tree, struct strbuf *base, int tn_len)
  {
 -      int len;
 -      int hit = 0;
 +      int hit = 0, matched = 0;
        struct name_entry entry;
 -      char *down;
 -      int tn_len = strlen(tree_name);
 -      struct strbuf pathbuf;
 -
 -      strbuf_init(&pathbuf, PATH_MAX + tn_len);
 -
 -      if (tn_len) {
 -              strbuf_add(&pathbuf, tree_name, tn_len);
 -              strbuf_addch(&pathbuf, ':');
 -              tn_len = pathbuf.len;
 -      }
 -      strbuf_addstr(&pathbuf, base);
 -      len = pathbuf.len;
 +      int old_baselen = base->len;
  
        while (tree_entry(tree, &entry)) {
                int te_len = tree_entry_len(entry.path, entry.sha1);
 -              pathbuf.len = len;
 -              strbuf_add(&pathbuf, entry.path, te_len);
 -
 -              if (S_ISDIR(entry.mode))
 -                      /* Match "abc/" against pathspec to
 -                       * decide if we want to descend into "abc"
 -                       * directory.
 -                       */
 -                      strbuf_addch(&pathbuf, '/');
 -
 -              down = pathbuf.buf + tn_len;
 -              if (!pathspec_matches(paths, down, opt->max_depth))
 -                      ;
 -              else if (S_ISREG(entry.mode))
 -                      hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len);
 +
 +              if (matched != 2) {
 +                      matched = tree_entry_interesting(&entry, base, tn_len, pathspec);
 +                      if (matched == -1)
 +                              break; /* no more matches */
 +                      if (!matched)
 +                              continue;
 +              }
 +
 +              strbuf_add(base, entry.path, te_len);
 +
 +              if (S_ISREG(entry.mode)) {
 +                      hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len);
 +              }
                else if (S_ISDIR(entry.mode)) {
                        enum object_type type;
                        struct tree_desc sub;
  
                        data = lock_and_read_sha1_file(entry.sha1, &type, &size);
                        if (!data)
-                               die("unable to read tree (%s)",
+                               die(_("unable to read tree (%s)"),
                                    sha1_to_hex(entry.sha1));
 +
 +                      strbuf_addch(base, '/');
                        init_tree_desc(&sub, data, size);
 -                      hit |= grep_tree(opt, paths, &sub, tree_name, down);
 +                      hit |= grep_tree(opt, pathspec, &sub, base, tn_len);
                        free(data);
                }
 +              strbuf_setlen(base, old_baselen);
 +
                if (hit && opt->status_only)
                        break;
        }
 -      strbuf_release(&pathbuf);
        return hit;
  }
  
 -static int grep_object(struct grep_opt *opt, const char **paths,
 +static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
                       struct object *obj, const char *name)
  {
        if (obj->type == OBJ_BLOB)
                struct tree_desc tree;
                void *data;
                unsigned long size;
 -              int hit;
 +              struct strbuf base;
 +              int hit, len;
 +
                data = read_object_with_reference(obj->sha1, tree_type,
                                                  &size, NULL);
                if (!data)
-                       die("unable to read tree (%s)", sha1_to_hex(obj->sha1));
+                       die(_("unable to read tree (%s)"), sha1_to_hex(obj->sha1));
 +
 +              len = name ? strlen(name) : 0;
 +              strbuf_init(&base, PATH_MAX + len + 1);
 +              if (len) {
 +                      strbuf_add(&base, name, len);
 +                      strbuf_addch(&base, ':');
 +              }
                init_tree_desc(&tree, data, size);
 -              hit = grep_tree(opt, paths, &tree, name, "");
 +              hit = grep_tree(opt, pathspec, &tree, &base, base.len);
 +              strbuf_release(&base);
                free(data);
                return hit;
        }
-       die("unable to grep from object of type %s", typename(obj->type));
+       die(_("unable to grep from object of type %s"), typename(obj->type));
  }
  
 -static int grep_objects(struct grep_opt *opt, const char **paths,
 +static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
                        const struct object_array *list)
  {
        unsigned int i;
        for (i = 0; i < nr; i++) {
                struct object *real_obj;
                real_obj = deref_tag(list->objects[i].item, NULL, 0);
 -              if (grep_object(opt, paths, real_obj, list->objects[i].name)) {
 +              if (grep_object(opt, pathspec, real_obj, list->objects[i].name)) {
                        hit = 1;
                        if (opt->status_only)
                                break;
        return hit;
  }
  
 -static int grep_directory(struct grep_opt *opt, const char **paths)
 +static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec)
  {
        struct dir_struct dir;
        int i, hit = 0;
        memset(&dir, 0, sizeof(dir));
        setup_standard_excludes(&dir);
  
 -      fill_directory(&dir, paths);
 +      fill_directory(&dir, pathspec->raw);
        for (i = 0; i < dir.nr; i++) {
 +              const char *name = dir.entries[i]->name;
 +              int namelen = strlen(name);
 +              if (!match_pathspec_depth(pathspec, name, namelen, 0, NULL))
 +                      continue;
                hit |= grep_file(opt, dir.entries[i]->name);
                if (hit && opt->status_only)
                        break;
@@@ -649,7 -748,7 +649,7 @@@ static int context_callback(const struc
        }
        value = strtol(arg, (char **)&endp, 10);
        if (*endp) {
-               return error("switch `%c' expects a numerical value",
+               return error(_("switch `%c' expects a numerical value"),
                             opt->short_name);
        }
        grep_opt->pre_context = grep_opt->post_context = value;
  static int file_callback(const struct option *opt, const char *arg, int unset)
  {
        struct grep_opt *grep_opt = opt->value;
 +      int from_stdin = !strcmp(arg, "-");
        FILE *patterns;
        int lno = 0;
        struct strbuf sb = STRBUF_INIT;
  
 -      patterns = fopen(arg, "r");
 +      patterns = from_stdin ? stdin : fopen(arg, "r");
        if (!patterns)
-               die_errno("cannot open '%s'", arg);
+               die_errno(_("cannot open '%s'"), arg);
        while (strbuf_getline(&sb, patterns, '\n') == 0) {
                char *s;
                size_t len;
                s = strbuf_detach(&sb, &len);
                append_grep_pat(grep_opt, s, len, arg, ++lno, GREP_PATTERN);
        }
 -      fclose(patterns);
 +      if (!from_stdin)
 +              fclose(patterns);
        strbuf_release(&sb);
        return 0;
  }
@@@ -735,7 -832,6 +735,7 @@@ int cmd_grep(int argc, const char **arg
        struct grep_opt opt;
        struct object_array list = OBJECT_ARRAY_INIT;
        const char **paths = NULL;
 +      struct pathspec pathspec;
        struct string_list path_list = STRING_LIST_INIT_NODUP;
        int i;
        int dummy;
                OPT_BOOLEAN('F', "fixed-strings", &opt.fixed,
                        "interpret patterns as fixed strings"),
                OPT_GROUP(""),
 -              OPT_BOOLEAN('n', NULL, &opt.linenum, "show line numbers"),
 +              OPT_BOOLEAN('n', "line-number", &opt.linenum, "show line numbers"),
                OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
                OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
                OPT_NEGBIT(0, "full-name", &opt.relative,
        }
  
        if (!opt.pattern_list)
-               die("no pattern given.");
+               die(_("no pattern given."));
        if (!opt.fixed && opt.ignore_case)
                opt.regflags |= REG_ICASE;
        if ((opt.regflags != REG_NEWLINE) && opt.fixed)
-               die("cannot mix --fixed-strings and regexp");
+               die(_("cannot mix --fixed-strings and regexp"));
  
  #ifndef NO_PTHREADS
        if (online_cpus() == 1 || !grep_threads_ok(&opt))
                if (!get_sha1(arg, sha1)) {
                        struct object *object = parse_object(sha1);
                        if (!object)
-                               die("bad object %s", arg);
+                               die(_("bad object %s"), arg);
                        add_object_array(object, arg, &list);
                        continue;
                }
                paths[0] = prefix;
                paths[1] = NULL;
        }
 +      init_pathspec(&pathspec, paths);
 +      pathspec.max_depth = opt.max_depth;
 +      pathspec.recursive = 1;
  
        if (show_in_pager && (cached || list.nr))
-               die("--open-files-in-pager only works on the worktree");
+               die(_("--open-files-in-pager only works on the worktree"));
  
        if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) {
                const char *pager = path_list.items[0].string;
  
        if (!use_index) {
                if (cached)
-                       die("--cached cannot be used with --no-index.");
+                       die(_("--cached cannot be used with --no-index."));
                if (list.nr)
-                       die("--no-index cannot be used with revs.");
+                       die(_("--no-index cannot be used with revs."));
 -              hit = grep_directory(&opt, paths);
 +              hit = grep_directory(&opt, &pathspec);
        } else if (!list.nr) {
                if (!cached)
                        setup_work_tree();
  
 -              hit = grep_cache(&opt, paths, cached);
 +              hit = grep_cache(&opt, &pathspec, cached);
        } else {
                if (cached)
-                       die("both --cached and trees are given.");
+                       die(_("both --cached and trees are given."));
 -              hit = grep_objects(&opt, paths, &list);
 +              hit = grep_objects(&opt, &pathspec, &list);
        }
  
        if (use_threads)
diff --combined builtin/init-db.c
index 8f5cfd712243975dacd08cb51c69c2e174e470b1,e0e5ce3b1985cd2aba66d8c00d134d5c7a5a62ef..6621e5671cbc4cbe5631a40f918aa4f0f05bb62e
@@@ -31,7 -31,7 +31,7 @@@ static void safe_create_dir(const char 
                }
        }
        else if (share && adjust_shared_perm(dir))
-               die("Could not make %s writable by group", dir);
+               die(_("Could not make %s writable by group"), dir);
  }
  
  static void copy_templates_1(char *path, int baselen,
                namelen = strlen(de->d_name);
                if ((PATH_MAX <= baselen + namelen) ||
                    (PATH_MAX <= template_baselen + namelen))
-                       die("insanely long template name %s", de->d_name);
+                       die(_("insanely long template name %s"), de->d_name);
                memcpy(path + baselen, de->d_name, namelen+1);
                memcpy(template + template_baselen, de->d_name, namelen+1);
                if (lstat(path, &st_git)) {
                        if (errno != ENOENT)
-                               die_errno("cannot stat '%s'", path);
+                               die_errno(_("cannot stat '%s'"), path);
                }
                else
                        exists = 1;
  
                if (lstat(template, &st_template))
-                       die_errno("cannot stat template '%s'", template);
+                       die_errno(_("cannot stat template '%s'"), template);
  
                if (S_ISDIR(st_template.st_mode)) {
                        DIR *subdir = opendir(template);
                        int baselen_sub = baselen + namelen;
                        int template_baselen_sub = template_baselen + namelen;
                        if (!subdir)
-                               die_errno("cannot opendir '%s'", template);
+                               die_errno(_("cannot opendir '%s'"), template);
                        path[baselen_sub++] =
                                template[template_baselen_sub++] = '/';
                        path[baselen_sub] =
                        int len;
                        len = readlink(template, lnk, sizeof(lnk));
                        if (len < 0)
-                               die_errno("cannot readlink '%s'", template);
+                               die_errno(_("cannot readlink '%s'"), template);
                        if (sizeof(lnk) <= len)
-                               die("insanely long symlink %s", template);
+                               die(_("insanely long symlink %s"), template);
                        lnk[len] = 0;
                        if (symlink(lnk, path))
-                               die_errno("cannot symlink '%s' '%s'", lnk, path);
+                               die_errno(_("cannot symlink '%s' '%s'"), lnk, path);
                }
                else if (S_ISREG(st_template.st_mode)) {
                        if (copy_file(path, template, st_template.st_mode))
-                               die_errno("cannot copy '%s' to '%s'", template,
+                               die_errno(_("cannot copy '%s' to '%s'"), template,
                                          path);
                }
                else
-                       error("ignoring template %s", template);
+                       error(_("ignoring template %s"), template);
        }
  }
  
@@@ -129,7 -129,7 +129,7 @@@ static void copy_templates(const char *
                return;
        template_len = strlen(template_dir);
        if (PATH_MAX <= (template_len+strlen("/config")))
-               die("insanely long template path %s", template_dir);
+               die(_("insanely long template path %s"), template_dir);
        strcpy(template_path, template_dir);
        if (template_path[template_len-1] != '/') {
                template_path[template_len++] = '/';
        }
        dir = opendir(template_path);
        if (!dir) {
-               warning("templates not found %s", template_dir);
+               warning(_("templates not found %s"), template_dir);
                return;
        }
  
  
        if (repository_format_version &&
            repository_format_version != GIT_REPO_VERSION) {
-               warning("not copying templates of "
-                       "a wrong format version %d from '%s'",
+               warning(_("not copying templates of "
+                       "a wrong format version %d from '%s'"),
                        repository_format_version,
                        template_dir);
                closedir(dir);
@@@ -188,7 -188,7 +188,7 @@@ static int create_default_files(const c
        int filemode;
  
        if (len > sizeof(path)-50)
-               die("insane git directory %s", git_dir);
+               die(_("insane git directory %s"), git_dir);
        memcpy(path, git_dir, len);
  
        if (len && path[len-1] != '/')
@@@ -354,9 -354,15 +354,15 @@@ int init_db(const char *template_dir, u
        if (!(flags & INIT_DB_QUIET)) {
                const char *git_dir = get_git_dir();
                int len = strlen(git_dir);
-               printf("%s%s Git repository in %s%s\n",
-                      reinit ? "Reinitialized existing" : "Initialized empty",
-                      shared_repository ? " shared" : "",
+               /*
+                * TRANSLATORS: The first '%s' is either "Reinitialized
+                * existing" or "Initialized empty", the second " shared" or
+                * "", and the last '%s%s' is the verbatim directory name.
+                */
+               printf(_("%s%s Git repository in %s%s\n"),
+                      reinit ? _("Reinitialized existing") : _("Initialized empty"),
+                      shared_repository ? _(" shared") : "",
                       git_dir, len && git_dir[len-1] != '/' ? "/" : "");
        }
  
@@@ -375,7 -381,7 +381,7 @@@ static int guess_repository_type(const 
        if (!strcmp(".", git_dir))
                return 1;
        if (!getcwd(cwd, sizeof(cwd)))
-               die_errno("cannot tell cwd");
+               die_errno(_("cannot tell cwd"));
        if (!strcmp(git_dir, cwd))
                return 1;
        /*
@@@ -450,18 -456,18 +456,18 @@@ int cmd_init_db(int argc, const char **
                                        errno = EEXIST;
                                        /* fallthru */
                                case -1:
-                                       die_errno("cannot mkdir %s", argv[0]);
+                                       die_errno(_("cannot mkdir %s"), argv[0]);
                                        break;
                                default:
                                        break;
                                }
                                shared_repository = saved;
                                if (mkdir(argv[0], 0777) < 0)
-                                       die_errno("cannot mkdir %s", argv[0]);
+                                       die_errno(_("cannot mkdir %s"), argv[0]);
                                mkdir_tried = 1;
                                goto retry;
                        }
-                       die_errno("cannot chdir to %s", argv[0]);
+                       die_errno(_("cannot chdir to %s"), argv[0]);
                }
        } else if (0 < argc) {
                usage(init_db_usage[0]);
        git_dir = getenv(GIT_DIR_ENVIRONMENT);
        work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
        if ((!git_dir || is_bare_repository_cfg == 1) && work_tree)
-               die("%s (or --work-tree=<directory>) not allowed without "
-                   "specifying %s (or --git-dir=<directory>)",
+               die(_("%s (or --work-tree=<directory>) not allowed without "
+                         "specifying %s (or --git-dir=<directory>)"),
                    GIT_WORK_TREE_ENVIRONMENT,
                    GIT_DIR_ENVIRONMENT);
  
                is_bare_repository_cfg = guess_repository_type(git_dir);
  
        if (!is_bare_repository_cfg) {
 -              if (git_dir) {
 -                      const char *git_dir_parent = strrchr(git_dir, '/');
 -                      if (git_dir_parent) {
 -                              char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
 -                              git_work_tree_cfg = xstrdup(make_absolute_path(rel));
 -                              free(rel);
 -                      }
 +              const char *git_dir_parent = strrchr(git_dir, '/');
 +              if (git_dir_parent) {
 +                      char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
 +                      git_work_tree_cfg = xstrdup(real_path(rel));
 +                      free(rel);
                }
                if (!git_work_tree_cfg) {
                        git_work_tree_cfg = xcalloc(PATH_MAX, 1);
                        if (!getcwd(git_work_tree_cfg, PATH_MAX))
-                               die_errno ("Cannot access current working directory");
+                               die_errno (_("Cannot access current working directory"));
                }
                if (work_tree)
 -                      set_git_work_tree(make_absolute_path(work_tree));
 +                      set_git_work_tree(real_path(work_tree));
                else
                        set_git_work_tree(git_work_tree_cfg);
                if (access(get_git_work_tree(), X_OK))
-                       die_errno ("Cannot access work tree '%s'",
+                       die_errno (_("Cannot access work tree '%s'"),
                                   get_git_work_tree());
        }
        else {
                if (work_tree)
 -                      set_git_work_tree(make_absolute_path(work_tree));
 +                      set_git_work_tree(real_path(work_tree));
        }
  
 -      set_git_dir(make_absolute_path(git_dir));
 +      set_git_dir(real_path(git_dir));
  
        return init_db(template_dir, flags);
  }
diff --combined builtin/log.c
index 4a0f78dc7139ac529e60e7e1099834ff7efe1163,853f5d0401f32b9e3dede14ad1f3e1e78b1dccdb..9db43edb063bbcb4da3b213d92d14b5c92aa4cfb
@@@ -89,7 -89,7 +89,7 @@@ static void cmd_log_init(int argc, cons
                rev->always_show_header = 0;
        if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {
                rev->always_show_header = 0;
 -              if (rev->diffopt.nr_paths != 1)
 +              if (rev->diffopt.pathspec.nr != 1)
                        usage("git logs can only follow renames on one pathname at a time");
        }
        for (i = 1; i < argc; i++) {
                        const char *v = skip_prefix(arg, "--decorate=");
                        decoration_style = parse_decoration_style(arg, v);
                        if (decoration_style < 0)
-                               die("invalid --decorate option: %s", arg);
+                               die(_("invalid --decorate option: %s"), arg);
                        decoration_given = 1;
                } else if (!strcmp(arg, "--no-decorate")) {
                        decoration_style = 0;
                } else if (!strcmp(arg, "-h")) {
                        usage(builtin_log_usage);
                } else
-                       die("unrecognized argument: %s", arg);
+                       die(_("unrecognized argument: %s"), arg);
        }
  
        /*
@@@ -153,7 -153,7 +153,7 @@@ static void show_early_header(struct re
                if (rev->commit_format != CMIT_FMT_ONELINE)
                        putchar(rev->diffopt.line_termination);
        }
-       printf("Final output: %d %s\n", nr, stage);
+       printf(_("Final output: %d %s\n"), nr, stage);
  }
  
  static struct itimerval early_output_timer;
@@@ -252,7 -252,7 +252,7 @@@ static int cmd_log_walk(struct rev_inf
                setup_early_output(rev);
  
        if (prepare_revision_walk(rev))
-               die("revision walk setup failed");
+               die(_("revision walk setup failed"));
  
        if (rev->early_output)
                finish_early_output(rev);
         * retain that state information if replacing rev->diffopt in this loop
         */
        while ((commit = get_revision(rev)) != NULL) {
 -              log_tree_commit(rev, commit);
 +              if (!log_tree_commit(rev, commit) &&
 +                  rev->max_count >= 0)
 +                      /*
 +                       * We decremented max_count in get_revision,
 +                       * but we didn't actually show the commit.
 +                       */
 +                      rev->max_count++;
                if (!rev->reflog_info) {
                        /* we allow cycles in reflog ancestry */
                        free(commit->buffer);
@@@ -349,7 -343,7 +349,7 @@@ static int show_object(const unsigned c
        int offset = 0;
  
        if (!buf)
-               return error("Could not read object %s", sha1_to_hex(sha1));
+               return error(_("Could not read object %s"), sha1_to_hex(sha1));
  
        if (show_tag_object)
                while (offset < size && buf[offset] != '\n') {
@@@ -436,7 -430,7 +436,7 @@@ int cmd_show(int argc, const char **arg
                                break;
                        o = parse_object(t->tagged->sha1);
                        if (!o)
-                               ret = error("Could not read object %s",
+                               ret = error(_("Could not read object %s"),
                                            sha1_to_hex(t->tagged->sha1));
                        objects[i].item = o;
                        i--;
                        ret = cmd_log_walk(&rev);
                        break;
                default:
-                       ret = error("Unknown type: %d", o->type);
+                       ret = error(_("Unknown type: %d"), o->type);
                }
        }
        free(objects);
@@@ -560,7 -554,7 +560,7 @@@ static int git_format_config(const cha
  {
        if (!strcmp(var, "format.headers")) {
                if (!value)
-                       die("format.headers without value");
+                       die(_("format.headers without value"));
                add_header(value);
                return 0;
        }
@@@ -632,7 -626,7 +632,7 @@@ static int reopen_stdout(struct commit 
                strbuf_addstr(&filename, output_directory);
                if (filename.len >=
                    PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len)
-                       return error("name of output directory is too long");
+                       return error(_("name of output directory is too long"));
                if (filename.buf[filename.len - 1] != '/')
                        strbuf_addch(&filename, '/');
        }
                fprintf(realstdout, "%s\n", filename.buf + outdir_offset);
  
        if (freopen(filename.buf, "w", stdout) == NULL)
-               return error("Cannot open patch file %s", filename.buf);
+               return error(_("Cannot open patch file %s"), filename.buf);
  
        strbuf_release(&filename);
        return 0;
@@@ -657,7 -651,7 +657,7 @@@ static void get_patch_ids(struct rev_in
        unsigned flags1, flags2;
  
        if (rev->pending.nr != 2)
-               die("Need exactly one range.");
+               die(_("Need exactly one range."));
  
        o1 = rev->pending.objects[0].item;
        flags1 = o1->flags;
        flags2 = o2->flags;
  
        if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
-               die("Not a range.");
+               die(_("Not a range."));
  
        init_patch_ids(ids);
  
        add_pending_object(&check_rev, o1, "o1");
        add_pending_object(&check_rev, o2, "o2");
        if (prepare_revision_walk(&check_rev))
-               die("revision walk setup failed");
+               die(_("revision walk setup failed"));
  
        while ((commit = get_revision(&check_rev)) != NULL) {
                /* ignore merges */
@@@ -702,7 -696,7 +702,7 @@@ static void gen_message_id(struct rev_i
        const char *email_end = strrchr(committer, '>');
        struct strbuf buf = STRBUF_INIT;
        if (!email_start || !email_end || email_start > email_end - 1)
-               die("Could not extract email from committer identity.");
+               die(_("Could not extract email from committer identity."));
        strbuf_addf(&buf, "%s.%lu.git.%.*s", base,
                    (unsigned long) time(NULL),
                    (int)(email_end - email_start - 1), email_start + 1);
@@@ -734,7 -728,7 +734,7 @@@ static void make_cover_letter(struct re
        struct commit *commit = NULL;
  
        if (rev->commit_format != CMIT_FMT_EMAIL)
-               die("Cover letter needs email format");
+               die(_("Cover letter needs email format"));
  
        committer = git_committer_info(0);
  
@@@ -827,7 -821,7 +827,7 @@@ static const char *clean_message_id(con
                m++;
        }
        if (!z)
-               die("insane in-reply-to: %s", msg_id);
+               die(_("insane in-reply-to: %s"), msg_id);
        if (++z == m)
                return a;
        return xmemdupz(a, z - a);
@@@ -900,7 -894,7 +900,7 @@@ static int output_directory_callback(co
  {
        const char **dir = (const char **)opt->value;
        if (*dir)
-               die("Two output directories?");
+               die(_("Two output directories?"));
        *dir = arg;
        return 0;
  }
@@@ -1061,7 -1055,7 +1061,7 @@@ int cmd_format_patch(int argc, const ch
        rev.commit_format = CMIT_FMT_EMAIL;
        rev.verbose_header = 1;
        rev.diff = 1;
 -      rev.no_merges = 1;
 +      rev.max_parents = 1;
        DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
        rev.subject_prefix = fmt_patch_subject_prefix;
        memset(&s_r_opt, 0, sizeof(s_r_opt));
                committer = git_committer_info(IDENT_ERROR_ON_NO_NAME);
                endpos = strchr(committer, '>');
                if (!endpos)
-                       die("bogus committer info %s", committer);
+                       die(_("bogus committer info %s"), committer);
                add_signoff = xmemdupz(committer, endpos - committer + 1);
        }
  
                numbered = 0;
  
        if (numbered && keep_subject)
-               die ("-n and -k are mutually exclusive.");
+               die (_("-n and -k are mutually exclusive."));
        if (keep_subject && subject_prefix)
-               die ("--subject-prefix and -k are mutually exclusive.");
+               die (_("--subject-prefix and -k are mutually exclusive."));
  
        argc = setup_revisions(argc, argv, &rev, &s_r_opt);
        if (argc > 1)
-               die ("unrecognized argument: %s", argv[1]);
+               die (_("unrecognized argument: %s"), argv[1]);
  
        if (rev.diffopt.output_format & DIFF_FORMAT_NAME)
-               die("--name-only does not make sense");
+               die(_("--name-only does not make sense"));
        if (rev.diffopt.output_format & DIFF_FORMAT_NAME_STATUS)
-               die("--name-status does not make sense");
+               die(_("--name-status does not make sense"));
        if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
-               die("--check does not make sense");
+               die(_("--check does not make sense"));
  
        if (!use_patch_format &&
                (!rev.diffopt.output_format ||
  
        if (output_directory) {
                if (use_stdout)
-                       die("standard output, or directory, which one?");
+                       die(_("standard output, or directory, which one?"));
                if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
-                       die_errno("Could not create directory '%s'",
+                       die_errno(_("Could not create directory '%s'"),
                                  output_directory);
        }
  
                realstdout = xfdopen(xdup(1), "w");
  
        if (prepare_revision_walk(&rev))
-               die("revision walk setup failed");
+               die(_("revision walk setup failed"));
        rev.boundary = 1;
        while ((commit = get_revision(&rev)) != NULL) {
                if (commit->object.flags & BOUNDARY) {
  
                if (!use_stdout && reopen_stdout(numbered_files ? NULL : commit,
                                                 &rev))
-                       die("Failed to create output files");
+                       die(_("Failed to create output files"));
                shown = log_tree_commit(&rev, commit);
                free(commit->buffer);
                commit->buffer = NULL;
@@@ -1358,23 -1352,6 +1358,23 @@@ static const char * const cherry_usage[
        NULL
  };
  
 +static void print_commit(char sign, struct commit *commit, int verbose,
 +                       int abbrev)
 +{
 +      if (!verbose) {
 +              printf("%c %s\n", sign,
 +                     find_unique_abbrev(commit->object.sha1, abbrev));
 +      } else {
 +              struct strbuf buf = STRBUF_INIT;
 +              struct pretty_print_context ctx = {0};
 +              pretty_print_commit(CMIT_FMT_ONELINE, commit, &buf, &ctx);
 +              printf("%c %s %s\n", sign,
 +                     find_unique_abbrev(commit->object.sha1, abbrev),
 +                     buf.buf);
 +              strbuf_release(&buf);
 +      }
 +}
 +
  int cmd_cherry(int argc, const char **argv, const char *prefix)
  {
        struct rev_info revs;
                if (!current_branch || !current_branch->merge
                                        || !current_branch->merge[0]
                                        || !current_branch->merge[0]->dst) {
-                       fprintf(stderr, "Could not find a tracked"
+                       fprintf(stderr, _("Could not find a tracked"
                                        " remote branch, please"
-                                       " specify <upstream> manually.\n");
+                                       " specify <upstream> manually.\n"));
                        usage_with_options(cherry_usage, options);
                }
  
        DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
  
        if (add_pending_commit(head, &revs, 0))
-               die("Unknown commit %s", head);
+               die(_("Unknown commit %s"), head);
        if (add_pending_commit(upstream, &revs, UNINTERESTING))
-               die("Unknown commit %s", upstream);
+               die(_("Unknown commit %s"), upstream);
  
        /* Don't say anything if head and upstream are the same. */
        if (revs.pending.nr == 2) {
        get_patch_ids(&revs, &ids, prefix);
  
        if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
-               die("Unknown commit %s", limit);
+               die(_("Unknown commit %s"), limit);
  
        /* reverse the list of commits */
        if (prepare_revision_walk(&revs))
-               die("revision walk setup failed");
+               die(_("revision walk setup failed"));
        while ((commit = get_revision(&revs)) != NULL) {
                /* ignore merges */
                if (commit->parents && commit->parents->next)
                commit = list->item;
                if (has_commit_patch_id(commit, &ids))
                        sign = '-';
 -
 -              if (verbose) {
 -                      struct strbuf buf = STRBUF_INIT;
 -                      struct pretty_print_context ctx = {0};
 -                      pretty_print_commit(CMIT_FMT_ONELINE, commit,
 -                                          &buf, &ctx);
 -                      printf("%c %s %s\n", sign,
 -                             find_unique_abbrev(commit->object.sha1, abbrev),
 -                             buf.buf);
 -                      strbuf_release(&buf);
 -              }
 -              else {
 -                      printf("%c %s\n", sign,
 -                             find_unique_abbrev(commit->object.sha1, abbrev));
 -              }
 -
 +              print_commit(sign, commit, verbose, abbrev);
                list = list->next;
        }
  
diff --combined builtin/merge.c
index c8d028cbccdc001efed2991e477b898606396114,f9982066139de64a3ad536b5970cb04e1c9f53cf..1e0bcfd792e4fb550fea8786ff2f84e7925aca86
@@@ -58,7 -58,6 +58,7 @@@ static int option_renormalize
  static int verbosity;
  static int allow_rerere_auto;
  static int abort_current_merge;
 +static int show_progress = -1;
  
  static struct strategy all_strategy[] = {
        { "recursive",  DEFAULT_TWOHEAD | NO_TRIVIAL },
@@@ -81,7 -80,7 +81,7 @@@ static int option_parse_message(const s
                strbuf_addf(buf, "%s%s", buf->len ? "\n\n" : "", arg);
                have_message = 1;
        } else
-               return error("switch `m' requires a value");
+               return error(_("switch `m' requires a value"));
        return 0;
  }
  
@@@ -118,13 -117,13 +118,13 @@@ static struct strategy *get_strategy(co
                exclude_cmds(&main_cmds, &not_strategies);
        }
        if (!is_in_cmdlist(&main_cmds, name) && !is_in_cmdlist(&other_cmds, name)) {
-               fprintf(stderr, "Could not find merge strategy '%s'.\n", name);
-               fprintf(stderr, "Available strategies are:");
+               fprintf(stderr, _("Could not find merge strategy '%s'.\n"), name);
+               fprintf(stderr, _("Available strategies are:"));
                for (i = 0; i < main_cmds.cnt; i++)
                        fprintf(stderr, " %s", main_cmds.names[i]->name);
                fprintf(stderr, ".\n");
                if (other_cmds.cnt) {
-                       fprintf(stderr, "Available custom strategies are:");
+                       fprintf(stderr, _("Available custom strategies are:"));
                        for (i = 0; i < other_cmds.cnt; i++)
                                fprintf(stderr, " %s", other_cmds.names[i]->name);
                        fprintf(stderr, ".\n");
@@@ -195,13 -194,12 +195,13 @@@ static struct option builtin_merge_opti
                "merge strategy to use", option_parse_strategy),
        OPT_CALLBACK('X', "strategy-option", &xopts, "option=value",
                "option for selected merge strategy", option_parse_x),
 -      OPT_CALLBACK('m', "message", &merge_msg, "MESSAGE",
 +      OPT_CALLBACK('m', "message", &merge_msg, "message",
                "merge commit message (for a non-fast-forward merge)",
                option_parse_message),
        OPT__VERBOSITY(&verbosity),
        OPT_BOOLEAN(0, "abort", &abort_current_merge,
                "abort the current in-progress merge"),
 +      OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
        OPT_END()
  };
  
@@@ -226,17 -224,17 +226,17 @@@ static void save_state(void
        cp.git_cmd = 1;
  
        if (start_command(&cp))
-               die("could not run stash.");
+               die(_("could not run stash."));
        len = strbuf_read(&buffer, cp.out, 1024);
        close(cp.out);
  
        if (finish_command(&cp) || len < 0)
-               die("stash failed");
+               die(_("stash failed"));
        else if (!len)
                return;
        strbuf_setlen(&buffer, buffer.len-1);
        if (get_sha1(buffer.buf, stash))
-               die("not a valid object: %s", buffer.buf);
+               die(_("not a valid object: %s"), buffer.buf);
  }
  
  static void read_empty(unsigned const char *sha1, int verbose)
        args[i] = NULL;
  
        if (run_command_v_opt(args, RUN_GIT_CMD))
-               die("read-tree failed");
+               die(_("read-tree failed"));
  }
  
  static void reset_hard(unsigned const char *sha1, int verbose)
        args[i] = NULL;
  
        if (run_command_v_opt(args, RUN_GIT_CMD))
-               die("read-tree failed");
+               die(_("read-tree failed"));
  }
  
  static void restore_state(void)
  static void finish_up_to_date(const char *msg)
  {
        if (verbosity >= 0)
-               printf("%s%s\n", squash ? " (nothing to squash)" : "", msg);
+               printf("%s%s\n", squash ? _(" (nothing to squash)") : "", msg);
        drop_save();
  }
  
@@@ -313,10 -311,10 +313,10 @@@ static void squash_message(void
        int fd;
        struct pretty_print_context ctx = {0};
  
-       printf("Squash commit -- not updating HEAD\n");
+       printf(_("Squash commit -- not updating HEAD\n"));
        fd = open(git_path("SQUASH_MSG"), O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
-               die_errno("Could not write to '%s'", git_path("SQUASH_MSG"));
+               die_errno(_("Could not write to '%s'"), git_path("SQUASH_MSG"));
  
        init_revisions(&rev, NULL);
        rev.ignore_merges = 1;
  
        setup_revisions(0, NULL, &rev, NULL);
        if (prepare_revision_walk(&rev))
-               die("revision walk setup failed");
+               die(_("revision walk setup failed"));
  
        ctx.abbrev = rev.abbrev;
        ctx.date_mode = rev.date_mode;
                pretty_print_commit(rev.commit_format, commit, &out, &ctx);
        }
        if (write(fd, out.buf, out.len) < 0)
-               die_errno("Writing SQUASH_MSG");
+               die_errno(_("Writing SQUASH_MSG"));
        if (close(fd))
-               die_errno("Finishing SQUASH_MSG");
+               die_errno(_("Finishing SQUASH_MSG"));
        strbuf_release(&out);
  }
  
@@@ -366,7 -364,7 +366,7 @@@ static void finish(const unsigned char 
                squash_message();
        } else {
                if (verbosity >= 0 && !merge_msg.len)
-                       printf("No merge message -- not updating HEAD\n");
+                       printf(_("No merge message -- not updating HEAD\n"));
                else {
                        const char *argv_gc_auto[] = { "gc", "--auto", NULL };
                        update_ref(reflog_message.buf, "HEAD",
                if (diff_use_color_default > 0)
                        DIFF_OPT_SET(&opts, COLOR_DIFF);
                if (diff_setup_done(&opts) < 0)
-                       die("diff_setup_done failed");
+                       die(_("diff_setup_done failed"));
                diff_tree_sha1(head, new_head, "", &opts);
                diffcore_std(&opts);
                diff_flush(&opts);
@@@ -417,7 -415,7 +417,7 @@@ static void merge_name(const char *remo
        memset(branch_head, 0, sizeof(branch_head));
        remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);
        if (!remote_head)
-               die("'%s' does not point to a commit", remote);
+               die(_("'%s' does not point to a commit"), remote);
  
        if (dwim_ref(remote, strlen(remote), branch_head, &found_ref) > 0) {
                if (!prefixcmp(found_ref, "refs/heads/")) {
  
                fp = fopen(git_path("FETCH_HEAD"), "r");
                if (!fp)
-                       die_errno("could not open '%s' for reading",
+                       die_errno(_("could not open '%s' for reading"),
                                  git_path("FETCH_HEAD"));
                strbuf_getline(&line, fp, '\n');
                fclose(fp);
@@@ -512,7 -510,7 +512,7 @@@ static int git_merge_config(const char 
                buf = xstrdup(v);
                argc = split_cmdline(buf, &argv);
                if (argc < 0)
-                       die("Bad branch.%s.mergeoptions string: %s", branch,
+                       die(_("Bad branch.%s.mergeoptions string: %s"), branch,
                            split_cmdline_strerror(argc));
                argv = xrealloc(argv, sizeof(*argv) * (argc + 2));
                memmove(argv + 1, argv, sizeof(*argv) * (argc + 1));
                int is_bool;
                shortlog_len = git_config_bool_or_int(k, v, &is_bool);
                if (!is_bool && shortlog_len < 0)
-                       return error("%s: negative length %s", k, v);
+                       return error(_("%s: negative length %s"), k, v);
                if (is_bool && shortlog_len)
                        shortlog_len = DEFAULT_MERGE_LOG_LEN;
                return 0;
@@@ -581,7 -579,7 +581,7 @@@ static int read_tree_trivial(unsigned c
  static void write_tree_trivial(unsigned char *sha1)
  {
        if (write_cache_as_tree(sha1, 0, NULL))
-               die("git write-tree failed to write a tree");
+               die(_("git write-tree failed to write a tree"));
  }
  
  int try_merge_command(const char *strategy, size_t xopts_nr,
        free(args);
        discard_cache();
        if (read_cache() < 0)
-               die("failed to read the cache");
+               die(_("failed to read the cache"));
        resolve_undo_clear();
  
        return ret;
@@@ -640,7 -638,7 +640,7 @@@ static int try_merge_strategy(const cha
        if (active_cache_changed &&
                        (write_cache(index_fd, active_cache, active_nr) ||
                         commit_locked_index(lock)))
-               return error("Unable to write index.");
+               return error(_("Unable to write index."));
        rollback_lock_file(lock);
  
        if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) {
                struct commit_list *j;
  
                if (remoteheads->next) {
-                       error("Not handling anything other than two heads merge.");
+                       error(_("Not handling anything other than two heads merge."));
                        return 2;
                }
  
                        o.subtree_shift = "";
  
                o.renormalize = option_renormalize;
 +              o.show_rename_progress =
 +                      show_progress == -1 ? isatty(2) : show_progress;
  
                for (x = 0; x < xopts_nr; x++)
                        if (parse_merge_opt(&o, xopts[x]))
-                               die("Unknown option for merge-recursive: -X%s", xopts[x]);
+                               die(_("Unknown option for merge-recursive: -X%s"), xopts[x]);
  
                o.branch1 = head_arg;
                o.branch2 = remoteheads->item->util;
                if (active_cache_changed &&
                                (write_cache(index_fd, active_cache, active_nr) ||
                                 commit_locked_index(lock)))
-                       die ("unable to write %s", get_index_file());
+                       die (_("unable to write %s"), get_index_file());
                rollback_lock_file(lock);
                return clean ? 0 : 1;
        } else {
@@@ -753,7 -749,7 +753,7 @@@ int checkout_fast_forward(const unsigne
                return -1;
        if (write_cache(fd, active_cache, active_nr) ||
                commit_locked_index(lock_file))
-               die("unable to write new index file");
+               die(_("unable to write new index file"));
        return 0;
  }
  
@@@ -801,44 -797,17 +801,44 @@@ static void add_strategies(const char *
  
  }
  
-               die_errno("Could not open '%s' for writing",
 +static void write_merge_msg(void)
 +{
 +      int fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
 +      if (fd < 0)
-               die_errno("Could not write to '%s'", git_path("MERGE_MSG"));
++              die_errno(_("Could not open '%s' for writing"),
 +                        git_path("MERGE_MSG"));
 +      if (write_in_full(fd, merge_msg.buf, merge_msg.len) != merge_msg.len)
++              die_errno(_("Could not write to '%s'"), git_path("MERGE_MSG"));
 +      close(fd);
 +}
 +
 +static void read_merge_msg(void)
 +{
 +      strbuf_reset(&merge_msg);
 +      if (strbuf_read_file(&merge_msg, git_path("MERGE_MSG"), 0) < 0)
 +              die_errno("Could not read from '%s'", git_path("MERGE_MSG"));
 +}
 +
 +static void run_prepare_commit_msg(void)
 +{
 +      write_merge_msg();
 +      run_hook(get_index_file(), "prepare-commit-msg",
 +               git_path("MERGE_MSG"), "merge", NULL, NULL);
 +      read_merge_msg();
 +}
 +
  static int merge_trivial(void)
  {
        unsigned char result_tree[20], result_commit[20];
        struct commit_list *parent = xmalloc(sizeof(*parent));
  
        write_tree_trivial(result_tree);
-       printf("Wonderful.\n");
+       printf(_("Wonderful.\n"));
        parent->item = lookup_commit(head);
        parent->next = xmalloc(sizeof(*parent->next));
        parent->next->item = remoteheads->item;
        parent->next->next = NULL;
 +      run_prepare_commit_msg();
        commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
        finish(result_commit, "In-index merge");
        drop_save();
@@@ -868,7 -837,6 +868,7 @@@ static int finish_automerge(struct comm
        }
        free_commit_list(remoteheads);
        strbuf_addch(&merge_msg, '\n');
 +      run_prepare_commit_msg();
        commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
        strbuf_addf(&buf, "Merge made by %s.", wt_strategy);
        finish(result_commit, buf.buf);
@@@ -884,7 -852,7 +884,7 @@@ static int suggest_conflicts(int renorm
  
        fp = fopen(git_path("MERGE_MSG"), "a");
        if (!fp)
-               die_errno("Could not open '%s' for writing",
+               die_errno(_("Could not open '%s' for writing"),
                          git_path("MERGE_MSG"));
        fprintf(fp, "\nConflicts:\n");
        for (pos = 0; pos < active_nr; pos++) {
        }
        fclose(fp);
        rerere(allow_rerere_auto);
-       printf("Automatic merge failed; "
-                       "fix conflicts and then commit the result.\n");
+       printf(_("Automatic merge failed; "
+                       "fix conflicts and then commit the result.\n"));
        return 1;
  }
  
@@@ -915,7 -883,7 +915,7 @@@ static struct commit *is_old_style_invo
                        return NULL;
                second_token = lookup_commit_reference_gently(second_sha1, 0);
                if (!second_token)
-                       die("'%s' is not a commit", argv[1]);
+                       die(_("'%s' is not a commit"), argv[1]);
                if (hashcmp(second_token->object.sha1, head))
                        return NULL;
        }
@@@ -978,15 -946,12 +978,15 @@@ int cmd_merge(int argc, const char **ar
        argc = parse_options(argc, argv, prefix, builtin_merge_options,
                        builtin_merge_usage, 0);
  
 +      if (verbosity < 0 && show_progress == -1)
 +              show_progress = 0;
 +
        if (abort_current_merge) {
                int nargc = 2;
                const char *nargv[] = {"reset", "--merge", NULL};
  
                if (!file_exists(git_path("MERGE_HEAD")))
-                       die("There is no merge to abort (MERGE_HEAD missing).");
+                       die(_("There is no merge to abort (MERGE_HEAD missing)."));
  
                /* Invoke 'git reset --merge' */
                return cmd_reset(nargc, nargv, prefix);
                 * add/rm <file>', just 'git commit'.
                 */
                if (advice_resolve_conflict)
-                       die("You have not concluded your merge (MERGE_HEAD exists).\n"
-                           "Please, commit your changes before you can merge.");
+                       die(_("You have not concluded your merge (MERGE_HEAD exists).\n"
+                                 "Please, commit your changes before you can merge."));
                else
-                       die("You have not concluded your merge (MERGE_HEAD exists).");
+                       die(_("You have not concluded your merge (MERGE_HEAD exists)."));
        }
 +      if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
 +              if (advice_resolve_conflict)
 +                      die("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
 +                          "Please, commit your changes before you can merge.");
 +              else
 +                      die("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).");
 +      }
        resolve_undo_clear();
  
        if (verbosity < 0)
  
        if (squash) {
                if (!allow_fast_forward)
-                       die("You cannot combine --squash with --no-ff.");
+                       die(_("You cannot combine --squash with --no-ff."));
                option_commit = 0;
        }
  
        if (!allow_fast_forward && fast_forward_only)
-               die("You cannot combine --no-ff with --ff-only.");
+               die(_("You cannot combine --no-ff with --ff-only."));
  
        if (!argc)
                usage_with_options(builtin_merge_usage,
                 * We do the same for "git pull".
                 */
                if (argc != 1)
-                       die("Can merge only exactly one commit into "
-                               "empty head");
+                       die(_("Can merge only exactly one commit into "
+                               "empty head"));
                if (squash)
-                       die("Squash commit into empty head not supported yet");
+                       die(_("Squash commit into empty head not supported yet"));
                if (!allow_fast_forward)
-                       die("Non-fast-forward commit does not make sense into "
-                           "an empty head");
+                       die(_("Non-fast-forward commit does not make sense into "
+                           "an empty head"));
                remote_head = peel_to_type(argv[0], 0, NULL, OBJ_COMMIT);
                if (!remote_head)
-                       die("%s - not something we can merge", argv[0]);
+                       die(_("%s - not something we can merge"), argv[0]);
 +              read_empty(remote_head->sha1, 0);
                update_ref("initial pull", "HEAD", remote_head->sha1, NULL, 0,
                                DIE_ON_ERR);
 -              read_empty(remote_head->sha1, 0);
                return 0;
        } else {
                struct strbuf merge_names = STRBUF_INIT;
  
                o = peel_to_type(argv[i], 0, NULL, OBJ_COMMIT);
                if (!o)
-                       die("%s - not something we can merge", argv[i]);
+                       die(_("%s - not something we can merge"), argv[i]);
                commit = lookup_commit(o->sha1);
                commit->util = (void *)argv[i];
                remotes = &commit_list_insert(commit, remotes)->next;
                strcpy(hex, find_unique_abbrev(head, DEFAULT_ABBREV));
  
                if (verbosity >= 0)
-                       printf("Updating %s..%s\n",
+                       printf(_("Updating %s..%s\n"),
                                hex,
                                find_unique_abbrev(remoteheads->item->object.sha1,
                                DEFAULT_ABBREV));
                if (allow_trivial && !fast_forward_only) {
                        /* See if it is really trivial. */
                        git_committer_info(IDENT_ERROR_ON_NO_NAME);
-                       printf("Trying really trivial in-index merge...\n");
+                       printf(_("Trying really trivial in-index merge...\n"));
                        if (!read_tree_trivial(common->item->object.sha1,
                                        head, remoteheads->item->object.sha1))
                                return merge_trivial();
-                       printf("Nope.\n");
+                       printf(_("Nope.\n"));
                }
        } else {
                /*
        }
  
        if (fast_forward_only)
-               die("Not possible to fast-forward, aborting.");
+               die(_("Not possible to fast-forward, aborting."));
  
        /* We are going to make a new commit. */
        git_committer_info(IDENT_ERROR_ON_NO_NAME);
        for (i = 0; i < use_strategies_nr; i++) {
                int ret;
                if (i) {
-                       printf("Rewinding the tree to pristine...\n");
+                       printf(_("Rewinding the tree to pristine...\n"));
                        restore_state();
                }
                if (use_strategies_nr != 1)
-                       printf("Trying merge strategy %s...\n",
+                       printf(_("Trying merge strategy %s...\n"),
                                use_strategies[i]->name);
                /*
                 * Remember which strategy left the state in the working
                restore_state();
                if (use_strategies_nr > 1)
                        fprintf(stderr,
-                               "No merge strategy handled the merge.\n");
+                               _("No merge strategy handled the merge.\n"));
                else
-                       fprintf(stderr, "Merge with strategy %s failed.\n",
+                       fprintf(stderr, _("Merge with strategy %s failed.\n"),
                                use_strategies[0]->name);
                return 2;
        } else if (best_strategy == wt_strategy)
                ; /* We already have its result in the working tree. */
        else {
-               printf("Rewinding the tree to pristine...\n");
+               printf(_("Rewinding the tree to pristine...\n"));
                restore_state();
-               printf("Using the %s to prepare resolving by hand.\n",
+               printf(_("Using the %s to prepare resolving by hand.\n"),
                        best_strategy);
                try_merge_strategy(best_strategy, common, head_arg);
        }
                                sha1_to_hex(j->item->object.sha1));
                fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666);
                if (fd < 0)
-                       die_errno("Could not open '%s' for writing",
+                       die_errno(_("Could not open '%s' for writing"),
                                  git_path("MERGE_HEAD"));
                if (write_in_full(fd, buf.buf, buf.len) != buf.len)
-                       die_errno("Could not write to '%s'", git_path("MERGE_HEAD"));
+                       die_errno(_("Could not write to '%s'"), git_path("MERGE_HEAD"));
                close(fd);
                strbuf_addch(&merge_msg, '\n');
 -              fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
 -              if (fd < 0)
 -                      die_errno(_("Could not open '%s' for writing"),
 -                                git_path("MERGE_MSG"));
 -              if (write_in_full(fd, merge_msg.buf, merge_msg.len) !=
 -                      merge_msg.len)
 -                      die_errno(_("Could not write to '%s'"), git_path("MERGE_MSG"));
 -              close(fd);
 +              write_merge_msg();
                fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666);
                if (fd < 0)
-                       die_errno("Could not open '%s' for writing",
+                       die_errno(_("Could not open '%s' for writing"),
                                  git_path("MERGE_MODE"));
                strbuf_reset(&buf);
                if (!allow_fast_forward)
                        strbuf_addf(&buf, "no-ff");
                if (write_in_full(fd, buf.buf, buf.len) != buf.len)
-                       die_errno("Could not write to '%s'", git_path("MERGE_MODE"));
+                       die_errno(_("Could not write to '%s'"), git_path("MERGE_MODE"));
                close(fd);
        }
  
        if (merge_was_ok) {
-               fprintf(stderr, "Automatic merge went well; "
-                       "stopped before committing as requested\n");
+               fprintf(stderr, _("Automatic merge went well; "
+                       "stopped before committing as requested\n"));
                return 0;
        } else
                return suggest_conflicts(option_renormalize);
diff --combined builtin/notes.c
index a0f310b72956dcb00d2a0899d39ddfb9f7811fa4,a0aa995158c3016875811952b0148ac8c04ce112..d6dcfcb0149ab6dc45f4a71e21cf77d13b494e18
@@@ -146,13 -146,13 +146,13 @@@ static void write_commented_object(int 
        show.err = 0;
        show.git_cmd = 1;
        if (start_command(&show))
-               die("unable to start 'show' for object '%s'",
+               die(_("unable to start 'show' for object '%s'"),
                    sha1_to_hex(object));
  
        /* Open the output as FILE* so strbuf_getline() can be used. */
        show_out = xfdopen(show.out, "r");
        if (show_out == NULL)
-               die_errno("can't fdopen 'show' output fd");
+               die_errno(_("can't fdopen 'show' output fd"));
  
        /* Prepend "# " to each output line and write result to 'fd' */
        while (strbuf_getline(&buf, show_out, '\n') != EOF) {
        }
        strbuf_release(&buf);
        if (fclose(show_out))
-               die_errno("failed to close pipe to 'show' for object '%s'",
+               die_errno(_("failed to close pipe to 'show' for object '%s'"),
                          sha1_to_hex(object));
        if (finish_command(&show))
-               die("failed to finish 'show' for object '%s'",
+               die(_("failed to finish 'show' for object '%s'"),
                    sha1_to_hex(object));
  }
  
@@@ -182,7 -182,7 +182,7 @@@ static void create_note(const unsigned 
                path = git_pathdup("NOTES_EDITMSG");
                fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
                if (fd < 0)
-                       die_errno("could not create file '%s'", path);
+                       die_errno(_("could not create file '%s'"), path);
  
                if (msg->given)
                        write_or_die(fd, msg->buf.buf, msg->buf.len);
                strbuf_reset(&(msg->buf));
  
                if (launch_editor(path, &(msg->buf), NULL)) {
-                       die("Please supply the note contents using either -m" \
-                           " or -F option");
+                       die(_("Please supply the note contents using either -m" \
+                           " or -F option"));
                }
                stripspace(&(msg->buf), 1);
        }
        }
  
        if (!msg->buf.len) {
-               fprintf(stderr, "Removing note for object %s\n",
+               fprintf(stderr, _("Removing note for object %s\n"),
                        sha1_to_hex(object));
                hashclr(result);
        } else {
                if (write_sha1_file(msg->buf.buf, msg->buf.len, blob_type, result)) {
-                       error("unable to write note object");
+                       error(_("unable to write note object"));
                        if (path)
-                               error("The note contents has been left in %s",
+                               error(_("The note contents has been left in %s"),
                                      path);
                        exit(128);
                }
@@@ -258,9 -258,9 +258,9 @@@ static int parse_file_arg(const struct 
                strbuf_addch(&(msg->buf), '\n');
        if (!strcmp(arg, "-")) {
                if (strbuf_read(&(msg->buf), 0, 1024) < 0)
-                       die_errno("cannot read '%s'", arg);
+                       die_errno(_("cannot read '%s'"), arg);
        } else if (strbuf_read_file(&(msg->buf), arg, 1024) < 0)
-               die_errno("could not open or read '%s'", arg);
+               die_errno(_("could not open or read '%s'"), arg);
        stripspace(&(msg->buf), 0);
  
        msg->given = 1;
@@@ -279,10 -279,10 +279,10 @@@ static int parse_reuse_arg(const struc
                strbuf_addch(&(msg->buf), '\n');
  
        if (get_sha1(arg, object))
-               die("Failed to resolve '%s' as a valid ref.", arg);
+               die(_("Failed to resolve '%s' as a valid ref."), arg);
        if (!(buf = read_sha1_file(object, &type, &len)) || !len) {
                free(buf);
-               die("Failed to read object '%s'.", arg);;
+               die(_("Failed to read object '%s'."), arg);;
        }
        strbuf_add(&(msg->buf), buf, len);
        free(buf);
@@@ -306,7 -306,7 +306,7 @@@ void commit_notes(struct notes_tree *t
        if (!t)
                t = &default_notes_tree;
        if (!t->initialized || !t->ref || !*t->ref)
-               die("Cannot commit uninitialized/unreferenced notes tree");
+               die(_("Cannot commit uninitialized/unreferenced notes tree"));
        if (!t->dirty)
                return; /* don't have to commit an unchanged tree */
  
@@@ -347,7 -347,7 +347,7 @@@ static int notes_rewrite_config(const c
                        config_error_nonbool(k);
                c->combine = parse_combine_notes_fn(v);
                if (!c->combine) {
-                       error("Bad notes.rewriteMode value: '%s'", v);
+                       error(_("Bad notes.rewriteMode value: '%s'"), v);
                        return 1;
                }
                return 0;
                if (!prefixcmp(v, "refs/notes/"))
                        string_list_add_refs_by_glob(c->refs, v);
                else
-                       warning("Refusing to rewrite notes in %s"
-                               " (outside of refs/notes/)", v);
+                       warning(_("Refusing to rewrite notes in %s"
+                               " (outside of refs/notes/)"), v);
                return 0;
        }
  
@@@ -382,8 -382,10 +382,10 @@@ struct notes_rewrite_cfg *init_copy_not
                c->mode_from_env = 1;
                c->combine = parse_combine_notes_fn(rewrite_mode_env);
                if (!c->combine)
-                       error("Bad " GIT_NOTES_REWRITE_MODE_ENVIRONMENT
-                             " value: '%s'", rewrite_mode_env);
+                       /* TRANSLATORS: The first %s is the name of the
+                          environment variable, the second %s is its value */
+                       error(_("Bad %s value: '%s'"), GIT_NOTES_REWRITE_MODE_ENVIRONMENT,
+                                       rewrite_mode_env);
        }
        if (rewrite_refs_env) {
                c->refs_from_env = 1;
@@@ -423,7 -425,7 +425,7 @@@ void finish_copy_notes_for_rewrite(stru
        free(c);
  }
  
 -int notes_copy_from_stdin(int force, const char *rewrite_cmd)
 +static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
  {
        struct strbuf buf = STRBUF_INIT;
        struct notes_rewrite_cfg *c = NULL;
  
                split = strbuf_split(&buf, ' ');
                if (!split[0] || !split[1])
-                       die("Malformed input line: '%s'.", buf.buf);
+                       die(_("Malformed input line: '%s'."), buf.buf);
                strbuf_rtrim(split[0]);
                strbuf_rtrim(split[1]);
                if (get_sha1(split[0]->buf, from_obj))
-                       die("Failed to resolve '%s' as a valid ref.", split[0]->buf);
+                       die(_("Failed to resolve '%s' as a valid ref."), split[0]->buf);
                if (get_sha1(split[1]->buf, to_obj))
-                       die("Failed to resolve '%s' as a valid ref.", split[1]->buf);
+                       die(_("Failed to resolve '%s' as a valid ref."), split[1]->buf);
  
                if (rewrite_cmd)
                        err = copy_note_for_rewrite(c, from_obj, to_obj);
                                        combine_notes_overwrite);
  
                if (err) {
-                       error("Failed to copy notes from '%s' to '%s'",
+                       error(_("Failed to copy notes from '%s' to '%s'"),
                              split[0]->buf, split[1]->buf);
                        ret = 1;
                }
@@@ -505,20 -507,20 +507,20 @@@ static int list(int argc, const char **
                                     git_notes_list_usage, 0);
  
        if (1 < argc) {
-               error("too many parameters");
+               error(_("too many parameters"));
                usage_with_options(git_notes_list_usage, options);
        }
  
        t = init_notes_check("list");
        if (argc) {
                if (get_sha1(argv[0], object))
-                       die("Failed to resolve '%s' as a valid ref.", argv[0]);
+                       die(_("Failed to resolve '%s' as a valid ref."), argv[0]);
                note = get_note(t, object);
                if (note) {
                        puts(sha1_to_hex(note));
                        retval = 0;
                } else
-                       retval = error("No note found for object %s.",
+                       retval = error(_("No note found for object %s."),
                                       sha1_to_hex(object));
        } else
                retval = for_each_note(t, 0, list_each_note, NULL);
@@@ -537,16 -539,16 +539,16 @@@ static int add(int argc, const char **a
        const unsigned char *note;
        struct msg_arg msg = { 0, 0, STRBUF_INIT };
        struct option options[] = {
 -              { OPTION_CALLBACK, 'm', "message", &msg, "MSG",
 +              { OPTION_CALLBACK, 'm', "message", &msg, "msg",
                        "note contents as a string", PARSE_OPT_NONEG,
                        parse_msg_arg},
 -              { OPTION_CALLBACK, 'F', "file", &msg, "FILE",
 +              { OPTION_CALLBACK, 'F', "file", &msg, "file",
                        "note contents in a file", PARSE_OPT_NONEG,
                        parse_file_arg},
 -              { OPTION_CALLBACK, 'c', "reedit-message", &msg, "OBJECT",
 +              { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
                        "reuse and edit specified note object", PARSE_OPT_NONEG,
                        parse_reedit_arg},
 -              { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT",
 +              { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
                        "reuse specified note object", PARSE_OPT_NONEG,
                        parse_reuse_arg},
                OPT__FORCE(&force, "replace existing notes"),
                             0);
  
        if (1 < argc) {
-               error("too many parameters");
+               error(_("too many parameters"));
                usage_with_options(git_notes_add_usage, options);
        }
  
        object_ref = argc ? argv[0] : "HEAD";
  
        if (get_sha1(object_ref, object))
-               die("Failed to resolve '%s' as a valid ref.", object_ref);
+               die(_("Failed to resolve '%s' as a valid ref."), object_ref);
  
        t = init_notes_check("add");
        note = get_note(t, object);
  
        if (note) {
                if (!force) {
-                       retval = error("Cannot add notes. Found existing notes "
+                       retval = error(_("Cannot add notes. Found existing notes "
                                       "for object %s. Use '-f' to overwrite "
-                                      "existing notes", sha1_to_hex(object));
+                                      "existing notes"), sha1_to_hex(object));
                        goto out;
                }
-               fprintf(stderr, "Overwriting existing notes for object %s\n",
+               fprintf(stderr, _("Overwriting existing notes for object %s\n"),
                        sha1_to_hex(object));
        }
  
@@@ -618,7 -620,7 +620,7 @@@ static int copy(int argc, const char **
  
        if (from_stdin || rewrite_cmd) {
                if (argc) {
-                       error("too many parameters");
+                       error(_("too many parameters"));
                        usage_with_options(git_notes_copy_usage, options);
                } else {
                        return notes_copy_from_stdin(force, rewrite_cmd);
        }
  
        if (argc < 2) {
-               error("too few parameters");
+               error(_("too few parameters"));
                usage_with_options(git_notes_copy_usage, options);
        }
        if (2 < argc) {
-               error("too many parameters");
+               error(_("too many parameters"));
                usage_with_options(git_notes_copy_usage, options);
        }
  
        if (get_sha1(argv[0], from_obj))
-               die("Failed to resolve '%s' as a valid ref.", argv[0]);
+               die(_("Failed to resolve '%s' as a valid ref."), argv[0]);
  
        object_ref = 1 < argc ? argv[1] : "HEAD";
  
        if (get_sha1(object_ref, object))
-               die("Failed to resolve '%s' as a valid ref.", object_ref);
+               die(_("Failed to resolve '%s' as a valid ref."), object_ref);
  
        t = init_notes_check("copy");
        note = get_note(t, object);
  
        if (note) {
                if (!force) {
-                       retval = error("Cannot copy notes. Found existing "
+                       retval = error(_("Cannot copy notes. Found existing "
                                       "notes for object %s. Use '-f' to "
-                                      "overwrite existing notes",
+                                      "overwrite existing notes"),
                                       sha1_to_hex(object));
                        goto out;
                }
-               fprintf(stderr, "Overwriting existing notes for object %s\n",
+               fprintf(stderr, _("Overwriting existing notes for object %s\n"),
                        sha1_to_hex(object));
        }
  
        from_note = get_note(t, from_obj);
        if (!from_note) {
-               retval = error("Missing notes on source object %s. Cannot "
-                              "copy.", sha1_to_hex(from_obj));
+               retval = error(_("Missing notes on source object %s. Cannot "
+                              "copy."), sha1_to_hex(from_obj));
                goto out;
        }
  
@@@ -682,16 -684,16 +684,16 @@@ static int append_edit(int argc, const 
        const char * const *usage;
        struct msg_arg msg = { 0, 0, STRBUF_INIT };
        struct option options[] = {
 -              { OPTION_CALLBACK, 'm', "message", &msg, "MSG",
 +              { OPTION_CALLBACK, 'm', "message", &msg, "msg",
                        "note contents as a string", PARSE_OPT_NONEG,
                        parse_msg_arg},
 -              { OPTION_CALLBACK, 'F', "file", &msg, "FILE",
 +              { OPTION_CALLBACK, 'F', "file", &msg, "file",
                        "note contents in a file", PARSE_OPT_NONEG,
                        parse_file_arg},
 -              { OPTION_CALLBACK, 'c', "reedit-message", &msg, "OBJECT",
 +              { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
                        "reuse and edit specified note object", PARSE_OPT_NONEG,
                        parse_reedit_arg},
 -              { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT",
 +              { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
                        "reuse specified note object", PARSE_OPT_NONEG,
                        parse_reuse_arg},
                OPT_END()
                             PARSE_OPT_KEEP_ARGV0);
  
        if (2 < argc) {
-               error("too many parameters");
+               error(_("too many parameters"));
                usage_with_options(usage, options);
        }
  
        if (msg.given && edit)
-               fprintf(stderr, "The -m/-F/-c/-C options have been deprecated "
+               fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated "
                        "for the 'edit' subcommand.\n"
-                       "Please use 'git notes add -f -m/-F/-c/-C' instead.\n");
+                       "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"));
  
        object_ref = 1 < argc ? argv[1] : "HEAD";
  
        if (get_sha1(object_ref, object))
-               die("Failed to resolve '%s' as a valid ref.", object_ref);
+               die(_("Failed to resolve '%s' as a valid ref."), object_ref);
  
        t = init_notes_check(argv[0]);
        note = get_note(t, object);
@@@ -750,20 -752,20 +752,20 @@@ static int show(int argc, const char **
                             0);
  
        if (1 < argc) {
-               error("too many parameters");
+               error(_("too many parameters"));
                usage_with_options(git_notes_show_usage, options);
        }
  
        object_ref = argc ? argv[0] : "HEAD";
  
        if (get_sha1(object_ref, object))
-               die("Failed to resolve '%s' as a valid ref.", object_ref);
+               die(_("Failed to resolve '%s' as a valid ref."), object_ref);
  
        t = init_notes_check("show");
        note = get_note(t, object);
  
        if (!note)
-               retval = error("No note found for object %s.",
+               retval = error(_("No note found for object %s."),
                               sha1_to_hex(object));
        else {
                const char *show_args[3] = {"show", sha1_to_hex(note), NULL};
@@@ -819,7 -821,7 +821,7 @@@ static int merge_commit(struct notes_me
        t = xcalloc(1, sizeof(struct notes_tree));
        init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
  
 -      o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, 0);
 +      o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, NULL);
        if (!o->local_ref)
                die("Failed to resolve NOTES_MERGE_REF");
  
@@@ -961,22 -963,22 +963,22 @@@ static int remove_cmd(int argc, const c
                             git_notes_remove_usage, 0);
  
        if (1 < argc) {
-               error("too many parameters");
+               error(_("too many parameters"));
                usage_with_options(git_notes_remove_usage, options);
        }
  
        object_ref = argc ? argv[0] : "HEAD";
  
        if (get_sha1(object_ref, object))
-               die("Failed to resolve '%s' as a valid ref.", object_ref);
+               die(_("Failed to resolve '%s' as a valid ref."), object_ref);
  
        t = init_notes_check("remove");
  
        retval = remove_note(t, object);
        if (retval)
-               fprintf(stderr, "Object %s has no note\n", sha1_to_hex(object));
+               fprintf(stderr, _("Object %s has no note\n"), sha1_to_hex(object));
        else {
-               fprintf(stderr, "Removing note for object %s\n",
+               fprintf(stderr, _("Removing note for object %s\n"),
                        sha1_to_hex(object));
  
                commit_notes(t, "Notes removed by 'git notes remove'");
@@@ -999,7 -1001,7 +1001,7 @@@ static int prune(int argc, const char *
                             0);
  
        if (argc) {
-               error("too many parameters");
+               error(_("too many parameters"));
                usage_with_options(git_notes_prune_usage, options);
        }
  
@@@ -1069,7 -1071,7 +1071,7 @@@ int cmd_notes(int argc, const char **ar
        else if (!strcmp(argv[0], "get-ref"))
                result = get_ref(argc, argv, prefix);
        else {
-               result = error("Unknown subcommand: %s", argv[0]);
+               result = error(_("Unknown subcommand: %s"), argv[0]);
                usage_with_options(git_notes_usage, options);
        }
  
diff --combined builtin/push.c
index 6f6a66f9862d5ee5eaf4a4ce07934832569eacf9,8c8d8c717be6be5b4c701d6af53307ac684c54a5..9cebf9ea234d968eab638f7dcdc65370f77c0047
@@@ -40,7 -40,7 +40,7 @@@ static void set_refspecs(const char **r
                        char *tag;
                        int len;
                        if (nr <= ++i)
-                               die("tag shorthand without <tag>");
+                               die(_("tag shorthand without <tag>"));
                        len = strlen(refs[i]) + 11;
                        if (deleterefs) {
                                tag = xmalloc(len+1);
                        strcat(delref, ref);
                        ref = delref;
                } else if (deleterefs)
-                       die("--delete only accepts plain target ref names");
+                       die(_("--delete only accepts plain target ref names"));
                add_refspec(ref);
        }
  }
  
 -static void setup_push_tracking(void)
 +static void setup_push_upstream(struct remote *remote)
  {
        struct strbuf refspec = STRBUF_INIT;
        struct branch *branch = branch_get(NULL);
        if (!branch)
-               die("You are not currently on a branch.\n"
 -              die(_("You are not currently on a branch."));
++              die(_("You are not currently on a branch.\n"
 +                  "To push the history leading to the current (detached HEAD)\n"
 +                  "state now, use\n"
 +                  "\n"
-                   "    git push %s HEAD:<name-of-remote-branch>\n",
++                  "    git push %s HEAD:<name-of-remote-branch>\n"),
 +                  remote->name);
        if (!branch->merge_nr || !branch->merge)
-               die("The current branch %s has no upstream branch.\n"
 -              die(_("The current branch %s is not tracking anything."),
++              die(_("The current branch %s has no upstream branch.\n"
 +                  "To push the current branch and set the remote as upstream, use\n"
 +                  "\n"
-                   "    git push --set-upstream %s %s\n",
++                  "    git push --set-upstream %s %s\n"),
 +                  branch->name,
 +                  remote->name,
                    branch->name);
        if (branch->merge_nr != 1)
-               die("The current branch %s has multiple upstream branches, "
-                   "refusing to push.", branch->name);
 -              die(_("The current branch %s is tracking multiple branches, "
++              die(_("The current branch %s has multiple upstream branches, "
+                   "refusing to push."), branch->name);
        strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
        add_refspec(refspec.buf);
  }
  
 -static void setup_default_push_refspecs(void)
 +static void setup_default_push_refspecs(struct remote *remote)
  {
        switch (push_default) {
        default:
@@@ -98,8 -88,8 +98,8 @@@
                add_refspec(":");
                break;
  
 -      case PUSH_DEFAULT_TRACKING:
 -              setup_push_tracking();
 +      case PUSH_DEFAULT_UPSTREAM:
 +              setup_push_upstream(remote);
                break;
  
        case PUSH_DEFAULT_CURRENT:
                break;
  
        case PUSH_DEFAULT_NOTHING:
-               die("You didn't specify any refspecs to push, and "
-                   "push.default is \"nothing\".");
+               die(_("You didn't specify any refspecs to push, and "
+                   "push.default is \"nothing\"."));
                break;
        }
  }
@@@ -127,11 -117,11 +127,11 @@@ static int push_with_options(struct tra
                transport_set_option(transport, TRANS_OPT_THIN, "yes");
  
        if (verbosity > 0)
-               fprintf(stderr, "Pushing to %s\n", transport->url);
+               fprintf(stderr, _("Pushing to %s\n"), transport->url);
        err = transport_push(transport, refspec_nr, refspec, flags,
                             &nonfastforward);
        if (err != 0)
-               error("failed to push some refs to '%s'", transport->url);
+               error(_("failed to push some refs to '%s'"), transport->url);
  
        err |= transport_disconnect(transport);
  
                return 0;
  
        if (nonfastforward && advice_push_nonfastforward) {
-               fprintf(stderr, "To prevent you from losing history, non-fast-forward updates were rejected\n"
+               fprintf(stderr, _("To prevent you from losing history, non-fast-forward updates were rejected\n"
                                "Merge the remote changes (e.g. 'git pull') before pushing again.  See the\n"
-                               "'Note about fast-forwards' section of 'git push --help' for details.\n");
+                               "'Note about fast-forwards' section of 'git push --help' for details.\n"));
        }
  
        return 1;
@@@ -156,15 -146,8 +156,15 @@@ static int do_push(const char *repo, in
  
        if (!remote) {
                if (repo)
-                       die("bad repository '%s'", repo);
-               die("No configured push destination.\n"
+                       die(_("bad repository '%s'"), repo);
 -              die(_("No destination configured to push to."));
++              die(_("No configured push destination.\n"
 +                  "Either specify the URL from the command-line or configure a remote repository using\n"
 +                  "\n"
 +                  "    git remote add <name> <url>\n"
 +                  "\n"
 +                  "and then push using the remote name\n"
 +                  "\n"
-                   "    git push <name>\n");
++                  "    git push <name>\n"));
        }
  
        if (remote->mirror)
  
        if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
                if (!strcmp(*refspec, "refs/tags/*"))
-                       return error("--all and --tags are incompatible");
-               return error("--all can't be combined with refspecs");
+                       return error(_("--all and --tags are incompatible"));
+               return error(_("--all can't be combined with refspecs"));
        }
  
        if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) {
                if (!strcmp(*refspec, "refs/tags/*"))
-                       return error("--mirror and --tags are incompatible");
-               return error("--mirror can't be combined with refspecs");
+                       return error(_("--mirror and --tags are incompatible"));
+               return error(_("--mirror can't be combined with refspecs"));
        }
  
        if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
                                (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
-               return error("--all and --mirror are incompatible");
+               return error(_("--all and --mirror are incompatible"));
        }
  
        if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
                        refspec = remote->push_refspec;
                        refspec_nr = remote->push_refspec_nr;
                } else if (!(flags & TRANSPORT_PUSH_MIRROR))
 -                      setup_default_push_refspecs();
 +                      setup_default_push_refspecs(remote);
        }
        errs = 0;
        if (remote->pushurl_nr) {
@@@ -245,14 -228,13 +245,14 @@@ int cmd_push(int argc, const char **arg
                OPT_END()
        };
  
 +      packet_trace_identity("push");
        git_config(git_default_config, NULL);
        argc = parse_options(argc, argv, prefix, options, push_usage, 0);
  
        if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
-               die("--delete is incompatible with --all, --mirror and --tags");
+               die(_("--delete is incompatible with --all, --mirror and --tags"));
        if (deleterefs && argc < 2)
-               die("--delete doesn't make sense without any refs");
+               die(_("--delete doesn't make sense without any refs"));
  
        if (tags)
                add_refspec("refs/tags/*");
diff --combined builtin/reset.c
index eb5f98c16320cd4eded3c842ec1d019e75c5b9c3,1fe5b0f9ef66d70ba8b39291e9b4a6fbebc20f30..98bca044c1267fa63cb084a45aaf621e85f7d9b6
@@@ -7,7 -7,7 +7,7 @@@
   *
   * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
   */
 -#include "cache.h"
 +#include "builtin.h"
  #include "tag.h"
  #include "object.h"
  #include "commit.h"
@@@ -30,7 -30,7 +30,7 @@@ static const char * const git_reset_usa
  
  enum reset_type { MIXED, SOFT, HARD, MERGE, KEEP, NONE };
  static const char *reset_type_names[] = {
-       "mixed", "soft", "hard", "merge", "keep", NULL
+       N_("mixed"), N_("soft"), N_("hard"), N_("merge"), N_("keep"), NULL
  };
  
  static char *args_to_str(const char **argv)
@@@ -92,20 -92,20 +92,20 @@@ static int reset_index_file(const unsig
        if (reset_type == KEEP) {
                unsigned char head_sha1[20];
                if (get_sha1("HEAD", head_sha1))
-                       return error("You do not have a valid HEAD.");
+                       return error(_("You do not have a valid HEAD."));
                if (!fill_tree_descriptor(desc, head_sha1))
-                       return error("Failed to find tree of HEAD.");
+                       return error(_("Failed to find tree of HEAD."));
                nr++;
                opts.fn = twoway_merge;
        }
  
        if (!fill_tree_descriptor(desc + nr - 1, sha1))
-               return error("Failed to find tree of %s.", sha1_to_hex(sha1));
+               return error(_("Failed to find tree of %s."), sha1_to_hex(sha1));
        if (unpack_trees(nr, desc, &opts))
                return -1;
        if (write_cache(newfd, active_cache, active_nr) ||
            commit_locked_index(lock))
-               return error("Could not write new index file.");
+               return error(_("Could not write new index file."));
  
        return 0;
  }
@@@ -115,7 -115,7 +115,7 @@@ static void print_new_head_line(struct 
        const char *hex, *body;
  
        hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
-       printf("HEAD is now at %s", hex);
+       printf(_("HEAD is now at %s"), hex);
        body = strstr(commit->buffer, "\n\n");
        if (body) {
                const char *eol;
@@@ -139,10 -139,10 +139,10 @@@ static int update_index_refresh(int fd
        }
  
        if (read_cache() < 0)
-               return error("Could not read index");
+               return error(_("Could not read index"));
  
        result = refresh_index(&the_index, (flags), NULL, NULL,
-                              "Unstaged changes after reset:") ? 1 : 0;
+                              _("Unstaged changes after reset:")) ? 1 : 0;
        if (write_cache(fd, active_cache, active_nr) ||
                        commit_locked_index(index_lock))
                return error ("Could not refresh index");
@@@ -167,7 -167,7 +167,7 @@@ static void update_index_from_diff(stru
                        ce = make_cache_entry(one->mode, one->sha1, one->path,
                                0, 0);
                        if (!ce)
-                               die("make_cache_entry failed for path '%s'",
+                               die(_("make_cache_entry failed for path '%s'"),
                                    one->path);
                        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD |
                                ADD_CACHE_OK_TO_REPLACE);
@@@ -222,14 -222,14 +222,14 @@@ static void prepend_reflog_action(cons
        if (!rla)
                rla = sep = "";
        if (snprintf(buf, size, "%s%s%s", rla, sep, action) >= size)
-               warning("Reflog action message too long: %.*s...", 50, buf);
+               warning(_("Reflog action message too long: %.*s..."), 50, buf);
  }
  
  static void die_if_unmerged_cache(int reset_type)
  {
        if (is_merge() || read_cache() < 0 || unmerged_cache())
-               die("Cannot do a %s reset in the middle of a merge.",
-                   reset_type_names[reset_type]);
+               die(_("Cannot do a %s reset in the middle of a merge."),
+                   _(reset_type_names[reset_type]));
  
  }
  
@@@ -300,16 -300,16 +300,16 @@@ int cmd_reset(int argc, const char **ar
        }
  
        if (get_sha1(rev, sha1))
-               die("Failed to resolve '%s' as a valid ref.", rev);
+               die(_("Failed to resolve '%s' as a valid ref."), rev);
  
        commit = lookup_commit_reference(sha1);
        if (!commit)
-               die("Could not parse object '%s'.", rev);
+               die(_("Could not parse object '%s'."), rev);
        hashcpy(sha1, commit->object.sha1);
  
        if (patch_mode) {
                if (reset_type != NONE)
-                       die("--patch is incompatible with --{hard,mixed,soft}");
+                       die(_("--patch is incompatible with --{hard,mixed,soft}"));
                return interactive_reset(rev, argv + i, prefix);
        }
  
         * affecting the working tree nor HEAD. */
        if (i < argc) {
                if (reset_type == MIXED)
-                       warning("--mixed with paths is deprecated; use 'git reset -- <paths>' instead.");
+                       warning(_("--mixed with paths is deprecated; use 'git reset -- <paths>' instead."));
                else if (reset_type != NONE)
-                       die("Cannot do %s reset with paths.",
-                                       reset_type_names[reset_type]);
+                       die(_("Cannot do %s reset with paths."),
+                                       _(reset_type_names[reset_type]));
                return read_from_tree(prefix, argv + i, sha1,
                                quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
        }
                setup_work_tree();
  
        if (reset_type == MIXED && is_bare_repository())
-               die("%s reset is not allowed in a bare repository",
-                   reset_type_names[reset_type]);
+               die(_("%s reset is not allowed in a bare repository"),
+                   _(reset_type_names[reset_type]));
  
        /* Soft reset does not touch the index file nor the working tree
         * at all, but requires them in a good order.  Other resets reset
                if (reset_type == KEEP)
                        err = err || reset_index_file(sha1, MIXED, quiet);
                if (err)
-                       die("Could not reset index file to revision '%s'.", rev);
+                       die(_("Could not reset index file to revision '%s'."), rev);
        }
  
        /* Any resets update HEAD to the head being switched to,
diff --combined builtin/revert.c
index c57b872fe114145ec82bf33717c2a8d7f0982204,98dfd4d131444e0b1893d734b16a231781024321..2bb13ebb1de48e793e01d18ced29a468aa273b34
@@@ -3,6 -3,7 +3,6 @@@
  #include "object.h"
  #include "commit.h"
  #include "tag.h"
 -#include "wt-status.h"
  #include "run-command.h"
  #include "exec_cmd.h"
  #include "utf8.h"
@@@ -95,7 -96,7 +95,7 @@@ static void parse_args(int argc, const 
                        OPT_END(),
                };
                if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
-                       die("program error");
+                       die(_("program error"));
        }
  
        commit_argc = parse_options(argc, argv, NULL, options, usage_str,
@@@ -167,7 -168,7 +167,7 @@@ static char *get_encoding(const char *m
        const char *p = message, *eol;
  
        if (!p)
-               die ("Could not read commit message of %s",
+               die (_("Could not read commit message of %s"),
                                sha1_to_hex(commit->object.sha1));
        while (*p && *p != '\n') {
                for (eol = p + 1; *eol && *eol != '\n'; eol++)
@@@ -197,20 -198,54 +197,20 @@@ static void add_message_to_msg(struct s
        strbuf_addstr(msgbuf, p);
  }
  
 -static void set_author_ident_env(const char *message)
 +static void write_cherry_pick_head(void)
  {
 -      const char *p = message;
 -      if (!p)
 -              die (_("Could not read commit message of %s"),
 -                              sha1_to_hex(commit->object.sha1));
 -      while (*p && *p != '\n') {
 -              const char *eol;
 -
 -              for (eol = p; *eol && *eol != '\n'; eol++)
 -                      ; /* do nothing */
 -              if (!prefixcmp(p, "author ")) {
 -                      char *line, *pend, *email, *timestamp;
 -
 -                      p += 7;
 -                      line = xmemdupz(p, eol - p);
 -                      email = strchr(line, '<');
 -                      if (!email)
 -                              die (_("Could not extract author email from %s"),
 -                                      sha1_to_hex(commit->object.sha1));
 -                      if (email == line)
 -                              pend = line;
 -                      else
 -                              for (pend = email; pend != line + 1 &&
 -                                              isspace(pend[-1]); pend--);
 -                                      ; /* do nothing */
 -                      *pend = '\0';
 -                      email++;
 -                      timestamp = strchr(email, '>');
 -                      if (!timestamp)
 -                              die (_("Could not extract author time from %s"),
 -                                      sha1_to_hex(commit->object.sha1));
 -                      *timestamp = '\0';
 -                      for (timestamp++; *timestamp && isspace(*timestamp);
 -                                      timestamp++)
 -                              ; /* do nothing */
 -                      setenv("GIT_AUTHOR_NAME", line, 1);
 -                      setenv("GIT_AUTHOR_EMAIL", email, 1);
 -                      setenv("GIT_AUTHOR_DATE", timestamp, 1);
 -                      free(line);
 -                      return;
 -              }
 -              p = eol;
 -              if (*p == '\n')
 -                      p++;
 -      }
 -      die (_("No author information found in %s"),
 -                      sha1_to_hex(commit->object.sha1));
 +      int fd;
 +      struct strbuf buf = STRBUF_INIT;
 +
 +      strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1));
 +
 +      fd = open(git_path("CHERRY_PICK_HEAD"), O_WRONLY | O_CREAT, 0666);
 +      if (fd < 0)
-               die_errno("Could not open '%s' for writing",
++              die_errno(_("Could not open '%s' for writing"),
 +                        git_path("CHERRY_PICK_HEAD"));
 +      if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))
-               die_errno("Could not write to '%s'", git_path("CHERRY_PICK_HEAD"));
++              die_errno(_("Could not write to '%s'"), git_path("CHERRY_PICK_HEAD"));
 +      strbuf_release(&buf);
  }
  
  static void advise(const char *advice, ...)
@@@ -228,18 -263,15 +228,18 @@@ static void print_advice(void
  
        if (msg) {
                fprintf(stderr, "%s\n", msg);
 +              /*
 +               * A conflict has occured but the porcelain
 +               * (typically rebase --interactive) wants to take care
 +               * of the commit itself so remove CHERRY_PICK_HEAD
 +               */
 +              unlink(git_path("CHERRY_PICK_HEAD"));
                return;
        }
  
        advise("after resolving the conflicts, mark the corrected paths");
        advise("with 'git add <paths>' or 'git rm <paths>'");
 -
 -      if (action == CHERRY_PICK)
 -              advise("and commit the result with 'git commit -c %s'",
 -                     find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
 +      advise("and commit the result with 'git commit'");
  }
  
  static void write_message(struct strbuf *msgbuf, const char *filename)
        int msg_fd = hold_lock_file_for_update(&msg_file, filename,
                                               LOCK_DIE_ON_ERROR);
        if (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)
-               die_errno("Could not write to %s.", filename);
+               die_errno(_("Could not write to %s."), filename);
        strbuf_release(msgbuf);
        if (commit_lock_file(&msg_file) < 0)
-               die("Error wrapping up %s", filename);
+               die(_("Error wrapping up %s"), filename);
  }
  
  static struct tree *empty_tree(void)
@@@ -270,11 -302,19 +270,19 @@@ static NORETURN void die_dirty_index(co
        if (read_cache_unmerged()) {
                die_resolve_conflict(me);
        } else {
-               if (advice_commit_before_merge)
-                       die("Your local changes would be overwritten by %s.\n"
-                           "Please, commit your changes or stash them to proceed.", me);
-               else
-                       die("Your local changes would be overwritten by %s.\n", me);
+               if (advice_commit_before_merge) {
+                       if (action == REVERT)
+                               die(_("Your local changes would be overwritten by revert.\n"
+                                         "Please, commit your changes or stash them to proceed."));
+                       else
+                               die(_("Your local changes would be overwritten by cherry-pick.\n"
+                                         "Please, commit your changes or stash them to proceed."));
+               } else {
+                       if (action == REVERT)
+                               die(_("Your local changes would be overwritten by revert.\n"));
+                       else
+                               die(_("Your local changes would be overwritten by cherry-pick.\n"));
+               }
        }
  }
  
@@@ -322,7 -362,8 +330,8 @@@ static int do_recursive_merge(struct co
        if (active_cache_changed &&
            (write_cache(index_fd, active_cache, active_nr) ||
             commit_locked_index(&index_lock)))
-               die("%s: Unable to write new index file", me);
+               /* TRANSLATORS: %s will be "revert" or "cherry-pick" */
+               die(_("%s: Unable to write new index file"), me);
        rollback_lock_file(&index_lock);
  
        if (!clean) {
@@@ -388,10 -429,10 +397,10 @@@ static int do_pick_commit(void
                 * to work on.
                 */
                if (write_cache_as_tree(head, 0, NULL))
-                       die ("Your index file is unmerged.");
+                       die (_("Your index file is unmerged."));
        } else {
                if (get_sha1("HEAD", head))
-                       die ("You do not have a valid HEAD");
+                       die (_("You do not have a valid HEAD"));
                if (index_differs_from("HEAD", 0))
                        die_dirty_index(me);
        }
  
        if (!commit->parents) {
                if (action == REVERT)
-                       die ("Cannot revert a root commit");
+                       die (_("Cannot revert a root commit"));
                parent = NULL;
        }
        else if (commit->parents->next) {
                struct commit_list *p;
  
                if (!mainline)
-                       die("Commit %s is a merge but no -m option was given.",
+                       die(_("Commit %s is a merge but no -m option was given."),
                            sha1_to_hex(commit->object.sha1));
  
                for (cnt = 1, p = commit->parents;
                     cnt++)
                        p = p->next;
                if (cnt != mainline || !p)
-                       die("Commit %s does not have parent %d",
+                       die(_("Commit %s does not have parent %d"),
                            sha1_to_hex(commit->object.sha1), mainline);
                parent = p->item;
        } else if (0 < mainline)
-               die("Mainline was specified but commit %s is not a merge.",
+               die(_("Mainline was specified but commit %s is not a merge."),
                    sha1_to_hex(commit->object.sha1));
        else
                parent = commit->parents->item;
                return fast_forward_to(commit->object.sha1, head);
  
        if (parent && parse_commit(parent) < 0)
-               die("%s: cannot parse parent commit %s",
+               /* TRANSLATORS: The first %s will be "revert" or
+                  "cherry-pick", the second %s a SHA1 */
+               die(_("%s: cannot parse parent commit %s"),
                    me, sha1_to_hex(parent->object.sha1));
  
        if (get_message(commit->buffer, &msg) != 0)
-               die("Cannot get commit message for %s",
+               die(_("Cannot get commit message for %s"),
                                sha1_to_hex(commit->object.sha1));
  
        /*
                base_label = msg.parent_label;
                next = commit;
                next_label = msg.label;
 -              set_author_ident_env(msg.message);
                add_message_to_msg(&msgbuf, msg.message);
                if (no_replay) {
                        strbuf_addstr(&msgbuf, "(cherry picked from commit ");
                        strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
                        strbuf_addstr(&msgbuf, ")\n");
                }
 +              if (!no_commit)
 +                      write_cherry_pick_head();
        }
  
        if (!strategy || !strcmp(strategy, "recursive") || action == REVERT) {
        }
  
        if (res) {
-               error("could not %s %s... %s",
-                     action == REVERT ? "revert" : "apply",
+               error(action == REVERT
+                     ? _("could not revert %s... %s")
+                     : _("could not apply %s... %s"),
                      find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV),
                      msg.subject);
                print_advice();
@@@ -525,10 -568,10 +537,10 @@@ static void prepare_revs(struct rev_inf
                usage(*revert_or_cherry_pick_usage());
  
        if (prepare_revision_walk(revs))
-               die("revision walk setup failed");
+               die(_("revision walk setup failed"));
  
        if (!revs->commits)
-               die("empty commit set passed");
+               die(_("empty commit set passed"));
  }
  
  static void read_and_refresh_cache(const char *me)
        static struct lock_file index_lock;
        int index_fd = hold_locked_index(&index_lock, 0);
        if (read_index_preload(&the_index, NULL) < 0)
-               die("git %s: failed to read the index", me);
+               die(_("git %s: failed to read the index"), me);
        refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
        if (the_index.cache_changed) {
                if (write_index(&the_index, index_fd) ||
                    commit_locked_index(&index_lock))
-                       die("git %s: failed to refresh the index", me);
+                       die(_("git %s: failed to refresh the index"), me);
        }
        rollback_lock_file(&index_lock);
  }
@@@ -557,13 -600,13 +569,13 @@@ static int revert_or_cherry_pick(int ar
  
        if (allow_ff) {
                if (signoff)
-                       die("cherry-pick --ff cannot be used with --signoff");
+                       die(_("cherry-pick --ff cannot be used with --signoff"));
                if (no_commit)
-                       die("cherry-pick --ff cannot be used with --no-commit");
+                       die(_("cherry-pick --ff cannot be used with --no-commit"));
                if (no_replay)
-                       die("cherry-pick --ff cannot be used with -x");
+                       die(_("cherry-pick --ff cannot be used with -x"));
                if (edit)
-                       die("cherry-pick --ff cannot be used with --edit");
+                       die(_("cherry-pick --ff cannot be used with --edit"));
        }
  
        read_and_refresh_cache(me);
diff --combined builtin/tag.c
index 7cf48abca857f049243dfab7c95fea70d216ea93,4242e271aea68c8702b61e0829f1ff40cfb7ca2e..b66b34a1820b3c258ddd85180442df865becee15
@@@ -118,12 -118,12 +118,12 @@@ static int for_each_tag_name(const cha
        for (p = argv; *p; p++) {
                if (snprintf(ref, sizeof(ref), "refs/tags/%s", *p)
                                        >= sizeof(ref)) {
-                       error("tag name too long: %.*s...", 50, *p);
+                       error(_("tag name too long: %.*s..."), 50, *p);
                        had_error = 1;
                        continue;
                }
                if (!resolve_ref(ref, sha1, 1, NULL)) {
-                       error("tag '%s' not found.", *p);
+                       error(_("tag '%s' not found."), *p);
                        had_error = 1;
                        continue;
                }
@@@ -138,7 -138,7 +138,7 @@@ static int delete_tag(const char *name
  {
        if (delete_ref(ref, sha1, 0))
                return 1;
-       printf("Deleted tag '%s' (was %s)\n", name, find_unique_abbrev(sha1, DEFAULT_ABBREV));
+       printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(sha1, DEFAULT_ABBREV));
        return 0;
  }
  
@@@ -150,7 -150,7 +150,7 @@@ static int verify_tag(const char *name
        argv_verify_tag[2] = sha1_to_hex(sha1);
  
        if (run_command_v_opt(argv_verify_tag, RUN_GIT_CMD))
-               return error("could not verify the tag '%s'", name);
+               return error(_("could not verify the tag '%s'"), name);
        return 0;
  }
  
@@@ -165,7 -165,7 +165,7 @@@ static int do_sign(struct strbuf *buffe
        if (!*signingkey) {
                if (strlcpy(signingkey, git_committer_info(IDENT_ERROR_ON_NO_NAME),
                                sizeof(signingkey)) > sizeof(signingkey) - 1)
-                       return error("committer info too long.");
+                       return error(_("committer info too long."));
                bracket = strchr(signingkey, '>');
                if (bracket)
                        bracket[1] = '\0';
        args[3] = NULL;
  
        if (start_command(&gpg))
-               return error("could not run gpg.");
+               return error(_("could not run gpg."));
  
        if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
                close(gpg.in);
                close(gpg.out);
                finish_command(&gpg);
-               return error("gpg did not accept the tag data");
+               return error(_("gpg did not accept the tag data"));
        }
        close(gpg.in);
        len = strbuf_read(buffer, gpg.out, 1024);
        close(gpg.out);
  
        if (finish_command(&gpg) || !len || len < 0)
-               return error("gpg failed to sign the tag");
+               return error(_("gpg failed to sign the tag"));
  
        /* Strip CR from the line endings, in case we are on Windows. */
        for (i = j = 0; i < buffer->len; i++)
  }
  
  static const char tag_template[] =
-       "\n"
+       N_("\n"
        "#\n"
        "# Write a tag message\n"
-       "#\n";
+       "#\n");
  
  static void set_signingkey(const char *value)
  {
        if (strlcpy(signingkey, value, sizeof(signingkey)) >= sizeof(signingkey))
-               die("signing key value too long (%.10s...)", value);
+               die(_("signing key value too long (%.10s...)"), value);
  }
  
  static int git_tag_config(const char *var, const char *value, void *cb)
@@@ -261,9 -261,9 +261,9 @@@ static void write_tag_body(int fd, cons
  static int build_tag_object(struct strbuf *buf, int sign, unsigned char *result)
  {
        if (sign && do_sign(buf) < 0)
-               return error("unable to sign the tag");
+               return error(_("unable to sign the tag"));
        if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
-               return error("unable to write tag file");
+               return error(_("unable to write tag file"));
        return 0;
  }
  
@@@ -278,7 -278,7 +278,7 @@@ static void create_tag(const unsigned c
  
        type = sha1_object_info(object, NULL);
        if (type <= OBJ_NONE)
-           die("bad object type.");
+           die(_("bad object type."));
  
        header_len = snprintf(header_buf, sizeof(header_buf),
                          "object %s\n"
                          git_committer_info(IDENT_ERROR_ON_NO_NAME));
  
        if (header_len > sizeof(header_buf) - 1)
-               die("tag header too big.");
+               die(_("tag header too big."));
  
        if (!message) {
                int fd;
                path = git_pathdup("TAG_EDITMSG");
                fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
                if (fd < 0)
-                       die_errno("could not create file '%s'", path);
+                       die_errno(_("could not create file '%s'"), path);
  
                if (!is_null_sha1(prev))
                        write_tag_body(fd, prev);
                else
-                       write_or_die(fd, tag_template, strlen(tag_template));
+                       write_or_die(fd, _(tag_template), strlen(_(tag_template)));
                close(fd);
  
                if (launch_editor(path, buf, NULL)) {
                        fprintf(stderr,
-                       "Please supply the message using either -m or -F option.\n");
+                       _("Please supply the message using either -m or -F option.\n"));
                        exit(1);
                }
        }
        stripspace(buf, 1);
  
        if (!message && !buf->len)
-               die("no tag message?");
+               die(_("no tag message?"));
  
        strbuf_insert(buf, 0, header_buf, header_len);
  
        if (build_tag_object(buf, sign, result) < 0) {
                if (path)
-                       fprintf(stderr, "The tag message has been left in %s\n",
+                       fprintf(stderr, _("The tag message has been left in %s\n"),
                                path);
                exit(128);
        }
@@@ -376,7 -376,7 +376,7 @@@ int cmd_tag(int argc, const char **argv
                OPT_GROUP("Tag creation options"),
                OPT_BOOLEAN('a', NULL, &annotate,
                                        "annotated tag, needs a message"),
 -              OPT_CALLBACK('m', NULL, &msg, "MESSAGE",
 +              OPT_CALLBACK('m', NULL, &msg, "message",
                             "tag message", parse_msg_arg),
                OPT_FILENAME('F', NULL, &msgfile, "read message from file"),
                OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"),
                return list_tags(argv[0], lines == -1 ? 0 : lines,
                                 with_commit);
        if (lines != -1)
-               die("-n option is only allowed with -l.");
+               die(_("-n option is only allowed with -l."));
        if (with_commit)
-               die("--contains option is only allowed with -l.");
+               die(_("--contains option is only allowed with -l."));
        if (delete)
                return for_each_tag_name(argv, delete_tag);
        if (verify)
  
        if (msg.given || msgfile) {
                if (msg.given && msgfile)
-                       die("only one -F or -m option is allowed.");
+                       die(_("only one -F or -m option is allowed."));
                annotate = 1;
                if (msg.given)
                        strbuf_addbuf(&buf, &(msg.buf));
                else {
                        if (!strcmp(msgfile, "-")) {
                                if (strbuf_read(&buf, 0, 1024) < 0)
-                                       die_errno("cannot read '%s'", msgfile);
+                                       die_errno(_("cannot read '%s'"), msgfile);
                        } else {
                                if (strbuf_read_file(&buf, msgfile, 1024) < 0)
-                                       die_errno("could not open or read '%s'",
+                                       die_errno(_("could not open or read '%s'"),
                                                msgfile);
                        }
                }
  
        object_ref = argc == 2 ? argv[1] : "HEAD";
        if (argc > 2)
-               die("too many params");
+               die(_("too many params"));
  
        if (get_sha1(object_ref, object))
-               die("Failed to resolve '%s' as a valid ref.", object_ref);
+               die(_("Failed to resolve '%s' as a valid ref."), object_ref);
  
        if (snprintf(ref, sizeof(ref), "refs/tags/%s", tag) > sizeof(ref) - 1)
-               die("tag name too long: %.*s...", 50, tag);
+               die(_("tag name too long: %.*s..."), 50, tag);
        if (check_ref_format(ref))
-               die("'%s' is not a valid tag name.", tag);
+               die(_("'%s' is not a valid tag name."), tag);
  
        if (!resolve_ref(ref, prev, 1, NULL))
                hashclr(prev);
        else if (!force)
-               die("tag '%s' already exists", tag);
+               die(_("tag '%s' already exists"), tag);
  
        if (annotate)
                create_tag(object, tag, &buf, msg.given || msgfile,
  
        lock = lock_any_ref_for_update(ref, prev, 0);
        if (!lock)
-               die("%s: cannot lock the ref", ref);
+               die(_("%s: cannot lock the ref"), ref);
        if (write_ref_sha1(lock, object, NULL) < 0)
-               die("%s: cannot update the ref", ref);
+               die(_("%s: cannot update the ref"), ref);
        if (force && hashcmp(prev, object))
-               printf("Updated tag '%s' (was %s)\n", tag, find_unique_abbrev(prev, DEFAULT_ABBREV));
+               printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV));
  
        strbuf_release(&buf);
        return 0;
diff --combined t/t0001-init.sh
index ce4ba1379ef05066cc697cdc7fdf53f8c40f58ee,dd4c00d14b82b7289e27b4da816be263629699f1..0ee9f179939f073ea8e918a6a94328daf88e8d8a
@@@ -47,7 -47,7 +47,7 @@@ test_expect_success 'plain nested in ba
  
  test_expect_success 'plain through aliased command, outside any git repo' '
        (
 -              sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG_NOGLOBAL &&
 +              sane_unset GIT_DIR GIT_WORK_TREE &&
                HOME=$(pwd)/alias-config &&
                export HOME &&
                mkdir alias-config &&
@@@ -180,7 -180,7 +180,7 @@@ test_expect_success 'GIT_DIR & GIT_WORK
        fi
  '
  
- test_expect_success 'reinit' '
+ test_expect_success C_LOCALE_OUTPUT 'reinit' '
  
        (
                sane_unset GIT_CONFIG GIT_WORK_TREE GIT_CONFIG &&
@@@ -231,6 -231,7 +231,6 @@@ test_expect_success 'init with init.tem
                git config -f "$test_config"  init.templatedir "${HOME}/templatedir-source" &&
                mkdir templatedir-set &&
                cd templatedir-set &&
 -              sane_unset GIT_CONFIG_NOGLOBAL &&
                sane_unset GIT_TEMPLATE_DIR &&
                NO_SET_GIT_TEMPLATE_DIR=t &&
                export NO_SET_GIT_TEMPLATE_DIR &&
  test_expect_success 'init --bare/--shared overrides system/global config' '
        (
                test_config="$HOME"/.gitconfig &&
 -              sane_unset GIT_CONFIG_NOGLOBAL &&
                git config -f "$test_config" core.bare false &&
                git config -f "$test_config" core.sharedRepository 0640 &&
                mkdir init-bare-shared-override &&
  test_expect_success 'init honors global core.sharedRepository' '
        (
                test_config="$HOME"/.gitconfig &&
 -              sane_unset GIT_CONFIG_NOGLOBAL &&
                git config -f "$test_config" core.sharedRepository 0666 &&
                mkdir shared-honor-global &&
                cd shared-honor-global &&
diff --combined t/t3200-branch.sh
index 78ce09f9d788203ebea280cc94c8098c9043311f,940d7ae1fe4931bdced41fca53521f12af6bbf5e..286a2a68692dd7a70e34851f75098506a1fc783a
@@@ -203,7 -203,7 +203,7 @@@ test_expect_success 'test deleting bran
       test -z "$(git config branch.my7.remote)" &&
       test -z "$(git config branch.my7.merge)"'
  
- test_expect_success 'test deleting branch without config' \
+ test_expect_success C_LOCALE_OUTPUT 'test deleting branch without config' \
      'git branch my7 s &&
       sha1=$(git rev-parse my7 | cut -c 1-7) &&
       test "$(git branch -d my7 2>&1)" = "Deleted branch my7 (was $sha1)."'
@@@ -223,11 -223,6 +223,11 @@@ test_expect_success 
      'branch from non-branch HEAD w/--track causes failure' \
      'test_must_fail git branch --track my10 HEAD^'
  
 +test_expect_success \
 +    'branch from tag w/--track causes failure' \
 +    'git tag foobar &&
 +     test_must_fail git branch --track my11 foobar'
 +
  # Keep this test last, as it changes the current branch
  cat >expect <<EOF
  0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000    branch: Created from master
@@@ -493,15 -488,6 +493,15 @@@ test_expect_success 'autosetuprebase al
        test "z$(git config branch.myr20.rebase)" = z
  '
  
 +test_expect_success 'autosetuprebase always on detached HEAD' '
 +      git config branch.autosetupmerge always &&
 +      test_when_finished git checkout master &&
 +      git checkout HEAD^0 &&
 +      git branch my11 &&
 +      test -z "$(git config branch.my11.remote)" &&
 +      test -z "$(git config branch.my11.merge)"
 +'
 +
  test_expect_success 'detect misconfigured autosetuprebase (bad value)' '
        git config branch.autosetuprebase garbage &&
        test_must_fail git branch
index 95741801b0007b6ecbf22f665c4dcf3c744d5221,f7e40723198b6935b306409033241cfdd3a014a8..c0c8330c20e80f26d51b62c8999533c5692094de
@@@ -11,18 -11,6 +11,18 @@@ test_description='test cherry-pick and 
  
  . ./test-lib.sh
  
 +test_cmp_rev () {
 +      git rev-parse --verify "$1" >expect.rev &&
 +      git rev-parse --verify "$2" >actual.rev &&
 +      test_cmp expect.rev actual.rev
 +}
 +
 +pristine_detach () {
 +      git checkout -f "$1^0" &&
 +      git read-tree -u --reset HEAD &&
 +      git clean -d -f -f -q -x
 +}
 +
  test_expect_success setup '
  
        echo unrelated >unrelated &&
  '
  
  test_expect_success 'failed cherry-pick does not advance HEAD' '
 -
 -      git checkout -f initial^0 &&
 -      git read-tree -u --reset HEAD &&
 -      git clean -d -f -f -q -x &&
 -
 -      git update-index --refresh &&
 -      git diff-index --exit-code HEAD &&
 +      pristine_detach initial &&
  
        head=$(git rev-parse HEAD) &&
        test_must_fail git cherry-pick picked &&
        test "$head" = "$newhead"
  '
  
- test_expect_success 'advice from failed cherry-pick' "
+ test_expect_success C_LOCALE_OUTPUT 'advice from failed cherry-pick' "
 -      git checkout -f initial^0 &&
 -      git read-tree -u --reset HEAD &&
 -      git clean -d -f -f -q -x &&
 -
 -      git update-index --refresh &&
 -      git diff-index --exit-code HEAD &&
 +      pristine_detach initial &&
  
        picked=\$(git rev-parse --short picked) &&
        cat <<-EOF >expected &&
        error: could not apply \$picked... picked
        hint: after resolving the conflicts, mark the corrected paths
        hint: with 'git add <paths>' or 'git rm <paths>'
 -      hint: and commit the result with 'git commit -c \$picked'
 +      hint: and commit the result with 'git commit'
        EOF
        test_must_fail git cherry-pick picked 2>actual &&
  
        test_cmp expected actual
  "
  
 -test_expect_success 'failed cherry-pick produces dirty index' '
 +test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' '
 +      pristine_detach initial &&
 +      test_must_fail git cherry-pick picked &&
 +      test_cmp_rev picked CHERRY_PICK_HEAD
 +'
  
 -      git checkout -f initial^0 &&
 -      git read-tree -u --reset HEAD &&
 -      git clean -d -f -f -q -x &&
 +test_expect_success 'successful cherry-pick does not set CHERRY_PICK_HEAD' '
 +      pristine_detach initial &&
 +      git cherry-pick base &&
 +      test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 +'
 +
 +test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' '
 +      pristine_detach initial &&
 +      git cherry-pick --no-commit base &&
 +      test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 +'
 +
 +test_expect_success 'GIT_CHERRY_PICK_HELP suppresses CHERRY_PICK_HEAD' '
 +      pristine_detach initial &&
 +      (
 +              GIT_CHERRY_PICK_HELP="and then do something else" &&
 +              export GIT_CHERRY_PICK_HELP &&
 +              test_must_fail git cherry-pick picked
 +      ) &&
 +      test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 +'
 +
 +test_expect_success 'git reset clears CHERRY_PICK_HEAD' '
 +      pristine_detach initial &&
 +
 +      test_must_fail git cherry-pick picked &&
 +      git reset &&
 +
 +      test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 +'
 +
 +test_expect_success 'failed commit does not clear CHERRY_PICK_HEAD' '
 +      pristine_detach initial &&
 +
 +      test_must_fail git cherry-pick picked &&
 +      test_must_fail git commit &&
 +
 +      test_cmp_rev picked CHERRY_PICK_HEAD
 +'
 +
 +test_expect_success 'cancelled commit does not clear CHERRY_PICK_HEAD' '
 +      pristine_detach initial &&
  
 -      git update-index --refresh &&
 -      git diff-index --exit-code HEAD &&
 +      test_must_fail git cherry-pick picked &&
 +      echo resolved >foo &&
 +      git add foo &&
 +      git update-index --refresh -q &&
 +      test_must_fail git diff-index --exit-code HEAD &&
 +      (
 +              GIT_EDITOR=false &&
 +              export GIT_EDITOR &&
 +              test_must_fail git commit
 +      ) &&
 +
 +      test_cmp_rev picked CHERRY_PICK_HEAD
 +'
 +
 +test_expect_success 'successful commit clears CHERRY_PICK_HEAD' '
 +      pristine_detach initial &&
 +
 +      test_must_fail git cherry-pick picked &&
 +      echo resolved >foo &&
 +      git add foo &&
 +      git commit &&
 +
 +      test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
 +'
 +
 +test_expect_success 'failed cherry-pick produces dirty index' '
 +      pristine_detach initial &&
  
        test_must_fail git cherry-pick picked &&
  
  '
  
  test_expect_success 'failed cherry-pick registers participants in index' '
 -
 -      git read-tree -u --reset HEAD &&
 -      git clean -d -f -f -q -x &&
 +      pristine_detach initial &&
        {
                git checkout base -- foo &&
                git ls-files --stage foo &&
                2 s/ 0  / 2     /
                3 s/ 0  / 3     /
        " < stages > expected &&
 -      git checkout -f initial^0 &&
 -
 -      git update-index --refresh &&
 -      git diff-index --exit-code HEAD &&
 +      git read-tree -u --reset HEAD &&
  
        test_must_fail git cherry-pick picked &&
        git ls-files --stage --unmerged > actual &&
  '
  
  test_expect_success 'failed cherry-pick describes conflict in work tree' '
 -
 -      git checkout -f initial^0 &&
 -      git read-tree -u --reset HEAD &&
 -      git clean -d -f -f -q -x &&
 +      pristine_detach initial &&
        cat <<-EOF > expected &&
        <<<<<<< HEAD
        a
        >>>>>>> objid picked
        EOF
  
 -      git update-index --refresh &&
 -      git diff-index --exit-code HEAD &&
 -
        test_must_fail git cherry-pick picked &&
  
        sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
  '
  
  test_expect_success 'diff3 -m style' '
 -
 +      pristine_detach initial &&
        git config merge.conflictstyle diff3 &&
 -      git checkout -f initial^0 &&
 -      git read-tree -u --reset HEAD &&
 -      git clean -d -f -f -q -x &&
        cat <<-EOF > expected &&
        <<<<<<< HEAD
        a
        >>>>>>> objid picked
        EOF
  
 -      git update-index --refresh &&
 -      git diff-index --exit-code HEAD &&
 -
        test_must_fail git cherry-pick picked &&
  
        sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
  '
  
  test_expect_success 'revert also handles conflicts sanely' '
 -
        git config --unset merge.conflictstyle &&
 -      git read-tree -u --reset HEAD &&
 -      git clean -d -f -f -q -x &&
 +      pristine_detach initial &&
        cat <<-EOF > expected &&
        <<<<<<< HEAD
        a
                2 s/ 0  / 2     /
                3 s/ 0  / 3     /
        " < stages > expected-stages &&
 -      git checkout -f initial^0 &&
 -
 -      git update-index --refresh &&
 -      git diff-index --exit-code HEAD &&
 +      git read-tree -u --reset HEAD &&
  
        head=$(git rev-parse HEAD) &&
        test_must_fail git revert picked &&
  '
  
  test_expect_success 'revert conflict, diff3 -m style' '
 +      pristine_detach initial &&
        git config merge.conflictstyle diff3 &&
 -      git checkout -f initial^0 &&
 -      git read-tree -u --reset HEAD &&
 -      git clean -d -f -f -q -x &&
        cat <<-EOF > expected &&
        <<<<<<< HEAD
        a
        >>>>>>> parent of objid picked
        EOF
  
 -      git update-index --refresh &&
 -      git diff-index --exit-code HEAD &&
 -
        test_must_fail git revert picked &&
  
        sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
diff --combined t/t4014-format-patch.sh
index 9c663677df0887cc09ce2c8277ec300e8de4eaaa,a46d88828ba2244023a6b1980914fd539c807782..c3cdb5205350985f3362268b0cd63bc59bee2444
@@@ -614,7 -614,7 +614,7 @@@ echo "fatal: --name-only does not make 
  echo "fatal: --name-status does not make sense" > expect.name-status
  echo "fatal: --check does not make sense" > expect.check
  
- test_expect_success 'options no longer allowed for format-patch' '
+ test_expect_success C_LOCALE_OUTPUT 'options no longer allowed for format-patch' '
        test_must_fail git format-patch --name-only 2> output &&
        test_cmp expect.name-only output &&
        test_must_fail git format-patch --name-status 2> output &&
@@@ -709,88 -709,4 +709,88 @@@ test_expect_success TTY 'format-patch -
        test_path_is_missing .git/pager_used
  '
  
 +test_expect_success 'format-patch handles multi-line subjects' '
 +      rm -rf patches/ &&
 +      echo content >>file &&
 +      for i in one two three; do echo $i; done >msg &&
 +      git add file &&
 +      git commit -F msg &&
 +      git format-patch -o patches -1 &&
 +      grep ^Subject: patches/0001-one.patch >actual &&
 +      echo "Subject: [PATCH] one two three" >expect &&
 +      test_cmp expect actual
 +'
 +
 +test_expect_success 'format-patch handles multi-line encoded subjects' '
 +      rm -rf patches/ &&
 +      echo content >>file &&
 +      for i in en tvÃ¥ tre; do echo $i; done >msg &&
 +      git add file &&
 +      git commit -F msg &&
 +      git format-patch -o patches -1 &&
 +      grep ^Subject: patches/0001-en.patch >actual &&
 +      echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
 +      test_cmp expect actual
 +'
 +
 +M8="foo bar "
 +M64=$M8$M8$M8$M8$M8$M8$M8$M8
 +M512=$M64$M64$M64$M64$M64$M64$M64$M64
 +cat >expect <<'EOF'
 +Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 + foo bar foo bar foo bar foo bar
 +EOF
 +test_expect_success 'format-patch wraps extremely long headers (ascii)' '
 +      echo content >>file &&
 +      git add file &&
 +      git commit -m "$M512" &&
 +      git format-patch --stdout -1 >patch &&
 +      sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
 +      test_cmp expect subject
 +'
 +
 +M8="föö bar "
 +M64=$M8$M8$M8$M8$M8$M8$M8$M8
 +M512=$M64$M64$M64$M64$M64$M64$M64$M64
 +cat >expect <<'EOF'
 +Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
 + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
 +EOF
 +test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
 +      rm -rf patches/ &&
 +      echo content >>file &&
 +      git add file &&
 +      git commit -m "$M512" &&
 +      git format-patch --stdout -1 >patch &&
 +      sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
 +      test_cmp expect subject
 +'
 +
  test_done
diff --combined t/t5601-clone.sh
index 3ca275cc671502febd8397e1828c612f575c5b89,9e6fa3b2abd04c22c62ed9e4c3d3b35eea735a04..a92d145be6e168c44e1cd09e6629e87cde0d156f
@@@ -31,7 -31,7 +31,7 @@@ test_expect_success 'clone with excess 
  
  '
  
- test_expect_success 'output from clone' '
+ test_expect_success C_LOCALE_OUTPUT 'output from clone' '
        rm -fr dst &&
        git clone -n "file://$(pwd)/src" dst >output &&
        test $(grep Clon output | wc -l) = 1
@@@ -164,6 -164,7 +164,6 @@@ test_expect_success 'clone a void' 
  test_expect_success 'clone respects global branch.autosetuprebase' '
        (
                test_config="$HOME/.gitconfig" &&
 -              unset GIT_CONFIG_NOGLOBAL &&
                git config -f "$test_config" branch.autosetuprebase remote &&
                rm -fr dst &&
                git clone src dst &&
diff --combined t/t6040-tracking-info.sh
index cb851326425be7a552a0624a5d7483244625a7ed,6cad64344e15b5c04ac3934d7281ed96ec59e98a..6c3719141aa567b97de1228f53a6c49eaf139e8e
@@@ -42,7 -42,7 +42,7 @@@ b3 behind 
  b4 ahead 2
  EOF
  
- test_expect_success 'branch -v' '
+ test_expect_success C_LOCALE_OUTPUT 'branch -v' '
        (
                cd test &&
                git branch -v
@@@ -74,20 -74,20 +74,20 @@@ test_expect_success 'status' 
        grep "have 1 and 1 different" actual
  '
  
 -test_expect_success 'status when tracking lightweight tags' '
 +test_expect_success 'fail to track lightweight tags' '
        git checkout master &&
        git tag light &&
 -      git branch --track lighttrack light >actual &&
 -      grep "set up to track" actual &&
 -      git checkout lighttrack
 +      test_must_fail git branch --track lighttrack light >actual &&
 +      test_must_fail grep "set up to track" actual &&
 +      test_must_fail git checkout lighttrack
  '
  
 -test_expect_success 'status when tracking annotated tags' '
 +test_expect_success 'fail to track annotated tags' '
        git checkout master &&
        git tag -m heavy heavy &&
 -      git branch --track heavytrack heavy >actual &&
 -      grep "set up to track" actual &&
 -      git checkout heavytrack
 +      test_must_fail git branch --track heavytrack heavy >actual &&
 +      test_must_fail grep "set up to track" actual &&
 +      test_must_fail git checkout heavytrack
  '
  
  test_expect_success 'setup tracking with branch --set-upstream on existing branch' '
diff --combined t/t7201-co.sh
index 0c002ab6951752bbf1d466ff5d0a4668835ca57c,fb1fe6886cef1f54cb5d2524fc0e5284759fc8a2..37ed0931d9499791a6b3336efb97385356df6157
@@@ -223,7 -223,7 +223,7 @@@ test_expect_success 'checkout --merge -
        test_cmp two expect
  '
  
- test_expect_success 'checkout to detach HEAD (with advice declined)' '
+ test_expect_success C_LOCALE_OUTPUT 'checkout to detach HEAD (with advice declined)' '
  
        git config advice.detachedHead false &&
        git checkout -f renamer && git clean -f &&
        fi
  '
  
- test_expect_success 'checkout to detach HEAD' '
+ test_expect_success C_LOCALE_OUTPUT 'checkout to detach HEAD' '
        git config advice.detachedHead true &&
        git checkout -f renamer && git clean -f &&
        git checkout renamer^ 2>messages &&
        fi
  '
  
- test_expect_success 'checkout to detach HEAD with branchname^' '
+ test_expect_success C_LOCALE_OUTPUT 'checkout to detach HEAD with branchname^' '
  
        git checkout -f master && git clean -f &&
        git checkout renamer^ &&
        fi
  '
  
- test_expect_success 'checkout to detach HEAD with :/message' '
+ test_expect_success C_LOCALE_OUTPUT 'checkout to detach HEAD with :/message' '
  
        git checkout -f master && git clean -f &&
        git checkout ":/Initial" &&
        fi
  '
  
- test_expect_success 'checkout to detach HEAD with HEAD^0' '
+ test_expect_success C_LOCALE_OUTPUT 'checkout to detach HEAD with HEAD^0' '
  
        git checkout -f master && git clean -f &&
        git checkout HEAD^0 &&
@@@ -408,15 -408,6 +408,15 @@@ test_expect_success 'checkout w/--trac
      test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
  '
  
 +test_expect_success 'checkout w/--track from tag fails' '
 +    git checkout master^0 &&
 +    test_must_fail git symbolic-ref HEAD &&
 +    test_must_fail git checkout --track -b track frotz &&
 +    test_must_fail git rev-parse --verify track &&
 +    test_must_fail git symbolic-ref HEAD &&
 +    test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
 +'
 +
  test_expect_success 'detach a symbolic link HEAD' '
      git checkout master &&
      git config --bool core.prefersymlinkrefs yes &&
  test_expect_success \
      'checkout with --track fakes a sensible -b <name>' '
      git update-ref refs/remotes/origin/koala/bear renamer &&
 -    git update-ref refs/new/koala/bear renamer &&
  
      git checkout --track origin/koala/bear &&
      test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
  
      git checkout --track remotes/origin/koala/bear &&
      test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
 -    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
 -
 -    git checkout master && git branch -D koala/bear &&
 -
 -    git checkout --track refs/new/koala/bear &&
 -    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
      test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
  '
  
diff --combined t/t7500-commit.sh
index 5976f598fc7bf48120865eca3ceef74a151e717a,a101256df6205ec37b13c488c7812372df55a869..bcdf0847d0970f544e96afa0036ec12800422fd8
@@@ -28,21 -28,13 +28,21 @@@ test_expect_success 'a basic commit in 
  test_expect_success 'nonexistent template file should return error' '
        echo changes >> foo &&
        git add foo &&
 -      test_must_fail git commit --template "$PWD"/notexist
 +      (
 +              GIT_EDITOR="echo hello >\"\$1\"" &&
 +              export GIT_EDITOR &&
 +              test_must_fail git commit --template "$PWD"/notexist
 +      )
  '
  
  test_expect_success 'nonexistent template file in config should return error' '
        git config commit.template "$PWD"/notexist &&
 -      test_must_fail git commit &&
 -      git config --unset commit.template
 +      test_when_finished "git config --unset commit.template" &&
 +      (
 +              GIT_EDITOR="echo hello >\"\$1\"" &&
 +              export GIT_EDITOR &&
 +              test_must_fail git commit
 +      )
  '
  
  # From now on we'll use a template file that exists.
@@@ -72,7 -64,7 +72,7 @@@ test_expect_success 'adding comments t
        )
  '
  
- test_expect_success 'adding real content to a template should commit' '
+ test_expect_success C_LOCALE_OUTPUT 'adding real content to a template should commit' '
        (
                test_set_editor "$TEST_DIRECTORY"/t7500/add-content &&
                git commit --template "$TEMPLATE"
@@@ -80,7 -72,7 +80,7 @@@
        commit_msg_is "template linecommit message"
  '
  
- test_expect_success '-t option should be short for --template' '
+ test_expect_success C_LOCALE_OUTPUT '-t option should be short for --template' '
        echo "short template" > "$TEMPLATE" &&
        echo "new content" >> foo &&
        git add foo &&
@@@ -91,7 -83,7 +91,7 @@@
        commit_msg_is "short templatecommit message"
  '
  
- test_expect_success 'config-specified template should commit' '
+ test_expect_success C_LOCALE_OUTPUT 'config-specified template should commit' '
        echo "new template" > "$TEMPLATE" &&
        git config commit.template "$TEMPLATE" &&
        echo "more content" >> foo &&
@@@ -290,7 -282,7 +290,7 @@@ test_expect_success 'commit --squash wo
        commit_msg_is "squash! edited commit"
  '
  
- test_expect_success 'commit --squash works with editor' '
+ test_expect_success C_LOCALE_OUTPUT 'commit --squash works with editor' '
        commit_for_rebase_autosquash_setup &&
        test_set_editor "$TEST_DIRECTORY"/t7500/add-content &&
        git commit --squash HEAD~1 &&
index b54e840ee2ab09a67afc663a2f475bfc9fcb9d8b,0a9b90b33f4bc5b66c7e5d9b1334eab9f84c5118..ef84f04102ed067768c66ea9608b98d47851eb8b
@@@ -122,7 -122,7 +122,7 @@@ test_expect_success 'will not overwrit
        rm -f sub sub2
  '
  
 -test_expect_failure SYMLINKS 'will not overwrite untracked symlink in leading path' '
 +test_expect_success SYMLINKS 'will not overwrite untracked symlink in leading path' '
        git reset --hard c0 &&
        rm -rf sub &&
        mkdir sub2 &&
@@@ -150,17 -150,18 +150,23 @@@ test_expect_success 'will not overwrit
        git rm -fr . &&
        git checkout --orphan new &&
        cp important c0.c &&
-       test_must_fail git merge c0 2>out &&
-       test_cmp out expect &&
+       test_must_fail git merge c0 2>out
+ '
+ test_expect_success C_LOCALE_OUTPUT 'will not overwrite untracked file on unborn branch: output' '
+       test_cmp out expect
+ '
+ test_expect_success 'will not overwrite untracked file on unborn branch .git/MERGE_HEAD sanity etc.' '
 +      test_when_finished "rm c0.c" &&
        test_path_is_missing .git/MERGE_HEAD &&
        test_cmp important c0.c
  '
  
 +test_expect_success 'failed merge leaves unborn branch in the womb' '
 +      test_must_fail git rev-parse --verify HEAD
 +'
 +
  test_expect_success 'set up unborn branch and content' '
        git symbolic-ref HEAD refs/heads/unborn &&
        rm -f .git/index &&
        echo bar > untracked-file
  '
  
 -test_expect_failure 'will not clobber WT/index when merging into unborn' '
 +test_expect_success 'will not clobber WT/index when merging into unborn' '
        git merge master &&
        grep foo tracked-file &&
        git show :tracked-file >expect &&
diff --combined wt-status.c
index 53558d7e5f517479af478e375076718189c2d2d5,9ff059012249821fe36cb2060f19a77db16efcc0..9f4e0ba9c17120ca2903b30b95b6d8fbcc62cd9c
@@@ -131,16 -131,16 +131,16 @@@ static void wt_status_print_unmerged_he
  {
        const char *c = color(WT_STATUS_HEADER, s);
  
-       status_printf_ln(s, c, "Unmerged paths:");
+       status_printf_ln(s, c, _("Unmerged paths:"));
        if (!advice_status_hints)
                return;
 -      if (s->in_merge)
 +      if (s->whence != FROM_COMMIT)
                ;
        else if (!s->is_initial)
-               status_printf_ln(s, c, "  (use \"git reset %s <file>...\" to unstage)", s->reference);
+               status_printf_ln(s, c, _("  (use \"git reset %s <file>...\" to unstage)"), s->reference);
        else
-               status_printf_ln(s, c, "  (use \"git rm --cached <file>...\" to unstage)");
-       status_printf_ln(s, c, "  (use \"git add/rm <file>...\" as appropriate to mark resolution)");
+               status_printf_ln(s, c, _("  (use \"git rm --cached <file>...\" to unstage)"));
+       status_printf_ln(s, c, _("  (use \"git add/rm <file>...\" as appropriate to mark resolution)"));
        status_printf_ln(s, c, "");
  }
  
@@@ -148,15 -148,15 +148,15 @@@ static void wt_status_print_cached_head
  {
        const char *c = color(WT_STATUS_HEADER, s);
  
-       status_printf_ln(s, c, "Changes to be committed:");
+       status_printf_ln(s, c, _("Changes to be committed:"));
        if (!advice_status_hints)
                return;
 -      if (s->in_merge)
 +      if (s->whence != FROM_COMMIT)
                ; /* NEEDSWORK: use "git reset --unresolve"??? */
        else if (!s->is_initial)
-               status_printf_ln(s, c, "  (use \"git reset %s <file>...\" to unstage)", s->reference);
+               status_printf_ln(s, c, _("  (use \"git reset %s <file>...\" to unstage)"), s->reference);
        else
-               status_printf_ln(s, c, "  (use \"git rm --cached <file>...\" to unstage)");
+               status_printf_ln(s, c, _("  (use \"git rm --cached <file>...\" to unstage)"));
        status_printf_ln(s, c, "");
  }
  
@@@ -166,16 -166,16 +166,16 @@@ static void wt_status_print_dirty_heade
  {
        const char *c = color(WT_STATUS_HEADER, s);
  
-       status_printf_ln(s, c, "Changes not staged for commit:");
+       status_printf_ln(s, c, _("Changes not staged for commit:"));
        if (!advice_status_hints)
                return;
        if (!has_deleted)
-               status_printf_ln(s, c, "  (use \"git add <file>...\" to update what will be committed)");
+               status_printf_ln(s, c, _("  (use \"git add <file>...\" to update what will be committed)"));
        else
-               status_printf_ln(s, c, "  (use \"git add/rm <file>...\" to update what will be committed)");
-       status_printf_ln(s, c, "  (use \"git checkout -- <file>...\" to discard changes in working directory)");
+               status_printf_ln(s, c, _("  (use \"git add/rm <file>...\" to update what will be committed)"));
+       status_printf_ln(s, c, _("  (use \"git checkout -- <file>...\" to discard changes in working directory)"));
        if (has_dirty_submodules)
-               status_printf_ln(s, c, "  (commit or discard the untracked or modified content in submodules)");
+               status_printf_ln(s, c, _("  (commit or discard the untracked or modified content in submodules)"));
        status_printf_ln(s, c, "");
  }
  
@@@ -184,10 -184,10 +184,10 @@@ static void wt_status_print_other_heade
                                         const char *how)
  {
        const char *c = color(WT_STATUS_HEADER, s);
-       status_printf_ln(s, c, "%s files:", what);
+       status_printf_ln(s, c, _("%s files:"), what);
        if (!advice_status_hints)
                return;
-       status_printf_ln(s, c, "  (use \"git %s <file>...\" to include in what will be committed)", how);
+       status_printf_ln(s, c, _("  (use \"git %s <file>...\" to include in what will be committed)"), how);
        status_printf_ln(s, c, "");
  }
  
@@@ -204,18 -204,18 +204,18 @@@ static void wt_status_print_unmerged_da
        const char *c = color(WT_STATUS_UNMERGED, s);
        struct wt_status_change_data *d = it->util;
        struct strbuf onebuf = STRBUF_INIT;
-       const char *one, *how = "bug";
+       const char *one, *how = _("bug");
  
        one = quote_path(it->string, -1, &onebuf, s->prefix);
        status_printf(s, color(WT_STATUS_HEADER, s), "\t");
        switch (d->stagemask) {
-       case 1: how = "both deleted:"; break;
-       case 2: how = "added by us:"; break;
-       case 3: how = "deleted by them:"; break;
-       case 4: how = "added by them:"; break;
-       case 5: how = "deleted by us:"; break;
-       case 6: how = "both added:"; break;
-       case 7: how = "both modified:"; break;
+       case 1: how = _("both deleted:"); break;
+       case 2: how = _("added by us:"); break;
+       case 3: how = _("deleted by them:"); break;
+       case 4: how = _("added by them:"); break;
+       case 5: how = _("deleted by us:"); break;
+       case 6: how = _("both added:"); break;
+       case 7: how = _("both modified:"); break;
        }
        status_printf_more(s, c, "%-20s%s\n", how, one);
        strbuf_release(&onebuf);
@@@ -245,11 -245,11 +245,11 @@@ static void wt_status_print_change_data
                if (d->new_submodule_commits || d->dirty_submodule) {
                        strbuf_addstr(&extra, " (");
                        if (d->new_submodule_commits)
-                               strbuf_addf(&extra, "new commits, ");
+                               strbuf_addf(&extra, _("new commits, "));
                        if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
-                               strbuf_addf(&extra, "modified content, ");
+                               strbuf_addf(&extra, _("modified content, "));
                        if (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
-                               strbuf_addf(&extra, "untracked content, ");
+                               strbuf_addf(&extra, _("untracked content, "));
                        strbuf_setlen(&extra, extra.len - 2);
                        strbuf_addch(&extra, ')');
                }
        status_printf(s, color(WT_STATUS_HEADER, s), "\t");
        switch (status) {
        case DIFF_STATUS_ADDED:
-               status_printf_more(s, c, "new file:   %s", one);
+               status_printf_more(s, c, _("new file:   %s"), one);
                break;
        case DIFF_STATUS_COPIED:
-               status_printf_more(s, c, "copied:     %s -> %s", one, two);
+               status_printf_more(s, c, _("copied:     %s -> %s"), one, two);
                break;
        case DIFF_STATUS_DELETED:
-               status_printf_more(s, c, "deleted:    %s", one);
+               status_printf_more(s, c, _("deleted:    %s"), one);
                break;
        case DIFF_STATUS_MODIFIED:
-               status_printf_more(s, c, "modified:   %s", one);
+               status_printf_more(s, c, _("modified:   %s"), one);
                break;
        case DIFF_STATUS_RENAMED:
-               status_printf_more(s, c, "renamed:    %s -> %s", one, two);
+               status_printf_more(s, c, _("renamed:    %s -> %s"), one, two);
                break;
        case DIFF_STATUS_TYPE_CHANGED:
-               status_printf_more(s, c, "typechange: %s", one);
+               status_printf_more(s, c, _("typechange: %s"), one);
                break;
        case DIFF_STATUS_UNKNOWN:
-               status_printf_more(s, c, "unknown:    %s", one);
+               status_printf_more(s, c, _("unknown:    %s"), one);
                break;
        case DIFF_STATUS_UNMERGED:
-               status_printf_more(s, c, "unmerged:   %s", one);
+               status_printf_more(s, c, _("unmerged:   %s"), one);
                break;
        default:
-               die("bug: unhandled diff status %c", status);
+               die(_("bug: unhandled diff status %c"), status);
        }
        if (extra.len) {
                status_printf_more(s, color(WT_STATUS_HEADER, s), "%s", extra.buf);
@@@ -397,7 -397,7 +397,7 @@@ static void wt_status_collect_changes_w
      }
        rev.diffopt.format_callback = wt_status_collect_changed_cb;
        rev.diffopt.format_callback_data = s;
 -      rev.prune_data = s->pathspec;
 +      init_pathspec(&rev.prune_data, s->pathspec);
        run_diff_files(&rev, 0);
  }
  
@@@ -422,22 -422,20 +422,22 @@@ static void wt_status_collect_changes_i
        rev.diffopt.detect_rename = 1;
        rev.diffopt.rename_limit = 200;
        rev.diffopt.break_opt = 0;
 -      rev.prune_data = s->pathspec;
 +      init_pathspec(&rev.prune_data, s->pathspec);
        run_diff_index(&rev, 1);
  }
  
  static void wt_status_collect_changes_initial(struct wt_status *s)
  {
 +      struct pathspec pathspec;
        int i;
  
 +      init_pathspec(&pathspec, s->pathspec);
        for (i = 0; i < active_nr; i++) {
                struct string_list_item *it;
                struct wt_status_change_data *d;
                struct cache_entry *ce = active_cache[i];
  
 -              if (!ce_path_match(ce, s->pathspec))
 +              if (!ce_path_match(ce, &pathspec))
                        continue;
                it = string_list_insert(&s->change, ce->name);
                d = it->util;
                else
                        d->index_status = DIFF_STATUS_ADDED;
        }
 +      free_pathspec(&pathspec);
  }
  
  static void wt_status_collect_untracked(struct wt_status *s)
@@@ -710,14 -707,14 +710,14 @@@ void wt_status_print(struct wt_status *
        const char *branch_status_color = color(WT_STATUS_HEADER, s);
  
        if (s->branch) {
-               const char *on_what = "On branch ";
+               const char *on_what = _("On branch ");
                const char *branch_name = s->branch;
                if (!prefixcmp(branch_name, "refs/heads/"))
                        branch_name += 11;
                else if (!strcmp(branch_name, "HEAD")) {
                        branch_name = "";
                        branch_status_color = color(WT_STATUS_NOBRANCH, s);
-                       on_what = "Not currently on any branch.";
+                       on_what = _("Not currently on any branch.");
                }
                status_printf(s, color(WT_STATUS_HEADER, s), "");
                status_printf_more(s, branch_status_color, "%s", on_what);
  
        if (s->is_initial) {
                status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
-               status_printf_ln(s, color(WT_STATUS_HEADER, s), "Initial commit");
+               status_printf_ln(s, color(WT_STATUS_HEADER, s), _("Initial commit"));
                status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
        }
  
                wt_status_print_submodule_summary(s, 1);  /* unstaged */
        }
        if (s->show_untracked_files) {
-               wt_status_print_other(s, &s->untracked, "Untracked", "add");
+               wt_status_print_other(s, &s->untracked, _("Untracked"), "add");
                if (s->show_ignored_files)
-                       wt_status_print_other(s, &s->ignored, "Ignored", "add -f");
+                       wt_status_print_other(s, &s->ignored, _("Ignored"), "add -f");
        } else if (s->commitable)
-               status_printf_ln(s, GIT_COLOR_NORMAL, "Untracked files not listed%s",
+               status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),
                        advice_status_hints
-                       ? " (use -u option to show untracked files)" : "");
+                       ? _(" (use -u option to show untracked files)") : "");
  
        if (s->verbose)
                wt_status_print_verbose(s);
        if (!s->commitable) {
                if (s->amend)
-                       status_printf_ln(s, GIT_COLOR_NORMAL, "No changes");
+                       status_printf_ln(s, GIT_COLOR_NORMAL, _("No changes"));
                else if (s->nowarn)
                        ; /* nothing */
                else if (s->workdir_dirty)
-                       printf("no changes added to commit%s\n",
+                       printf(_("no changes added to commit%s\n"),
                                advice_status_hints
-                               ? " (use \"git add\" and/or \"git commit -a\")" : "");
+                               ? _(" (use \"git add\" and/or \"git commit -a\")") : "");
                else if (s->untracked.nr)
-                       printf("nothing added to commit but untracked files present%s\n",
+                       printf(_("nothing added to commit but untracked files present%s\n"),
                                advice_status_hints
-                               ? " (use \"git add\" to track)" : "");
+                               ? _(" (use \"git add\" to track)") : "");
                else if (s->is_initial)
-                       printf("nothing to commit%s\n", advice_status_hints
-                               ? " (create/copy files and use \"git add\" to track)" : "");
+                       printf(_("nothing to commit%s\n"), advice_status_hints
+                               ? _(" (create/copy files and use \"git add\" to track)") : "");
                else if (!s->show_untracked_files)
-                       printf("nothing to commit%s\n", advice_status_hints
-                               ? " (use -u to show untracked files)" : "");
+                       printf(_("nothing to commit%s\n"), advice_status_hints
+                               ? _(" (use -u to show untracked files)") : "");
                else
-                       printf("nothing to commit%s\n", advice_status_hints
-                               ? " (working directory clean)" : "");
+                       printf(_("nothing to commit%s\n"), advice_status_hints
+                               ? _(" (working directory clean)") : "");
        }
  }
  
@@@ -881,13 -878,13 +881,13 @@@ static void wt_shortstatus_print_tracki
        if (!prefixcmp(branch_name, "refs/heads/"))
                branch_name += 11;
        else if (!strcmp(branch_name, "HEAD")) {
-               branch_name = "HEAD (no branch)";
+               branch_name = _("HEAD (no branch)");
                branch_color_local = color(WT_STATUS_NOBRANCH, s);
        }
  
        branch = branch_get(s->branch + 11);
        if (s->is_initial)
-               color_fprintf(s->fp, header_color, "Initial commit on ");
+               color_fprintf(s->fp, header_color, _("Initial commit on "));
        if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
                color_fprintf_ln(s->fp, branch_color_local,
                        "%s", branch_name);
  
        color_fprintf(s->fp, header_color, " [");
        if (!num_ours) {
-               color_fprintf(s->fp, header_color, "behind ");
+               color_fprintf(s->fp, header_color, _("behind "));
                color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
        } else if (!num_theirs) {
-               color_fprintf(s->fp, header_color, "ahead ");
+               color_fprintf(s->fp, header_color, _("ahead "));
                color_fprintf(s->fp, branch_color_local, "%d", num_ours);
        } else {
-               color_fprintf(s->fp, header_color, "ahead ");
+               color_fprintf(s->fp, header_color, _("ahead "));
                color_fprintf(s->fp, branch_color_local, "%d", num_ours);
-               color_fprintf(s->fp, header_color, ", behind ");
+               color_fprintf(s->fp, header_color, _(", behind "));
                color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
        }