Merge branch 'va/i18n-even-more'
authorJunio C Hamano <gitster@pobox.com>
Wed, 13 Jul 2016 18:24:10 +0000 (11:24 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 13 Jul 2016 18:24:10 +0000 (11:24 -0700)
More markings of messages for i18n, with updates to various tests
to pass GETTEXT_POISON tests.

One patch from the original submission dropped due to conflicts
with jk/upload-pack-hook, which is still in flux.

* va/i18n-even-more: (38 commits)
t5541: become resilient to GETTEXT_POISON
i18n: branch: mark comment when editing branch description for translation
i18n: unmark die messages for translation
i18n: submodule: escape shell variables inside eval_gettext
i18n: submodule: join strings marked for translation
i18n: init-db: join message pieces
i18n: remote: allow translations to reorder message
i18n: remote: mark URL fallback text for translation
i18n: standardise messages
i18n: sequencer: add period to error message
i18n: merge: change command option help to lowercase
i18n: merge: mark messages for translation
i18n: notes: mark options for translation
i18n: notes: mark strings for translation
i18n: transport-helper.c: change N_() call to _()
i18n: bisect: mark strings for translation
t5523: use test_i18ngrep for negation
t4153: fix negated test_i18ngrep call
t9003: become resilient to GETTEXT_POISON
tests: unpack-trees: update to use test_i18n* functions
...

16 files changed:
1  2 
Makefile
bisect.c
builtin/apply.c
builtin/checkout.c
builtin/pull.c
builtin/remote.c
builtin/repack.c
git-rebase--interactive.sh
git-sh-setup.sh
git-submodule.sh
sequencer.c
t/t0008-ignores.sh
t/t1308-config-set.sh
t/t5520-pull.sh
t/t7403-submodule-sync.sh
wt-status.c
diff --combined Makefile
index de5a0302565899a90482631e2267f3c413f347d4,d8117bb20d95f3d75bdd5b48d19d32354b42169d..3cb1d601a3d273c3a5588ede35338cc5a7323479
+++ b/Makefile
@@@ -375,7 -375,13 +375,7 @@@ GIT-VERSION-FILE: FORC
  # CFLAGS and LDFLAGS are for the users to override from the command line.
  
  CFLAGS = -g -O2 -Wall
 -LDFLAGS =
 -ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 -ALL_LDFLAGS = $(LDFLAGS)
 -STRIP ?= strip
 -
 -ifdef DEVELOPER
 -CFLAGS += -Werror \
 +DEVELOPER_CFLAGS = -Werror \
        -Wdeclaration-after-statement \
        -Wno-format-zero-length \
        -Wold-style-definition \
        -Wstrict-prototypes \
        -Wunused \
        -Wvla
 -endif
 +LDFLAGS =
 +ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 +ALL_LDFLAGS = $(LDFLAGS)
 +STRIP ?= strip
  
  # Create as necessary, replace existing, make ranlib unneeded.
  ARFLAGS = rcs
@@@ -948,10 -951,6 +948,10 @@@ include config.mak.unam
  -include config.mak.autogen
  -include config.mak
  
 +ifdef DEVELOPER
 +CFLAGS += $(DEVELOPER_CFLAGS)
 +endif
 +
  ifndef sysconfdir
  ifeq ($(prefix),/usr)
  sysconfdir = /etc
@@@ -2063,7 -2062,10 +2063,10 @@@ XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) -
        --keyword=gettextln --keyword=eval_gettextln
  XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
  LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
- LOCALIZED_SH = $(SCRIPT_SH) git-parse-remote.sh
+ LOCALIZED_SH = $(SCRIPT_SH)
+ LOCALIZED_SH += git-parse-remote.sh
+ LOCALIZED_SH += git-rebase--interactive.sh
+ LOCALIZED_SH += git-sh-setup.sh
  LOCALIZED_PERL = $(SCRIPT_PERL)
  
  ifdef XGETTEXT_INCLUDE_TESTS
diff --combined bisect.c
index dc13319c20b255d2a3d76f237746ba5dc953680a,a8713a86329e117aa216b2fa8f7d2cea52f41bec..b2a75c60cfb292f750a69af900aada69cabb6fa6
+++ b/bisect.c
@@@ -438,12 -438,12 +438,12 @@@ static void read_bisect_paths(struct ar
        FILE *fp = fopen(filename, "r");
  
        if (!fp)
-               die_errno("Could not open file '%s'", filename);
+               die_errno(_("Could not open file '%s'"), filename);
  
        while (strbuf_getline_lf(&str, fp) != EOF) {
                strbuf_trim(&str);
                if (sq_dequote_to_argv_array(str.buf, array))
-                       die("Badly quoted content in file '%s': %s",
+                       die(_("Badly quoted content in file '%s': %s"),
                            filename, str.buf);
        }
  
@@@ -649,7 -649,7 +649,7 @@@ static void exit_if_skipped_commits(str
        print_commit_list(tried, "%s\n", "%s\n");
        if (bad)
                printf("%s\n", oid_to_hex(bad));
-       printf("We cannot bisect more!\n");
+       printf(_("We cannot bisect more!\n"));
        exit(2);
  }
  
@@@ -702,7 -702,7 +702,7 @@@ static struct commit *get_commit_refere
  {
        struct commit *r = lookup_commit_reference(sha1);
        if (!r)
-               die("Not a valid commit name %s", sha1_to_hex(sha1));
+               die(_("Not a valid commit name %s"), sha1_to_hex(sha1));
        return r;
  }
  
@@@ -726,27 -726,27 +726,27 @@@ static void handle_bad_merge_base(void
                char *bad_hex = oid_to_hex(current_bad_oid);
                char *good_hex = join_sha1_array_hex(&good_revs, ' ');
                if (!strcmp(term_bad, "bad") && !strcmp(term_good, "good")) {
-                       fprintf(stderr, "The merge base %s is bad.\n"
+                       fprintf(stderr, _("The merge base %s is bad.\n"
                                "This means the bug has been fixed "
-                               "between %s and [%s].\n",
+                               "between %s and [%s].\n"),
                                bad_hex, bad_hex, good_hex);
                } else if (!strcmp(term_bad, "new") && !strcmp(term_good, "old")) {
-                       fprintf(stderr, "The merge base %s is new.\n"
+                       fprintf(stderr, _("The merge base %s is new.\n"
                                "The property has changed "
-                               "between %s and [%s].\n",
+                               "between %s and [%s].\n"),
                                bad_hex, bad_hex, good_hex);
                } else {
-                       fprintf(stderr, "The merge base %s is %s.\n"
+                       fprintf(stderr, _("The merge base %s is %s.\n"
                                "This means the first '%s' commit is "
-                               "between %s and [%s].\n",
+                               "between %s and [%s].\n"),
                                bad_hex, term_bad, term_good, bad_hex, good_hex);
                }
                exit(3);
        }
  
-       fprintf(stderr, "Some %s revs are not ancestor of the %s rev.\n"
+       fprintf(stderr, _("Some %s revs are not ancestor of the %s rev.\n"
                "git bisect cannot work properly in this case.\n"
-               "Maybe you mistook %s and %s revs?\n",
+               "Maybe you mistook %s and %s revs?\n"),
                term_good, term_bad, term_good, term_bad);
        exit(1);
  }
@@@ -757,11 -757,11 +757,11 @@@ static void handle_skipped_merge_base(c
        char *bad_hex = sha1_to_hex(current_bad_oid->hash);
        char *good_hex = join_sha1_array_hex(&good_revs, ' ');
  
-       warning("the merge base between %s and [%s] "
+       warning(_("the merge base between %s and [%s] "
                "must be skipped.\n"
                "So we cannot be sure the first %s commit is "
                "between %s and %s.\n"
-               "We continue anyway.",
+               "We continue anyway."),
                bad_hex, good_hex, term_bad, mb_hex, bad_hex);
        free(good_hex);
  }
@@@ -792,7 -792,7 +792,7 @@@ static void check_merge_bases(int no_ch
                } else if (0 <= sha1_array_lookup(&skipped_revs, mb)) {
                        handle_skipped_merge_base(mb);
                } else {
-                       printf("Bisecting: a merge base must be tested\n");
+                       printf(_("Bisecting: a merge base must be tested\n"));
                        exit(bisect_checkout(mb, no_checkout));
                }
        }
@@@ -843,7 -843,7 +843,7 @@@ static void check_good_are_ancestors_of
        int fd;
  
        if (!current_bad_oid)
-               die("a %s revision is needed", term_bad);
+               die(_("a %s revision is needed"), term_bad);
  
        /* Check if file BISECT_ANCESTORS_OK exists. */
        if (!stat(filename, &st) && S_ISREG(st.st_mode))
        /* Create file BISECT_ANCESTORS_OK. */
        fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
        if (fd < 0)
-               warning_errno("could not create file '%s'",
+               warning_errno(_("could not create file '%s'"),
                              filename);
        else
                close(fd);
@@@ -890,7 -890,6 +890,7 @@@ static void show_diff_tree(const char *
        if (!opt.diffopt.output_format)
                opt.diffopt.output_format = DIFF_FORMAT_RAW;
  
 +      setup_revisions(0, NULL, &opt, NULL);
        log_tree_commit(&opt, commit);
  }
  
@@@ -911,7 -910,7 +911,7 @@@ void read_bisect_terms(const char **rea
                        *read_good = "good";
                        return;
                } else {
-                       die_errno("could not read file '%s'", filename);
+                       die_errno(_("could not read file '%s'"), filename);
                }
        } else {
                strbuf_getline_lf(&str, fp);
@@@ -937,10 -936,11 +937,11 @@@ int bisect_next_all(const char *prefix
        struct commit_list *tried;
        int reaches = 0, all = 0, nr, steps;
        const unsigned char *bisect_rev;
+       char steps_msg[32];
  
        read_bisect_terms(&term_bad, &term_good);
        if (read_bisect_refs())
-               die("reading bisect refs failed");
+               die(_("reading bisect refs failed"));
  
        check_good_are_ancestors_of_bad(prefix, no_checkout);
  
                 */
                exit_if_skipped_commits(tried, NULL);
  
-               printf("%s was both %s and %s\n",
+               printf(_("%s was both %s and %s\n"),
                       oid_to_hex(current_bad_oid),
                       term_good,
                       term_bad);
        }
  
        if (!all) {
-               fprintf(stderr, "No testable commit found.\n"
-                       "Maybe you started with bad path parameters?\n");
+               fprintf(stderr, _("No testable commit found.\n"
+                       "Maybe you started with bad path parameters?\n"));
                exit(4);
        }
  
  
        nr = all - reaches - 1;
        steps = estimate_bisect_steps(all);
-       printf("Bisecting: %d revision%s left to test after this "
-              "(roughly %d step%s)\n", nr, (nr == 1 ? "" : "s"),
-              steps, (steps == 1 ? "" : "s"));
+       xsnprintf(steps_msg, sizeof(steps_msg),
+                 Q_("(roughly %d step)", "(roughly %d steps)", steps),
+                 steps);
+       /* TRANSLATORS: the last %s will be replaced with
+          "(roughly %d steps)" translation */
+       printf(Q_("Bisecting: %d revision left to test after this %s\n",
+                 "Bisecting: %d revisions left to test after this %s\n",
+                 nr), nr, steps_msg);
  
        return bisect_checkout(bisect_rev, no_checkout);
  }
diff --combined builtin/apply.c
index 7fc5c3e30745d50a05accb3a83ccfa8871963df6,205c9f8f3301b17456e5c19d68dff8e6cbfca6b6..1a488f9e888b6e9ebb1357a6cf3f7f007cf732fe
  #include "ll-merge.h"
  #include "rerere.h"
  
 -/*
 - *  --check turns on checking that the working tree matches the
 - *    files that are being modified, but doesn't apply the patch
 - *  --stat does just a diffstat, and doesn't actually apply
 - *  --numstat does numeric diffstat, and doesn't actually apply
 - *  --index-info shows the old and new index info for paths if available.
 - *  --index updates the cache as well.
 - *  --cached updates only the cache without ever touching the working tree.
 - */
 -static const char *prefix;
 -static int prefix_length = -1;
 -static int newfd = -1;
 -
 -static int unidiff_zero;
 -static int p_value = 1;
 -static int p_value_known;
 -static int check_index;
 -static int update_index;
 -static int cached;
 -static int diffstat;
 -static int numstat;
 -static int summary;
 -static int check;
 -static int apply = 1;
 -static int apply_in_reverse;
 -static int apply_with_reject;
 -static int apply_verbosely;
 -static int allow_overlap;
 -static int no_add;
 -static int threeway;
 -static int unsafe_paths;
 -static const char *fake_ancestor;
 -static int line_termination = '\n';
 -static unsigned int p_context = UINT_MAX;
 -static const char * const apply_usage[] = {
 -      N_("git apply [<options>] [<patch>...]"),
 -      NULL
 -};
 -
 -static enum ws_error_action {
 +enum ws_error_action {
        nowarn_ws_error,
        warn_on_ws_error,
        die_on_ws_error,
        correct_ws_error
 -} ws_error_action = warn_on_ws_error;
 -static int whitespace_error;
 -static int squelch_whitespace_errors = 5;
 -static int applied_after_fixing_ws;
 +};
 +
  
 -static enum ws_ignore {
 +enum ws_ignore {
        ignore_ws_none,
        ignore_ws_change
 -} ws_ignore_action = ignore_ws_none;
 +};
 +
 +/*
 + * We need to keep track of how symlinks in the preimage are
 + * manipulated by the patches.  A patch to add a/b/c where a/b
 + * is a symlink should not be allowed to affect the directory
 + * the symlink points at, but if the same patch removes a/b,
 + * it is perfectly fine, as the patch removes a/b to make room
 + * to create a directory a/b so that a/b/c can be created.
 + *
 + * See also "struct string_list symlink_changes" in "struct
 + * apply_state".
 + */
 +#define SYMLINK_GOES_AWAY 01
 +#define SYMLINK_IN_RESULT 02
  
 +struct apply_state {
 +      const char *prefix;
 +      int prefix_length;
 +
 +      /* These are lock_file related */
 +      struct lock_file *lock_file;
 +      int newfd;
 +
 +      /* These control what gets looked at and modified */
 +      int apply; /* this is not a dry-run */
 +      int cached; /* apply to the index only */
 +      int check; /* preimage must match working tree, don't actually apply */
 +      int check_index; /* preimage must match the indexed version */
 +      int update_index; /* check_index && apply */
 +
 +      /* These control cosmetic aspect of the output */
 +      int diffstat; /* just show a diffstat, and don't actually apply */
 +      int numstat; /* just show a numeric diffstat, and don't actually apply */
 +      int summary; /* just report creation, deletion, etc, and don't actually apply */
 +
 +      /* These boolean parameters control how the apply is done */
 +      int allow_overlap;
 +      int apply_in_reverse;
 +      int apply_with_reject;
 +      int apply_verbosely;
 +      int no_add;
 +      int threeway;
 +      int unidiff_zero;
 +      int unsafe_paths;
 +
 +      /* Other non boolean parameters */
 +      const char *fake_ancestor;
 +      const char *patch_input_file;
 +      int line_termination;
 +      struct strbuf root;
 +      int p_value;
 +      int p_value_known;
 +      unsigned int p_context;
 +
 +      /* Exclude and include path parameters */
 +      struct string_list limit_by_name;
 +      int has_include;
 +
 +      /* Various "current state" */
 +      int linenr; /* current line number */
 +      struct string_list symlink_changes; /* we have to track symlinks */
  
 -static const char *patch_input_file;
 -static struct strbuf root = STRBUF_INIT;
 -static int read_stdin = 1;
 -static int options;
 +      /*
 +       * For "diff-stat" like behaviour, we keep track of the biggest change
 +       * we've seen, and the longest filename. That allows us to do simple
 +       * scaling.
 +       */
 +      int max_change;
 +      int max_len;
  
 -static void parse_whitespace_option(const char *option)
 +      /*
 +       * Records filenames that have been touched, in order to handle
 +       * the case where more than one patches touch the same file.
 +       */
 +      struct string_list fn_table;
 +
 +      /* These control whitespace errors */
 +      enum ws_error_action ws_error_action;
 +      enum ws_ignore ws_ignore_action;
 +      const char *whitespace_option;
 +      int whitespace_error;
 +      int squelch_whitespace_errors;
 +      int applied_after_fixing_ws;
 +};
 +
 +static const char * const apply_usage[] = {
 +      N_("git apply [<options>] [<patch>...]"),
 +      NULL
 +};
 +
 +static void parse_whitespace_option(struct apply_state *state, const char *option)
  {
        if (!option) {
 -              ws_error_action = warn_on_ws_error;
 +              state->ws_error_action = warn_on_ws_error;
                return;
        }
        if (!strcmp(option, "warn")) {
 -              ws_error_action = warn_on_ws_error;
 +              state->ws_error_action = warn_on_ws_error;
                return;
        }
        if (!strcmp(option, "nowarn")) {
 -              ws_error_action = nowarn_ws_error;
 +              state->ws_error_action = nowarn_ws_error;
                return;
        }
        if (!strcmp(option, "error")) {
 -              ws_error_action = die_on_ws_error;
 +              state->ws_error_action = die_on_ws_error;
                return;
        }
        if (!strcmp(option, "error-all")) {
 -              ws_error_action = die_on_ws_error;
 -              squelch_whitespace_errors = 0;
 +              state->ws_error_action = die_on_ws_error;
 +              state->squelch_whitespace_errors = 0;
                return;
        }
        if (!strcmp(option, "strip") || !strcmp(option, "fix")) {
 -              ws_error_action = correct_ws_error;
 +              state->ws_error_action = correct_ws_error;
                return;
        }
        die(_("unrecognized whitespace option '%s'"), option);
  }
  
 -static void parse_ignorewhitespace_option(const char *option)
 +static void parse_ignorewhitespace_option(struct apply_state *state,
 +                                        const char *option)
  {
        if (!option || !strcmp(option, "no") ||
            !strcmp(option, "false") || !strcmp(option, "never") ||
            !strcmp(option, "none")) {
 -              ws_ignore_action = ignore_ws_none;
 +              state->ws_ignore_action = ignore_ws_none;
                return;
        }
        if (!strcmp(option, "change")) {
 -              ws_ignore_action = ignore_ws_change;
 +              state->ws_ignore_action = ignore_ws_change;
                return;
        }
        die(_("unrecognized whitespace ignore option '%s'"), option);
  }
  
 -static void set_default_whitespace_mode(const char *whitespace_option)
 +static void set_default_whitespace_mode(struct apply_state *state)
  {
 -      if (!whitespace_option && !apply_default_whitespace)
 -              ws_error_action = (apply ? warn_on_ws_error : nowarn_ws_error);
 +      if (!state->whitespace_option && !apply_default_whitespace)
 +              state->ws_error_action = (state->apply ? warn_on_ws_error : nowarn_ws_error);
  }
  
 -/*
 - * For "diff-stat" like behaviour, we keep track of the biggest change
 - * we've seen, and the longest filename. That allows us to do simple
 - * scaling.
 - */
 -static int max_change, max_len;
 -
 -/*
 - * Various "current state", notably line numbers and what
 - * file (and how) we're patching right now.. The "is_xxxx"
 - * things are flags, where -1 means "don't know yet".
 - */
 -static int linenr = 1;
 -
  /*
   * This represents one "hunk" from a patch, starting with
   * "@@ -oldpos,oldlines +newpos,newlines @@" marker.  The
@@@ -294,6 -265,13 +294,6 @@@ struct image 
        struct line *line;
  };
  
 -/*
 - * Records filenames that have been touched, in order to handle
 - * the case where more than one patches touch the same file.
 - */
 -
 -static struct string_list fn_table;
 -
  static uint32_t hash_line(const char *cp, size_t len)
  {
        size_t i;
@@@ -464,7 -442,7 +464,7 @@@ static int is_dev_null(const char *str
  #define TERM_SPACE    1
  #define TERM_TAB      2
  
 -static int name_terminate(const char *name, int namelen, int c, int terminate)
 +static int name_terminate(int c, int terminate)
  {
        if (c == ' ' && !(terminate & TERM_SPACE))
                return 0;
@@@ -491,10 -469,7 +491,10 @@@ static char *squash_slash(char *name
        return name;
  }
  
 -static char *find_name_gnu(const char *line, const char *def, int p_value)
 +static char *find_name_gnu(struct apply_state *state,
 +                         const char *line,
 +                         const char *def,
 +                         int p_value)
  {
        struct strbuf name = STRBUF_INIT;
        char *cp;
        }
  
        strbuf_remove(&name, 0, cp - name.buf);
 -      if (root.len)
 -              strbuf_insert(&name, 0, root.buf, root.len);
 +      if (state->root.len)
 +              strbuf_insert(&name, 0, state->root.buf, state->root.len);
        return squash_slash(strbuf_detach(&name, NULL));
  }
  
@@@ -682,12 -657,8 +682,12 @@@ static size_t diff_timestamp_len(const 
        return line + len - end;
  }
  
 -static char *find_name_common(const char *line, const char *def,
 -                            int p_value, const char *end, int terminate)
 +static char *find_name_common(struct apply_state *state,
 +                            const char *line,
 +                            const char *def,
 +                            int p_value,
 +                            const char *end,
 +                            int terminate)
  {
        int len;
        const char *start = NULL;
                if (!end && isspace(c)) {
                        if (c == '\n')
                                break;
 -                      if (name_terminate(start, line-start, c, terminate))
 +                      if (name_terminate(c, terminate))
                                break;
                }
                line++;
                        return squash_slash(xstrdup(def));
        }
  
 -      if (root.len) {
 -              char *ret = xstrfmt("%s%.*s", root.buf, len, start);
 +      if (state->root.len) {
 +              char *ret = xstrfmt("%s%.*s", state->root.buf, len, start);
                return squash_slash(ret);
        }
  
        return squash_slash(xmemdupz(start, len));
  }
  
 -static char *find_name(const char *line, char *def, int p_value, int terminate)
 +static char *find_name(struct apply_state *state,
 +                     const char *line,
 +                     char *def,
 +                     int p_value,
 +                     int terminate)
  {
        if (*line == '"') {
 -              char *name = find_name_gnu(line, def, p_value);
 +              char *name = find_name_gnu(state, line, def, p_value);
                if (name)
                        return name;
        }
  
 -      return find_name_common(line, def, p_value, NULL, terminate);
 +      return find_name_common(state, line, def, p_value, NULL, terminate);
  }
  
 -static char *find_name_traditional(const char *line, char *def, int p_value)
 +static char *find_name_traditional(struct apply_state *state,
 +                                 const char *line,
 +                                 char *def,
 +                                 int p_value)
  {
        size_t len;
        size_t date_len;
  
        if (*line == '"') {
 -              char *name = find_name_gnu(line, def, p_value);
 +              char *name = find_name_gnu(state, line, def, p_value);
                if (name)
                        return name;
        }
        len = strchrnul(line, '\n') - line;
        date_len = diff_timestamp_len(line, len);
        if (!date_len)
 -              return find_name_common(line, def, p_value, NULL, TERM_TAB);
 +              return find_name_common(state, line, def, p_value, NULL, TERM_TAB);
        len -= date_len;
  
 -      return find_name_common(line, def, p_value, line + len, 0);
 +      return find_name_common(state, line, def, p_value, line + len, 0);
  }
  
  static int count_slashes(const char *cp)
   * Given the string after "--- " or "+++ ", guess the appropriate
   * p_value for the given patch.
   */
 -static int guess_p_value(const char *nameline)
 +static int guess_p_value(struct apply_state *state, const char *nameline)
  {
        char *name, *cp;
        int val = -1;
  
        if (is_dev_null(nameline))
                return -1;
 -      name = find_name_traditional(nameline, NULL, 0);
 +      name = find_name_traditional(state, nameline, NULL, 0);
        if (!name)
                return -1;
        cp = strchr(name, '/');
        if (!cp)
                val = 0;
 -      else if (prefix) {
 +      else if (state->prefix) {
                /*
                 * Does it begin with "a/$our-prefix" and such?  Then this is
                 * very likely to apply to our directory.
                 */
 -              if (!strncmp(name, prefix, prefix_length))
 -                      val = count_slashes(prefix);
 +              if (!strncmp(name, state->prefix, state->prefix_length))
 +                      val = count_slashes(state->prefix);
                else {
                        cp++;
 -                      if (!strncmp(cp, prefix, prefix_length))
 -                              val = count_slashes(prefix) + 1;
 +                      if (!strncmp(cp, state->prefix, state->prefix_length))
 +                              val = count_slashes(state->prefix) + 1;
                }
        }
        free(name);
@@@ -896,39 -860,36 +896,39 @@@ static int has_epoch_timestamp(const ch
   * files, we can happily check the index for a match, but for creating a
   * new file we should try to match whatever "patch" does. I have no idea.
   */
 -static void parse_traditional_patch(const char *first, const char *second, struct patch *patch)
 +static void parse_traditional_patch(struct apply_state *state,
 +                                  const char *first,
 +                                  const char *second,
 +                                  struct patch *patch)
  {
        char *name;
  
        first += 4;     /* skip "--- " */
        second += 4;    /* skip "+++ " */
 -      if (!p_value_known) {
 +      if (!state->p_value_known) {
                int p, q;
 -              p = guess_p_value(first);
 -              q = guess_p_value(second);
 +              p = guess_p_value(state, first);
 +              q = guess_p_value(state, second);
                if (p < 0) p = q;
                if (0 <= p && p == q) {
 -                      p_value = p;
 -                      p_value_known = 1;
 +                      state->p_value = p;
 +                      state->p_value_known = 1;
                }
        }
        if (is_dev_null(first)) {
                patch->is_new = 1;
                patch->is_delete = 0;
 -              name = find_name_traditional(second, NULL, p_value);
 +              name = find_name_traditional(state, second, NULL, state->p_value);
                patch->new_name = name;
        } else if (is_dev_null(second)) {
                patch->is_new = 0;
                patch->is_delete = 1;
 -              name = find_name_traditional(first, NULL, p_value);
 +              name = find_name_traditional(state, first, NULL, state->p_value);
                patch->old_name = name;
        } else {
                char *first_name;
 -              first_name = find_name_traditional(first, NULL, p_value);
 -              name = find_name_traditional(second, first_name, p_value);
 +              first_name = find_name_traditional(state, first, NULL, state->p_value);
 +              name = find_name_traditional(state, second, first_name, state->p_value);
                free(first_name);
                if (has_epoch_timestamp(first)) {
                        patch->is_new = 1;
                }
        }
        if (!name)
 -              die(_("unable to find filename in patch at line %d"), linenr);
 +              die(_("unable to find filename in patch at line %d"), state->linenr);
  }
  
 -static int gitdiff_hdrend(const char *line, struct patch *patch)
 +static int gitdiff_hdrend(struct apply_state *state,
 +                        const char *line,
 +                        struct patch *patch)
  {
        return -1;
  }
  #define DIFF_OLD_NAME 0
  #define DIFF_NEW_NAME 1
  
 -static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name, int side)
 +static void gitdiff_verify_name(struct apply_state *state,
 +                              const char *line,
 +                              int isnull,
 +                              char **name,
 +                              int side)
  {
 -      if (!orig_name && !isnull)
 -              return find_name(line, NULL, p_value, TERM_TAB);
 +      if (!*name && !isnull) {
 +              *name = find_name(state, line, NULL, state->p_value, TERM_TAB);
 +              return;
 +      }
  
 -      if (orig_name) {
 -              int len = strlen(orig_name);
 +      if (*name) {
 +              int len = strlen(*name);
                char *another;
                if (isnull)
                        die(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
 -                          orig_name, linenr);
 -              another = find_name(line, NULL, p_value, TERM_TAB);
 -              if (!another || memcmp(another, orig_name, len + 1))
 +                          *name, state->linenr);
 +              another = find_name(state, line, NULL, state->p_value, TERM_TAB);
 +              if (!another || memcmp(another, *name, len + 1))
                        die((side == DIFF_NEW_NAME) ?
                            _("git apply: bad git-diff - inconsistent new filename on line %d") :
 -                          _("git apply: bad git-diff - inconsistent old filename on line %d"), linenr);
 +                          _("git apply: bad git-diff - inconsistent old filename on line %d"), state->linenr);
                free(another);
 -              return orig_name;
        } else {
                /* expect "/dev/null" */
                if (memcmp("/dev/null", line, 9) || line[9] != '\n')
 -                      die(_("git apply: bad git-diff - expected /dev/null on line %d"), linenr);
 -              return NULL;
 +                      die(_("git apply: bad git-diff - expected /dev/null on line %d"), state->linenr);
        }
  }
  
 -static int gitdiff_oldname(const char *line, struct patch *patch)
 +static int gitdiff_oldname(struct apply_state *state,
 +                         const char *line,
 +                         struct patch *patch)
  {
 -      patch->old_name = gitdiff_verify_name(line, patch->is_new, patch->old_name,
 -                                            DIFF_OLD_NAME);
 +      gitdiff_verify_name(state, line,
 +                          patch->is_new, &patch->old_name,
 +                          DIFF_OLD_NAME);
        return 0;
  }
  
 -static int gitdiff_newname(const char *line, struct patch *patch)
 +static int gitdiff_newname(struct apply_state *state,
 +                         const char *line,
 +                         struct patch *patch)
  {
 -      patch->new_name = gitdiff_verify_name(line, patch->is_delete, patch->new_name,
 -                                            DIFF_NEW_NAME);
 +      gitdiff_verify_name(state, line,
 +                          patch->is_delete, &patch->new_name,
 +                          DIFF_NEW_NAME);
        return 0;
  }
  
 -static int gitdiff_oldmode(const char *line, struct patch *patch)
 +static int gitdiff_oldmode(struct apply_state *state,
 +                         const char *line,
 +                         struct patch *patch)
  {
        patch->old_mode = strtoul(line, NULL, 8);
        return 0;
  }
  
 -static int gitdiff_newmode(const char *line, struct patch *patch)
 +static int gitdiff_newmode(struct apply_state *state,
 +                         const char *line,
 +                         struct patch *patch)
  {
        patch->new_mode = strtoul(line, NULL, 8);
        return 0;
  }
  
 -static int gitdiff_delete(const char *line, struct patch *patch)
 +static int gitdiff_delete(struct apply_state *state,
 +                        const char *line,
 +                        struct patch *patch)
  {
        patch->is_delete = 1;
        free(patch->old_name);
        patch->old_name = xstrdup_or_null(patch->def_name);
 -      return gitdiff_oldmode(line, patch);
 +      return gitdiff_oldmode(state, line, patch);
  }
  
 -static int gitdiff_newfile(const char *line, struct patch *patch)
 +static int gitdiff_newfile(struct apply_state *state,
 +                         const char *line,
 +                         struct patch *patch)
  {
        patch->is_new = 1;
        free(patch->new_name);
        patch->new_name = xstrdup_or_null(patch->def_name);
 -      return gitdiff_newmode(line, patch);
 +      return gitdiff_newmode(state, line, patch);
  }
  
 -static int gitdiff_copysrc(const char *line, struct patch *patch)
 +static int gitdiff_copysrc(struct apply_state *state,
 +                         const char *line,
 +                         struct patch *patch)
  {
        patch->is_copy = 1;
        free(patch->old_name);
 -      patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
 +      patch->old_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
        return 0;
  }
  
 -static int gitdiff_copydst(const char *line, struct patch *patch)
 +static int gitdiff_copydst(struct apply_state *state,
 +                         const char *line,
 +                         struct patch *patch)
  {
        patch->is_copy = 1;
        free(patch->new_name);
 -      patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
 +      patch->new_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
        return 0;
  }
  
 -static int gitdiff_renamesrc(const char *line, struct patch *patch)
 +static int gitdiff_renamesrc(struct apply_state *state,
 +                           const char *line,
 +                           struct patch *patch)
  {
        patch->is_rename = 1;
        free(patch->old_name);
 -      patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
 +      patch->old_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
        return 0;
  }
  
 -static int gitdiff_renamedst(const char *line, struct patch *patch)
 +static int gitdiff_renamedst(struct apply_state *state,
 +                           const char *line,
 +                           struct patch *patch)
  {
        patch->is_rename = 1;
        free(patch->new_name);
 -      patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
 +      patch->new_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
        return 0;
  }
  
 -static int gitdiff_similarity(const char *line, struct patch *patch)
 +static int gitdiff_similarity(struct apply_state *state,
 +                            const char *line,
 +                            struct patch *patch)
  {
        unsigned long val = strtoul(line, NULL, 10);
        if (val <= 100)
        return 0;
  }
  
 -static int gitdiff_dissimilarity(const char *line, struct patch *patch)
 +static int gitdiff_dissimilarity(struct apply_state *state,
 +                               const char *line,
 +                               struct patch *patch)
  {
        unsigned long val = strtoul(line, NULL, 10);
        if (val <= 100)
        return 0;
  }
  
 -static int gitdiff_index(const char *line, struct patch *patch)
 +static int gitdiff_index(struct apply_state *state,
 +                       const char *line,
 +                       struct patch *patch)
  {
        /*
         * index line is N hexadecimal, "..", N hexadecimal,
   * This is normal for a diff that doesn't change anything: we'll fall through
   * into the next diff. Tell the parser to break out.
   */
 -static int gitdiff_unrecognized(const char *line, struct patch *patch)
 +static int gitdiff_unrecognized(struct apply_state *state,
 +                              const char *line,
 +                              struct patch *patch)
  {
        return -1;
  }
   * Skip p_value leading components from "line"; as we do not accept
   * absolute paths, return NULL in that case.
   */
 -static const char *skip_tree_prefix(const char *line, int llen)
 +static const char *skip_tree_prefix(struct apply_state *state,
 +                                  const char *line,
 +                                  int llen)
  {
        int nslash;
        int i;
  
 -      if (!p_value)
 +      if (!state->p_value)
                return (llen && line[0] == '/') ? NULL : line;
  
 -      nslash = p_value;
 +      nslash = state->p_value;
        for (i = 0; i < llen; i++) {
                int ch = line[i];
                if (ch == '/' && --nslash <= 0)
   * creation or deletion of an empty file.  In any of these cases,
   * both sides are the same name under a/ and b/ respectively.
   */
 -static char *git_header_name(const char *line, int llen)
 +static char *git_header_name(struct apply_state *state,
 +                           const char *line,
 +                           int llen)
  {
        const char *name;
        const char *second = NULL;
                        goto free_and_fail1;
  
                /* strip the a/b prefix including trailing slash */
 -              cp = skip_tree_prefix(first.buf, first.len);
 +              cp = skip_tree_prefix(state, first.buf, first.len);
                if (!cp)
                        goto free_and_fail1;
                strbuf_remove(&first, 0, cp - first.buf);
                if (*second == '"') {
                        if (unquote_c_style(&sp, second, NULL))
                                goto free_and_fail1;
 -                      cp = skip_tree_prefix(sp.buf, sp.len);
 +                      cp = skip_tree_prefix(state, sp.buf, sp.len);
                        if (!cp)
                                goto free_and_fail1;
                        /* They must match, otherwise ignore */
                }
  
                /* unquoted second */
 -              cp = skip_tree_prefix(second, line + llen - second);
 +              cp = skip_tree_prefix(state, second, line + llen - second);
                if (!cp)
                        goto free_and_fail1;
                if (line + llen - cp != first.len ||
        }
  
        /* unquoted first name */
 -      name = skip_tree_prefix(line, llen);
 +      name = skip_tree_prefix(state, line, llen);
        if (!name)
                return NULL;
  
                        if (unquote_c_style(&sp, second, NULL))
                                goto free_and_fail2;
  
 -                      np = skip_tree_prefix(sp.buf, sp.len);
 +                      np = skip_tree_prefix(state, sp.buf, sp.len);
                        if (!np)
                                goto free_and_fail2;
  
                         */
                        if (!name[len + 1])
                                return NULL; /* no postimage name */
 -                      second = skip_tree_prefix(name + len + 1,
 +                      second = skip_tree_prefix(state, name + len + 1,
                                                  line_len - (len + 1));
                        if (!second)
                                return NULL;
  }
  
  /* Verify that we recognize the lines following a git header */
 -static int parse_git_header(const char *line, int len, unsigned int size, struct patch *patch)
 +static int parse_git_header(struct apply_state *state,
 +                          const char *line,
 +                          int len,
 +                          unsigned int size,
 +                          struct patch *patch)
  {
        unsigned long offset;
  
         * or removing or adding empty files), so we get
         * the default name from the header.
         */
 -      patch->def_name = git_header_name(line, len);
 -      if (patch->def_name && root.len) {
 -              char *s = xstrfmt("%s%s", root.buf, patch->def_name);
 +      patch->def_name = git_header_name(state, line, len);
 +      if (patch->def_name && state->root.len) {
 +              char *s = xstrfmt("%s%s", state->root.buf, patch->def_name);
                free(patch->def_name);
                patch->def_name = s;
        }
  
        line += len;
        size -= len;
 -      linenr++;
 -      for (offset = len ; size > 0 ; offset += len, size -= len, line += len, linenr++) {
 +      state->linenr++;
 +      for (offset = len ; size > 0 ; offset += len, size -= len, line += len, state->linenr++) {
                static const struct opentry {
                        const char *str;
 -                      int (*fn)(const char *, struct patch *);
 +                      int (*fn)(struct apply_state *, const char *, struct patch *);
                } optable[] = {
                        { "@@ -", gitdiff_hdrend },
                        { "--- ", gitdiff_oldname },
                        int oplen = strlen(p->str);
                        if (len < oplen || memcmp(p->str, line, oplen))
                                continue;
 -                      if (p->fn(line + oplen, patch) < 0)
 +                      if (p->fn(state, line + oplen, patch) < 0)
                                return offset;
                        break;
                }
@@@ -1514,11 -1431,7 +1514,11 @@@ static int parse_fragment_header(const 
        return offset;
  }
  
 -static int find_header(const char *line, unsigned long size, int *hdrsize, struct patch *patch)
 +static int find_header(struct apply_state *state,
 +                     const char *line,
 +                     unsigned long size,
 +                     int *hdrsize,
 +                     struct patch *patch)
  {
        unsigned long offset, len;
  
        patch->is_new = patch->is_delete = -1;
        patch->old_mode = patch->new_mode = 0;
        patch->old_name = patch->new_name = NULL;
 -      for (offset = 0; size > 0; offset += len, size -= len, line += len, linenr++) {
 +      for (offset = 0; size > 0; offset += len, size -= len, line += len, state->linenr++) {
                unsigned long nextlen;
  
                len = linelen(line, size);
                        if (parse_fragment_header(line, len, &dummy) < 0)
                                continue;
                        die(_("patch fragment without header at line %d: %.*s"),
 -                          linenr, (int)len-1, line);
 +                          state->linenr, (int)len-1, line);
                }
  
                if (size < len + 6)
                 * or mode change, so we handle that specially
                 */
                if (!memcmp("diff --git ", line, 11)) {
 -                      int git_hdr_len = parse_git_header(line, len, size, patch);
 +                      int git_hdr_len = parse_git_header(state, line, len, size, patch);
                        if (git_hdr_len <= len)
                                continue;
                        if (!patch->old_name && !patch->new_name) {
                                               "%d leading pathname component (line %d)",
                                               "git diff header lacks filename information when removing "
                                               "%d leading pathname components (line %d)",
 -                                             p_value),
 -                                          p_value, linenr);
 +                                             state->p_value),
 +                                          state->p_value, state->linenr);
                                patch->old_name = xstrdup(patch->def_name);
                                patch->new_name = xstrdup(patch->def_name);
                        }
                        if (!patch->is_delete && !patch->new_name)
                                die("git diff header lacks filename information "
 -                                  "(line %d)", linenr);
 +                                  "(line %d)", state->linenr);
                        patch->is_toplevel_relative = 1;
                        *hdrsize = git_hdr_len;
                        return offset;
                        continue;
  
                /* Ok, we'll consider it a patch */
 -              parse_traditional_patch(line, line+len, patch);
 +              parse_traditional_patch(state, line, line+len, patch);
                *hdrsize = len + nextlen;
 -              linenr += 2;
 +              state->linenr += 2;
                return offset;
        }
        return -1;
  }
  
 -static void record_ws_error(unsigned result, const char *line, int len, int linenr)
 +static void record_ws_error(struct apply_state *state,
 +                          unsigned result,
 +                          const char *line,
 +                          int len,
 +                          int linenr)
  {
        char *err;
  
        if (!result)
                return;
  
 -      whitespace_error++;
 -      if (squelch_whitespace_errors &&
 -          squelch_whitespace_errors < whitespace_error)
 +      state->whitespace_error++;
 +      if (state->squelch_whitespace_errors &&
 +          state->squelch_whitespace_errors < state->whitespace_error)
                return;
  
        err = whitespace_error_string(result);
        fprintf(stderr, "%s:%d: %s.\n%.*s\n",
 -              patch_input_file, linenr, err, len, line);
 +              state->patch_input_file, linenr, err, len, line);
        free(err);
  }
  
 -static void check_whitespace(const char *line, int len, unsigned ws_rule)
 +static void check_whitespace(struct apply_state *state,
 +                           const char *line,
 +                           int len,
 +                           unsigned ws_rule)
  {
        unsigned result = ws_check(line + 1, len - 1, ws_rule);
  
 -      record_ws_error(result, line + 1, len - 2, linenr);
 +      record_ws_error(state, result, line + 1, len - 2, state->linenr);
  }
  
  /*
   * between a "---" that is part of a patch, and a "---" that starts
   * the next patch is to look at the line counts..
   */
 -static int parse_fragment(const char *line, unsigned long size,
 -                        struct patch *patch, struct fragment *fragment)
 +static int parse_fragment(struct apply_state *state,
 +                        const char *line,
 +                        unsigned long size,
 +                        struct patch *patch,
 +                        struct fragment *fragment)
  {
        int added, deleted;
        int len = linelen(line, size), offset;
        /* Parse the thing.. */
        line += len;
        size -= len;
 -      linenr++;
 +      state->linenr++;
        added = deleted = 0;
        for (offset = len;
             0 < size;
 -           offset += len, size -= len, line += len, linenr++) {
 +           offset += len, size -= len, line += len, state->linenr++) {
                if (!oldlines && !newlines)
                        break;
                len = linelen(line, size);
                        if (!deleted && !added)
                                leading++;
                        trailing++;
 -                      if (!apply_in_reverse &&
 -                          ws_error_action == correct_ws_error)
 -                              check_whitespace(line, len, patch->ws_rule);
 +                      if (!state->apply_in_reverse &&
 +                          state->ws_error_action == correct_ws_error)
 +                              check_whitespace(state, line, len, patch->ws_rule);
                        break;
                case '-':
 -                      if (apply_in_reverse &&
 -                          ws_error_action != nowarn_ws_error)
 -                              check_whitespace(line, len, patch->ws_rule);
 +                      if (state->apply_in_reverse &&
 +                          state->ws_error_action != nowarn_ws_error)
 +                              check_whitespace(state, line, len, patch->ws_rule);
                        deleted++;
                        oldlines--;
                        trailing = 0;
                        break;
                case '+':
 -                      if (!apply_in_reverse &&
 -                          ws_error_action != nowarn_ws_error)
 -                              check_whitespace(line, len, patch->ws_rule);
 +                      if (!state->apply_in_reverse &&
 +                          state->ws_error_action != nowarn_ws_error)
 +                              check_whitespace(state, line, len, patch->ws_rule);
                        added++;
                        newlines--;
                        trailing = 0;
   * The (fragment->patch, fragment->size) pair points into the memory given
   * by the caller, not a copy, when we return.
   */
 -static int parse_single_patch(const char *line, unsigned long size, struct patch *patch)
 +static int parse_single_patch(struct apply_state *state,
 +                            const char *line,
 +                            unsigned long size,
 +                            struct patch *patch)
  {
        unsigned long offset = 0;
        unsigned long oldlines = 0, newlines = 0, context = 0;
                int len;
  
                fragment = xcalloc(1, sizeof(*fragment));
 -              fragment->linenr = linenr;
 -              len = parse_fragment(line, size, patch, fragment);
 +              fragment->linenr = state->linenr;
 +              len = parse_fragment(state, line, size, patch, fragment);
                if (len <= 0)
 -                      die(_("corrupt patch at line %d"), linenr);
 +                      die(_("corrupt patch at line %d"), state->linenr);
                fragment->patch = line;
                fragment->size = len;
                oldlines += fragment->oldlines;
@@@ -1857,8 -1757,7 +1857,8 @@@ static char *inflate_it(const void *dat
   * points at an allocated memory that the caller must free, so
   * it is marked as "->free_patch = 1".
   */
 -static struct fragment *parse_binary_hunk(char **buf_p,
 +static struct fragment *parse_binary_hunk(struct apply_state *state,
 +                                        char **buf_p,
                                          unsigned long *sz_p,
                                          int *status_p,
                                          int *used_p)
        else
                return NULL;
  
 -      linenr++;
 +      state->linenr++;
        buffer += llen;
        while (1) {
                int byte_length, max_byte_length, newsize;
                llen = linelen(buffer, size);
                used += llen;
 -              linenr++;
 +              state->linenr++;
                if (llen == 1) {
                        /* consume the blank line */
                        buffer++;
        free(data);
        *status_p = -1;
        error(_("corrupt binary patch at line %d: %.*s"),
 -            linenr-1, llen-1, buffer);
 +            state->linenr-1, llen-1, buffer);
        return NULL;
  }
  
   *   -1 in case of error,
   *   the length of the parsed binary patch otherwise
   */
 -static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
 +static int parse_binary(struct apply_state *state,
 +                      char *buffer,
 +                      unsigned long size,
 +                      struct patch *patch)
  {
        /*
         * We have read "GIT binary patch\n"; what follows is a line
        int status;
        int used, used_1;
  
 -      forward = parse_binary_hunk(&buffer, &size, &status, &used);
 +      forward = parse_binary_hunk(state, &buffer, &size, &status, &used);
        if (!forward && !status)
                /* there has to be one hunk (forward hunk) */
 -              return error(_("unrecognized binary patch at line %d"), linenr-1);
 +              return error(_("unrecognized binary patch at line %d"), state->linenr-1);
        if (status)
                /* otherwise we already gave an error message */
                return status;
  
 -      reverse = parse_binary_hunk(&buffer, &size, &status, &used_1);
 +      reverse = parse_binary_hunk(state, &buffer, &size, &status, &used_1);
        if (reverse)
                used += used_1;
        else if (status) {
        return used;
  }
  
 -static void prefix_one(char **name)
 +static void prefix_one(struct apply_state *state, char **name)
  {
        char *old_name = *name;
        if (!old_name)
                return;
 -      *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
 +      *name = xstrdup(prefix_filename(state->prefix, state->prefix_length, *name));
        free(old_name);
  }
  
 -static void prefix_patch(struct patch *p)
 +static void prefix_patch(struct apply_state *state, struct patch *p)
  {
 -      if (!prefix || p->is_toplevel_relative)
 +      if (!state->prefix || p->is_toplevel_relative)
                return;
 -      prefix_one(&p->new_name);
 -      prefix_one(&p->old_name);
 +      prefix_one(state, &p->new_name);
 +      prefix_one(state, &p->old_name);
  }
  
  /*
   * include/exclude
   */
  
 -static struct string_list limit_by_name;
 -static int has_include;
 -static void add_name_limit(const char *name, int exclude)
 +static void add_name_limit(struct apply_state *state,
 +                         const char *name,
 +                         int exclude)
  {
        struct string_list_item *it;
  
 -      it = string_list_append(&limit_by_name, name);
 +      it = string_list_append(&state->limit_by_name, name);
        it->util = exclude ? NULL : (void *) 1;
  }
  
 -static int use_patch(struct patch *p)
 +static int use_patch(struct apply_state *state, struct patch *p)
  {
        const char *pathname = p->new_name ? p->new_name : p->old_name;
        int i;
  
        /* Paths outside are not touched regardless of "--include" */
 -      if (0 < prefix_length) {
 +      if (0 < state->prefix_length) {
                int pathlen = strlen(pathname);
 -              if (pathlen <= prefix_length ||
 -                  memcmp(prefix, pathname, prefix_length))
 +              if (pathlen <= state->prefix_length ||
 +                  memcmp(state->prefix, pathname, state->prefix_length))
                        return 0;
        }
  
        /* See if it matches any of exclude/include rule */
 -      for (i = 0; i < limit_by_name.nr; i++) {
 -              struct string_list_item *it = &limit_by_name.items[i];
 +      for (i = 0; i < state->limit_by_name.nr; i++) {
 +              struct string_list_item *it = &state->limit_by_name.items[i];
                if (!wildmatch(it->string, pathname, 0, NULL))
                        return (it->util != NULL);
        }
         * not used.  Otherwise, we saw bunch of exclude rules (or none)
         * and such a path is used.
         */
 -      return !has_include;
 +      return !state->has_include;
  }
  
  
   * Return the number of bytes consumed, so that the caller can call us
   * again for the next patch.
   */
 -static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
 +static int parse_chunk(struct apply_state *state, char *buffer, unsigned long size, struct patch *patch)
  {
        int hdrsize, patchsize;
 -      int offset = find_header(buffer, size, &hdrsize, patch);
 +      int offset = find_header(state, buffer, size, &hdrsize, patch);
  
        if (offset < 0)
                return offset;
  
 -      prefix_patch(patch);
 +      prefix_patch(state, patch);
  
 -      if (!use_patch(patch))
 +      if (!use_patch(state, patch))
                patch->ws_rule = 0;
        else
                patch->ws_rule = whitespace_rule(patch->new_name
                                                 ? patch->new_name
                                                 : patch->old_name);
  
 -      patchsize = parse_single_patch(buffer + offset + hdrsize,
 -                                     size - offset - hdrsize, patch);
 +      patchsize = parse_single_patch(state,
 +                                     buffer + offset + hdrsize,
 +                                     size - offset - hdrsize,
 +                                     patch);
  
        if (!patchsize) {
                static const char git_binary[] = "GIT binary patch\n";
                if (llen == sizeof(git_binary) - 1 &&
                    !memcmp(git_binary, buffer + hd, llen)) {
                        int used;
 -                      linenr++;
 -                      used = parse_binary(buffer + hd + llen,
 +                      state->linenr++;
 +                      used = parse_binary(state, buffer + hd + llen,
                                            size - hd - llen, patch);
                        if (used < 0)
                                return -1;
                                int len = strlen(binhdr[i]);
                                if (len < size - hd &&
                                    !memcmp(binhdr[i], buffer + hd, len)) {
 -                                      linenr++;
 +                                      state->linenr++;
                                        patch->is_binary = 1;
                                        patchsize = llen;
                                        break;
                 * without metadata change.  A binary patch appears
                 * empty to us here.
                 */
 -              if ((apply || check) &&
 +              if ((state->apply || state->check) &&
                    (!patch->is_binary && !metadata_changes(patch)))
 -                      die(_("patch with only garbage at line %d"), linenr);
 +                      die(_("patch with only garbage at line %d"), state->linenr);
        }
  
        return offset + hdrsize + patchsize;
@@@ -2189,7 -2083,7 +2189,7 @@@ static const char pluses[] 
  static const char minuses[]=
  "----------------------------------------------------------------------";
  
 -static void show_stats(struct patch *patch)
 +static void show_stats(struct apply_state *state, struct patch *patch)
  {
        struct strbuf qname = STRBUF_INIT;
        char *cp = patch->new_name ? patch->new_name : patch->old_name;
        /*
         * "scale" the filename
         */
 -      max = max_len;
 +      max = state->max_len;
        if (max > 50)
                max = 50;
  
        /*
         * scale the add/delete
         */
 -      max = max + max_change > 70 ? 70 - max : max_change;
 +      max = max + state->max_change > 70 ? 70 - max : state->max_change;
        add = patch->lines_added;
        del = patch->lines_deleted;
  
 -      if (max_change > 0) {
 -              int total = ((add + del) * max + max_change / 2) / max_change;
 -              add = (add * max + max_change / 2) / max_change;
 +      if (state->max_change > 0) {
 +              int total = ((add + del) * max + state->max_change / 2) / state->max_change;
 +              add = (add * max + state->max_change / 2) / state->max_change;
                del = total - add;
        }
        printf("%5d %.*s%.*s\n", patch->lines_added + patch->lines_deleted,
@@@ -2300,17 -2194,17 +2300,17 @@@ static void update_pre_post_images(stru
        fixed = preimage->buf;
  
        for (i = reduced = ctx = 0; i < postimage->nr; i++) {
 -              size_t len = postimage->line[i].len;
 +              size_t l_len = postimage->line[i].len;
                if (!(postimage->line[i].flag & LINE_COMMON)) {
                        /* an added line -- no counterparts in preimage */
 -                      memmove(new, old, len);
 -                      old += len;
 -                      new += len;
 +                      memmove(new, old, l_len);
 +                      old += l_len;
 +                      new += l_len;
                        continue;
                }
  
                /* a common context -- skip it in the original postimage */
 -              old += len;
 +              old += l_len;
  
                /* and find the corresponding one in the fixed preimage */
                while (ctx < preimage->nr &&
                }
  
                /* and copy it in, while fixing the line length */
 -              len = preimage->line[ctx].len;
 -              memcpy(new, fixed, len);
 -              new += len;
 -              fixed += len;
 -              postimage->line[i].len = len;
 +              l_len = preimage->line[ctx].len;
 +              memcpy(new, fixed, l_len);
 +              new += l_len;
 +              fixed += l_len;
 +              postimage->line[i].len = l_len;
                ctx++;
        }
  
        postimage->nr -= reduced;
  }
  
 -static int match_fragment(struct image *img,
 +static int line_by_line_fuzzy_match(struct image *img,
 +                                  struct image *preimage,
 +                                  struct image *postimage,
 +                                  unsigned long try,
 +                                  int try_lno,
 +                                  int preimage_limit)
 +{
 +      int i;
 +      size_t imgoff = 0;
 +      size_t preoff = 0;
 +      size_t postlen = postimage->len;
 +      size_t extra_chars;
 +      char *buf;
 +      char *preimage_eof;
 +      char *preimage_end;
 +      struct strbuf fixed;
 +      char *fixed_buf;
 +      size_t fixed_len;
 +
 +      for (i = 0; i < preimage_limit; i++) {
 +              size_t prelen = preimage->line[i].len;
 +              size_t imglen = img->line[try_lno+i].len;
 +
 +              if (!fuzzy_matchlines(img->buf + try + imgoff, imglen,
 +                                    preimage->buf + preoff, prelen))
 +                      return 0;
 +              if (preimage->line[i].flag & LINE_COMMON)
 +                      postlen += imglen - prelen;
 +              imgoff += imglen;
 +              preoff += prelen;
 +      }
 +
 +      /*
 +       * Ok, the preimage matches with whitespace fuzz.
 +       *
 +       * imgoff now holds the true length of the target that
 +       * matches the preimage before the end of the file.
 +       *
 +       * Count the number of characters in the preimage that fall
 +       * beyond the end of the file and make sure that all of them
 +       * are whitespace characters. (This can only happen if
 +       * we are removing blank lines at the end of the file.)
 +       */
 +      buf = preimage_eof = preimage->buf + preoff;
 +      for ( ; i < preimage->nr; i++)
 +              preoff += preimage->line[i].len;
 +      preimage_end = preimage->buf + preoff;
 +      for ( ; buf < preimage_end; buf++)
 +              if (!isspace(*buf))
 +                      return 0;
 +
 +      /*
 +       * Update the preimage and the common postimage context
 +       * lines to use the same whitespace as the target.
 +       * If whitespace is missing in the target (i.e.
 +       * if the preimage extends beyond the end of the file),
 +       * use the whitespace from the preimage.
 +       */
 +      extra_chars = preimage_end - preimage_eof;
 +      strbuf_init(&fixed, imgoff + extra_chars);
 +      strbuf_add(&fixed, img->buf + try, imgoff);
 +      strbuf_add(&fixed, preimage_eof, extra_chars);
 +      fixed_buf = strbuf_detach(&fixed, &fixed_len);
 +      update_pre_post_images(preimage, postimage,
 +                             fixed_buf, fixed_len, postlen);
 +      return 1;
 +}
 +
 +static int match_fragment(struct apply_state *state,
 +                        struct image *img,
                          struct image *preimage,
                          struct image *postimage,
                          unsigned long try,
                preimage_limit = preimage->nr;
                if (match_end && (preimage->nr + try_lno != img->nr))
                        return 0;
 -      } else if (ws_error_action == correct_ws_error &&
 +      } else if (state->ws_error_action == correct_ws_error &&
                   (ws_rule & WS_BLANK_AT_EOF)) {
                /*
                 * This hunk extends beyond the end of img, and we are
         * fuzzy matching. We collect all the line length information because
         * we need it to adjust whitespace if we match.
         */
 -      if (ws_ignore_action == ignore_ws_change) {
 -              size_t imgoff = 0;
 -              size_t preoff = 0;
 -              size_t postlen = postimage->len;
 -              size_t extra_chars;
 -              char *preimage_eof;
 -              char *preimage_end;
 -              for (i = 0; i < preimage_limit; i++) {
 -                      size_t prelen = preimage->line[i].len;
 -                      size_t imglen = img->line[try_lno+i].len;
 -
 -                      if (!fuzzy_matchlines(img->buf + try + imgoff, imglen,
 -                                            preimage->buf + preoff, prelen))
 -                              return 0;
 -                      if (preimage->line[i].flag & LINE_COMMON)
 -                              postlen += imglen - prelen;
 -                      imgoff += imglen;
 -                      preoff += prelen;
 -              }
 +      if (state->ws_ignore_action == ignore_ws_change)
 +              return line_by_line_fuzzy_match(img, preimage, postimage,
 +                                              try, try_lno, preimage_limit);
  
 -              /*
 -               * Ok, the preimage matches with whitespace fuzz.
 -               *
 -               * imgoff now holds the true length of the target that
 -               * matches the preimage before the end of the file.
 -               *
 -               * Count the number of characters in the preimage that fall
 -               * beyond the end of the file and make sure that all of them
 -               * are whitespace characters. (This can only happen if
 -               * we are removing blank lines at the end of the file.)
 -               */
 -              buf = preimage_eof = preimage->buf + preoff;
 -              for ( ; i < preimage->nr; i++)
 -                      preoff += preimage->line[i].len;
 -              preimage_end = preimage->buf + preoff;
 -              for ( ; buf < preimage_end; buf++)
 -                      if (!isspace(*buf))
 -                              return 0;
 -
 -              /*
 -               * Update the preimage and the common postimage context
 -               * lines to use the same whitespace as the target.
 -               * If whitespace is missing in the target (i.e.
 -               * if the preimage extends beyond the end of the file),
 -               * use the whitespace from the preimage.
 -               */
 -              extra_chars = preimage_end - preimage_eof;
 -              strbuf_init(&fixed, imgoff + extra_chars);
 -              strbuf_add(&fixed, img->buf + try, imgoff);
 -              strbuf_add(&fixed, preimage_eof, extra_chars);
 -              fixed_buf = strbuf_detach(&fixed, &fixed_len);
 -              update_pre_post_images(preimage, postimage,
 -                              fixed_buf, fixed_len, postlen);
 -              return 1;
 -      }
 -
 -      if (ws_error_action != correct_ws_error)
 +      if (state->ws_error_action != correct_ws_error)
                return 0;
  
        /*
        return 0;
  }
  
 -static int find_pos(struct image *img,
 +static int find_pos(struct apply_state *state,
 +                  struct image *img,
                    struct image *preimage,
                    struct image *postimage,
                    int line,
        try_lno = line;
  
        for (i = 0; ; i++) {
 -              if (match_fragment(img, preimage, postimage,
 +              if (match_fragment(state, img, preimage, postimage,
                                   try, try_lno, ws_rule,
                                   match_beginning, match_end))
                        return try_lno;
@@@ -2718,8 -2594,7 +2718,8 @@@ static void remove_last_line(struct ima
   * apply at applied_pos (counts in line numbers) in "img".
   * Update "img" to remove "preimage" and replace it with "postimage".
   */
 -static void update_image(struct image *img,
 +static void update_image(struct apply_state *state,
 +                       struct image *img,
                         int applied_pos,
                         struct image *preimage,
                         struct image *postimage)
        memcpy(img->line + applied_pos,
               postimage->line,
               postimage->nr * sizeof(*img->line));
 -      if (!allow_overlap)
 +      if (!state->allow_overlap)
                for (i = 0; i < postimage->nr; i++)
                        img->line[applied_pos + i].flag |= LINE_PATCHED;
        img->nr = nr;
   * postimage) for the hunk.  Find lines that match "preimage" in "img" and
   * replace the part of "img" with "postimage" text.
   */
 -static int apply_one_fragment(struct image *img, struct fragment *frag,
 +static int apply_one_fragment(struct apply_state *state,
 +                            struct image *img, struct fragment *frag,
                              int inaccurate_eof, unsigned ws_rule,
                              int nth_fragment)
  {
                if (len < size && patch[len] == '\\')
                        plen--;
                first = *patch;
 -              if (apply_in_reverse) {
 +              if (state->apply_in_reverse) {
                        if (first == '-')
                                first = '+';
                        else if (first == '+')
                /* Fall-through for ' ' */
                case '+':
                        /* --no-add does not add new lines */
 -                      if (first == '+' && no_add)
 +                      if (first == '+' && state->no_add)
                                break;
  
                        start = newlines.len;
                        if (first != '+' ||
 -                          !whitespace_error ||
 -                          ws_error_action != correct_ws_error) {
 +                          !state->whitespace_error ||
 +                          state->ws_error_action != correct_ws_error) {
                                strbuf_add(&newlines, patch + 1, plen);
                        }
                        else {
 -                              ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &applied_after_fixing_ws);
 +                              ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &state->applied_after_fixing_ws);
                        }
                        add_line_info(&postimage, newlines.buf + start, newlines.len - start,
                                      (first == '+' ? 0 : LINE_COMMON));
                        /* Ignore it, we already handled it */
                        break;
                default:
 -                      if (apply_verbosely)
 +                      if (state->apply_verbosely)
                                error(_("invalid start of line: '%c'"), first);
                        applied_pos = -1;
                        goto out;
         * without leading context must match at the beginning.
         */
        match_beginning = (!frag->oldpos ||
 -                         (frag->oldpos == 1 && !unidiff_zero));
 +                         (frag->oldpos == 1 && !state->unidiff_zero));
  
        /*
         * A hunk without trailing lines must match at the end.
         * from the lack of trailing lines if the patch was generated
         * with unidiff without any context.
         */
 -      match_end = !unidiff_zero && !trailing;
 +      match_end = !state->unidiff_zero && !trailing;
  
        pos = frag->newpos ? (frag->newpos - 1) : 0;
        preimage.buf = oldlines;
  
        for (;;) {
  
 -              applied_pos = find_pos(img, &preimage, &postimage, pos,
 +              applied_pos = find_pos(state, img, &preimage, &postimage, pos,
                                       ws_rule, match_beginning, match_end);
  
                if (applied_pos >= 0)
                        break;
  
                /* Am I at my context limits? */
 -              if ((leading <= p_context) && (trailing <= p_context))
 +              if ((leading <= state->p_context) && (trailing <= state->p_context))
                        break;
                if (match_beginning || match_end) {
                        match_beginning = match_end = 0;
                if (new_blank_lines_at_end &&
                    preimage.nr + applied_pos >= img->nr &&
                    (ws_rule & WS_BLANK_AT_EOF) &&
 -                  ws_error_action != nowarn_ws_error) {
 -                      record_ws_error(WS_BLANK_AT_EOF, "+", 1,
 +                  state->ws_error_action != nowarn_ws_error) {
 +                      record_ws_error(state, WS_BLANK_AT_EOF, "+", 1,
                                        found_new_blank_lines_at_end);
 -                      if (ws_error_action == correct_ws_error) {
 +                      if (state->ws_error_action == correct_ws_error) {
                                while (new_blank_lines_at_end--)
                                        remove_last_line(&postimage);
                        }
                         * apply_patch->check_patch_list->check_patch->
                         * apply_data->apply_fragments->apply_one_fragment
                         */
 -                      if (ws_error_action == die_on_ws_error)
 -                              apply = 0;
 +                      if (state->ws_error_action == die_on_ws_error)
 +                              state->apply = 0;
                }
  
 -              if (apply_verbosely && applied_pos != pos) {
 +              if (state->apply_verbosely && applied_pos != pos) {
                        int offset = applied_pos - pos;
 -                      if (apply_in_reverse)
 +                      if (state->apply_in_reverse)
                                offset = 0 - offset;
                        fprintf_ln(stderr,
                                   Q_("Hunk #%d succeeded at %d (offset %d line).",
                        fprintf_ln(stderr, _("Context reduced to (%ld/%ld)"
                                             " to apply fragment at %d"),
                                   leading, trailing, applied_pos+1);
 -              update_image(img, applied_pos, &preimage, &postimage);
 +              update_image(state, img, applied_pos, &preimage, &postimage);
        } else {
 -              if (apply_verbosely)
 +              if (state->apply_verbosely)
                        error(_("while searching for:\n%.*s"),
                              (int)(old - oldlines), oldlines);
        }
@@@ -3048,9 -2922,7 +3048,9 @@@ out
        return (applied_pos < 0);
  }
  
 -static int apply_binary_fragment(struct image *img, struct patch *patch)
 +static int apply_binary_fragment(struct apply_state *state,
 +                               struct image *img,
 +                               struct patch *patch)
  {
        struct fragment *fragment = patch->fragments;
        unsigned long len;
                             patch->old_name);
  
        /* Binary patch is irreversible without the optional second hunk */
 -      if (apply_in_reverse) {
 +      if (state->apply_in_reverse) {
                if (!fragment->next)
                        return error("cannot reverse-apply a binary patch "
                                     "without the reverse hunk to '%s'",
   * but the preimage prepared by the caller in "img" is freed here
   * or in the helper function apply_binary_fragment() this calls.
   */
 -static int apply_binary(struct image *img, struct patch *patch)
 +static int apply_binary(struct apply_state *state,
 +                      struct image *img,
 +                      struct patch *patch)
  {
        const char *name = patch->old_name ? patch->old_name : patch->new_name;
        unsigned char sha1[20];
                 * apply the patch data to it, which is stored
                 * in the patch->fragments->{patch,size}.
                 */
 -              if (apply_binary_fragment(img, patch))
 +              if (apply_binary_fragment(state, img, patch))
                        return error(_("binary patch does not apply to '%s'"),
                                     name);
  
        return 0;
  }
  
 -static int apply_fragments(struct image *img, struct patch *patch)
 +static int apply_fragments(struct apply_state *state, struct image *img, struct patch *patch)
  {
        struct fragment *frag = patch->fragments;
        const char *name = patch->old_name ? patch->old_name : patch->new_name;
        int nth = 0;
  
        if (patch->is_binary)
 -              return apply_binary(img, patch);
 +              return apply_binary(state, img, patch);
  
        while (frag) {
                nth++;
 -              if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule, nth)) {
 +              if (apply_one_fragment(state, img, frag, inaccurate_eof, ws_rule, nth)) {
                        error(_("patch failed: %s:%ld"), name, frag->oldpos);
 -                      if (!apply_with_reject)
 +                      if (!state->apply_with_reject)
                                return -1;
                        frag->rejected = 1;
                }
@@@ -3223,14 -3093,14 +3223,14 @@@ static int read_file_or_gitlink(const s
        return read_blob_object(buf, ce->sha1, ce->ce_mode);
  }
  
 -static struct patch *in_fn_table(const char *name)
 +static struct patch *in_fn_table(struct apply_state *state, const char *name)
  {
        struct string_list_item *item;
  
        if (name == NULL)
                return NULL;
  
 -      item = string_list_lookup(&fn_table, name);
 +      item = string_list_lookup(&state->fn_table, name);
        if (item != NULL)
                return (struct patch *)item->util;
  
@@@ -3262,7 -3132,7 +3262,7 @@@ static int was_deleted(struct patch *pa
        return patch == PATH_WAS_DELETED;
  }
  
 -static void add_to_fn_table(struct patch *patch)
 +static void add_to_fn_table(struct apply_state *state, struct patch *patch)
  {
        struct string_list_item *item;
  
         * file creations and copies
         */
        if (patch->new_name != NULL) {
 -              item = string_list_insert(&fn_table, patch->new_name);
 +              item = string_list_insert(&state->fn_table, patch->new_name);
                item->util = patch;
        }
  
         * later chunks shouldn't patch old names
         */
        if ((patch->new_name == NULL) || (patch->is_rename)) {
 -              item = string_list_insert(&fn_table, patch->old_name);
 +              item = string_list_insert(&state->fn_table, patch->old_name);
                item->util = PATH_WAS_DELETED;
        }
  }
  
 -static void prepare_fn_table(struct patch *patch)
 +static void prepare_fn_table(struct apply_state *state, struct patch *patch)
  {
        /*
         * store information about incoming file deletion
        while (patch) {
                if ((patch->new_name == NULL) || (patch->is_rename)) {
                        struct string_list_item *item;
 -                      item = string_list_insert(&fn_table, patch->old_name);
 +                      item = string_list_insert(&state->fn_table, patch->old_name);
                        item->util = PATH_TO_BE_DELETED;
                }
                patch = patch->next;
@@@ -3315,9 -3185,7 +3315,9 @@@ static int checkout_target(struct index
        return 0;
  }
  
 -static struct patch *previous_patch(struct patch *patch, int *gone)
 +static struct patch *previous_patch(struct apply_state *state,
 +                                  struct patch *patch,
 +                                  int *gone)
  {
        struct patch *previous;
  
        if (patch->is_copy || patch->is_rename)
                return NULL; /* "git" patches do not depend on the order */
  
 -      previous = in_fn_table(patch->old_name);
 +      previous = in_fn_table(state, patch->old_name);
        if (!previous)
                return NULL;
  
@@@ -3350,16 -3218,15 +3350,16 @@@ static int verify_index_match(const str
  
  #define SUBMODULE_PATCH_WITHOUT_INDEX 1
  
 -static int load_patch_target(struct strbuf *buf,
 +static int load_patch_target(struct apply_state *state,
 +                           struct strbuf *buf,
                             const struct cache_entry *ce,
                             struct stat *st,
                             const char *name,
                             unsigned expected_mode)
  {
 -      if (cached || check_index) {
 +      if (state->cached || state->check_index) {
                if (read_file_or_gitlink(ce, buf))
-                       return error(_("read of %s failed"), name);
+                       return error(_("failed to read %s"), name);
        } else if (name) {
                if (S_ISGITLINK(expected_mode)) {
                        if (ce)
                        return error(_("reading from '%s' beyond a symbolic link"), name);
                } else {
                        if (read_old_data(st, name, buf))
-                               return error(_("read of %s failed"), name);
+                               return error(_("failed to read %s"), name);
                }
        }
        return 0;
   * applying a non-git patch that incrementally updates the tree,
   * we read from the result of a previous diff.
   */
 -static int load_preimage(struct image *image,
 +static int load_preimage(struct apply_state *state,
 +                       struct image *image,
                         struct patch *patch, struct stat *st,
                         const struct cache_entry *ce)
  {
        struct patch *previous;
        int status;
  
 -      previous = previous_patch(patch, &status);
 +      previous = previous_patch(state, patch, &status);
        if (status)
                return error(_("path %s has been renamed/deleted"),
                             patch->old_name);
                /* We have a patched copy in memory; use that. */
                strbuf_add(&buf, previous->result, previous->resultsize);
        } else {
 -              status = load_patch_target(&buf, ce, st,
 +              status = load_patch_target(state, &buf, ce, st,
                                           patch->old_name, patch->old_mode);
                if (status < 0)
                        return status;
                        free_fragment_list(patch->fragments);
                        patch->fragments = NULL;
                } else if (status) {
-                       return error(_("read of %s failed"), patch->old_name);
+                       return error(_("failed to read %s"), patch->old_name);
                }
        }
  
@@@ -3461,9 -3327,7 +3461,9 @@@ static int three_way_merge(struct imag
   * the current contents of the new_name.  In no cases other than that
   * this function will be called.
   */
 -static int load_current(struct image *image, struct patch *patch)
 +static int load_current(struct apply_state *state,
 +                      struct image *image,
 +                      struct patch *patch)
  {
        struct strbuf buf = STRBUF_INIT;
        int status, pos;
        if (verify_index_match(ce, &st))
                return error(_("%s: does not match index"), name);
  
 -      status = load_patch_target(&buf, ce, &st, name, mode);
 +      status = load_patch_target(state, &buf, ce, &st, name, mode);
        if (status < 0)
                return status;
        else if (status)
        return 0;
  }
  
 -static int try_threeway(struct image *image, struct patch *patch,
 -                      struct stat *st, const struct cache_entry *ce)
 +static int try_threeway(struct apply_state *state,
 +                      struct image *image,
 +                      struct patch *patch,
 +                      struct stat *st,
 +                      const struct cache_entry *ce)
  {
        unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
        struct strbuf buf = STRBUF_INIT;
        img = strbuf_detach(&buf, &len);
        prepare_image(&tmp_image, img, len, 1);
        /* Apply the patch to get the post image */
 -      if (apply_fragments(&tmp_image, patch) < 0) {
 +      if (apply_fragments(state, &tmp_image, patch) < 0) {
                clear_image(&tmp_image);
                return -1;
        }
  
        /* our_sha1[] is ours */
        if (patch->is_new) {
 -              if (load_current(&tmp_image, patch))
 +              if (load_current(state, &tmp_image, patch))
                        return error("cannot read the current contents of '%s'",
                                     patch->new_name);
        } else {
 -              if (load_preimage(&tmp_image, patch, st, ce))
 +              if (load_preimage(state, &tmp_image, patch, st, ce))
                        return error("cannot read the current contents of '%s'",
                                     patch->old_name);
        }
        return 0;
  }
  
 -static int apply_data(struct patch *patch, struct stat *st, const struct cache_entry *ce)
 +static int apply_data(struct apply_state *state, struct patch *patch,
 +                    struct stat *st, const struct cache_entry *ce)
  {
        struct image image;
  
 -      if (load_preimage(&image, patch, st, ce) < 0)
 +      if (load_preimage(state, &image, patch, st, ce) < 0)
                return -1;
  
        if (patch->direct_to_threeway ||
 -          apply_fragments(&image, patch) < 0) {
 +          apply_fragments(state, &image, patch) < 0) {
                /* Note: with --reject, apply_fragments() returns 0 */
 -              if (!threeway || try_threeway(&image, patch, st, ce) < 0)
 +              if (!state->threeway || try_threeway(state, &image, patch, st, ce) < 0)
                        return -1;
        }
        patch->result = image.buf;
        patch->resultsize = image.len;
 -      add_to_fn_table(patch);
 +      add_to_fn_table(state, patch);
        free(image.line_allocated);
  
        if (0 < patch->is_delete && patch->resultsize)
   * check_patch() separately makes sure (and errors out otherwise) that
   * the path the patch creates does not exist in the current tree.
   */
 -static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
 +static int check_preimage(struct apply_state *state,
 +                        struct patch *patch,
 +                        struct cache_entry **ce,
 +                        struct stat *st)
  {
        const char *old_name = patch->old_name;
        struct patch *previous = NULL;
                return 0;
  
        assert(patch->is_new <= 0);
 -      previous = previous_patch(patch, &status);
 +      previous = previous_patch(state, patch, &status);
  
        if (status)
                return error(_("path %s has been renamed/deleted"), old_name);
        if (previous) {
                st_mode = previous->new_mode;
 -      } else if (!cached) {
 +      } else if (!state->cached) {
                stat_ret = lstat(old_name, st);
                if (stat_ret && errno != ENOENT)
                        return error(_("%s: %s"), old_name, strerror(errno));
        }
  
 -      if (check_index && !previous) {
 +      if (state->check_index && !previous) {
                int pos = cache_name_pos(old_name, strlen(old_name));
                if (pos < 0) {
                        if (patch->is_new < 0)
                        if (checkout_target(&the_index, *ce, st))
                                return -1;
                }
 -              if (!cached && verify_index_match(*ce, st))
 +              if (!state->cached && verify_index_match(*ce, st))
                        return error(_("%s: does not match index"), old_name);
 -              if (cached)
 +              if (state->cached)
                        st_mode = (*ce)->ce_mode;
        } else if (stat_ret < 0) {
                if (patch->is_new < 0)
                return error(_("%s: %s"), old_name, strerror(errno));
        }
  
 -      if (!cached && !previous)
 +      if (!state->cached && !previous)
                st_mode = ce_mode_from_stat(*ce, st->st_mode);
  
        if (patch->is_new < 0)
  #define EXISTS_IN_INDEX 1
  #define EXISTS_IN_WORKTREE 2
  
 -static int check_to_create(const char *new_name, int ok_if_exists)
 +static int check_to_create(struct apply_state *state,
 +                         const char *new_name,
 +                         int ok_if_exists)
  {
        struct stat nst;
  
 -      if (check_index &&
 +      if (state->check_index &&
            cache_name_pos(new_name, strlen(new_name)) >= 0 &&
            !ok_if_exists)
                return EXISTS_IN_INDEX;
 -      if (cached)
 +      if (state->cached)
                return 0;
  
        if (!lstat(new_name, &nst)) {
        return 0;
  }
  
 -/*
 - * We need to keep track of how symlinks in the preimage are
 - * manipulated by the patches.  A patch to add a/b/c where a/b
 - * is a symlink should not be allowed to affect the directory
 - * the symlink points at, but if the same patch removes a/b,
 - * it is perfectly fine, as the patch removes a/b to make room
 - * to create a directory a/b so that a/b/c can be created.
 - */
 -static struct string_list symlink_changes;
 -#define SYMLINK_GOES_AWAY 01
 -#define SYMLINK_IN_RESULT 02
 -
 -static uintptr_t register_symlink_changes(const char *path, uintptr_t what)
 +static uintptr_t register_symlink_changes(struct apply_state *state,
 +                                        const char *path,
 +                                        uintptr_t what)
  {
        struct string_list_item *ent;
  
 -      ent = string_list_lookup(&symlink_changes, path);
 +      ent = string_list_lookup(&state->symlink_changes, path);
        if (!ent) {
 -              ent = string_list_insert(&symlink_changes, path);
 +              ent = string_list_insert(&state->symlink_changes, path);
                ent->util = (void *)0;
        }
        ent->util = (void *)(what | ((uintptr_t)ent->util));
        return (uintptr_t)ent->util;
  }
  
 -static uintptr_t check_symlink_changes(const char *path)
 +static uintptr_t check_symlink_changes(struct apply_state *state, const char *path)
  {
        struct string_list_item *ent;
  
 -      ent = string_list_lookup(&symlink_changes, path);
 +      ent = string_list_lookup(&state->symlink_changes, path);
        if (!ent)
                return 0;
        return (uintptr_t)ent->util;
  }
  
 -static void prepare_symlink_changes(struct patch *patch)
 +static void prepare_symlink_changes(struct apply_state *state, struct patch *patch)
  {
        for ( ; patch; patch = patch->next) {
                if ((patch->old_name && S_ISLNK(patch->old_mode)) &&
                    (patch->is_rename || patch->is_delete))
                        /* the symlink at patch->old_name is removed */
 -                      register_symlink_changes(patch->old_name, SYMLINK_GOES_AWAY);
 +                      register_symlink_changes(state, patch->old_name, SYMLINK_GOES_AWAY);
  
                if (patch->new_name && S_ISLNK(patch->new_mode))
                        /* the symlink at patch->new_name is created or remains */
 -                      register_symlink_changes(patch->new_name, SYMLINK_IN_RESULT);
 +                      register_symlink_changes(state, patch->new_name, SYMLINK_IN_RESULT);
        }
  }
  
 -static int path_is_beyond_symlink_1(struct strbuf *name)
 +static int path_is_beyond_symlink_1(struct apply_state *state, struct strbuf *name)
  {
        do {
                unsigned int change;
                if (!name->len)
                        break;
                name->buf[name->len] = '\0';
 -              change = check_symlink_changes(name->buf);
 +              change = check_symlink_changes(state, name->buf);
                if (change & SYMLINK_IN_RESULT)
                        return 1;
                if (change & SYMLINK_GOES_AWAY)
                        continue;
  
                /* otherwise, check the preimage */
 -              if (check_index) {
 +              if (state->check_index) {
                        struct cache_entry *ce;
  
                        ce = cache_file_exists(name->buf, name->len, ignore_case);
        return 0;
  }
  
 -static int path_is_beyond_symlink(const char *name_)
 +static int path_is_beyond_symlink(struct apply_state *state, const char *name_)
  {
        int ret;
        struct strbuf name = STRBUF_INIT;
  
        assert(*name_ != '\0');
        strbuf_addstr(&name, name_);
 -      ret = path_is_beyond_symlink_1(&name);
 +      ret = path_is_beyond_symlink_1(state, &name);
        strbuf_release(&name);
  
        return ret;
@@@ -3828,7 -3693,7 +3828,7 @@@ static void die_on_unsafe_path(struct p
   * Check and apply the patch in-core; leave the result in patch->result
   * for the caller to write it out to the final destination.
   */
 -static int check_patch(struct patch *patch)
 +static int check_patch(struct apply_state *state, struct patch *patch)
  {
        struct stat st;
        const char *old_name = patch->old_name;
  
        patch->rejected = 1; /* we will drop this after we succeed */
  
 -      status = check_preimage(patch, &ce, &st);
 +      status = check_preimage(state, patch, &ce, &st);
        if (status)
                return status;
        old_name = patch->old_name;
         * B and rename from A to B is handled the same way by asking
         * was_deleted().
         */
 -      if ((tpatch = in_fn_table(new_name)) &&
 +      if ((tpatch = in_fn_table(state, new_name)) &&
            (was_deleted(tpatch) || to_be_deleted(tpatch)))
                ok_if_exists = 1;
        else
  
        if (new_name &&
            ((0 < patch->is_new) || patch->is_rename || patch->is_copy)) {
 -              int err = check_to_create(new_name, ok_if_exists);
 +              int err = check_to_create(state, new_name, ok_if_exists);
  
 -              if (err && threeway) {
 +              if (err && state->threeway) {
                        patch->direct_to_threeway = 1;
                } else switch (err) {
                case 0:
                }
        }
  
 -      if (!unsafe_paths)
 +      if (!state->unsafe_paths)
                die_on_unsafe_path(patch);
  
        /*
         * is not deposited to a path that is beyond a symbolic link
         * here.
         */
 -      if (!patch->is_delete && path_is_beyond_symlink(patch->new_name))
 +      if (!patch->is_delete && path_is_beyond_symlink(state, patch->new_name))
                return error(_("affected file '%s' is beyond a symbolic link"),
                             patch->new_name);
  
 -      if (apply_data(patch, &st, ce) < 0)
 +      if (apply_data(state, patch, &st, ce) < 0)
                return error(_("%s: patch does not apply"), name);
        patch->rejected = 0;
        return 0;
  }
  
 -static int check_patch_list(struct patch *patch)
 +static int check_patch_list(struct apply_state *state, struct patch *patch)
  {
        int err = 0;
  
 -      prepare_symlink_changes(patch);
 -      prepare_fn_table(patch);
 +      prepare_symlink_changes(state, patch);
 +      prepare_fn_table(state, patch);
        while (patch) {
 -              if (apply_verbosely)
 +              if (state->apply_verbosely)
                        say_patch_name(stderr,
                                       _("Checking patch %s..."), patch);
 -              err |= check_patch(patch);
 +              err |= check_patch(state, patch);
                patch = patch->next;
        }
        return err;
@@@ -4047,7 -3912,7 +4047,7 @@@ static void build_fake_ancestor(struct 
        discard_index(&result);
  }
  
 -static void stat_patch_list(struct patch *patch)
 +static void stat_patch_list(struct apply_state *state, struct patch *patch)
  {
        int files, adds, dels;
  
                files++;
                adds += patch->lines_added;
                dels += patch->lines_deleted;
 -              show_stats(patch);
 +              show_stats(state, patch);
        }
  
        print_stat_summary(stdout, files, adds, dels);
  }
  
 -static void numstat_patch_list(struct patch *patch)
 +static void numstat_patch_list(struct apply_state *state,
 +                             struct patch *patch)
  {
        for ( ; patch; patch = patch->next) {
                const char *name;
                        printf("-\t-\t");
                else
                        printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
 -              write_name_quoted(name, stdout, line_termination);
 +              write_name_quoted(name, stdout, state->line_termination);
        }
  }
  
@@@ -4153,53 -4017,49 +4153,53 @@@ static void summary_patch_list(struct p
        }
  }
  
 -static void patch_stats(struct patch *patch)
 +static void patch_stats(struct apply_state *state, struct patch *patch)
  {
        int lines = patch->lines_added + patch->lines_deleted;
  
 -      if (lines > max_change)
 -              max_change = lines;
 +      if (lines > state->max_change)
 +              state->max_change = lines;
        if (patch->old_name) {
                int len = quote_c_style(patch->old_name, NULL, NULL, 0);
                if (!len)
                        len = strlen(patch->old_name);
 -              if (len > max_len)
 -                      max_len = len;
 +              if (len > state->max_len)
 +                      state->max_len = len;
        }
        if (patch->new_name) {
                int len = quote_c_style(patch->new_name, NULL, NULL, 0);
                if (!len)
                        len = strlen(patch->new_name);
 -              if (len > max_len)
 -                      max_len = len;
 +              if (len > state->max_len)
 +                      state->max_len = len;
        }
  }
  
 -static void remove_file(struct patch *patch, int rmdir_empty)
 +static void remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
  {
 -      if (update_index) {
 +      if (state->update_index) {
                if (remove_file_from_cache(patch->old_name) < 0)
                        die(_("unable to remove %s from index"), patch->old_name);
        }
 -      if (!cached) {
 +      if (!state->cached) {
                if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
                        remove_path(patch->old_name);
                }
        }
  }
  
 -static void add_index_file(const char *path, unsigned mode, void *buf, unsigned long size)
 +static void add_index_file(struct apply_state *state,
 +                         const char *path,
 +                         unsigned mode,
 +                         void *buf,
 +                         unsigned long size)
  {
        struct stat st;
        struct cache_entry *ce;
        int namelen = strlen(path);
        unsigned ce_size = cache_entry_size(namelen);
  
 -      if (!update_index)
 +      if (!state->update_index)
                return;
  
        ce = xcalloc(1, ce_size);
                    get_sha1_hex(s, ce->sha1))
                        die(_("corrupt patch for submodule %s"), path);
        } else {
 -              if (!cached) {
 +              if (!state->cached) {
                        if (lstat(path, &st) < 0)
                                die_errno(_("unable to stat newly created file '%s'"),
                                          path);
@@@ -4266,13 -4126,9 +4266,13 @@@ static int try_create_file(const char *
   * which is true 99% of the time anyway. If they don't,
   * we create them and try again.
   */
 -static void create_one_file(char *path, unsigned mode, const char *buf, unsigned long size)
 +static void create_one_file(struct apply_state *state,
 +                          char *path,
 +                          unsigned mode,
 +                          const char *buf,
 +                          unsigned long size)
  {
 -      if (cached)
 +      if (state->cached)
                return;
        if (!try_create_file(path, mode, buf, size))
                return;
        die_errno(_("unable to write file '%s' mode %o"), path, mode);
  }
  
 -static void add_conflicted_stages_file(struct patch *patch)
 +static void add_conflicted_stages_file(struct apply_state *state,
 +                                     struct patch *patch)
  {
        int stage, namelen;
        unsigned ce_size, mode;
        struct cache_entry *ce;
  
 -      if (!update_index)
 +      if (!state->update_index)
                return;
        namelen = strlen(patch->new_name);
        ce_size = cache_entry_size(namelen);
        }
  }
  
 -static void create_file(struct patch *patch)
 +static void create_file(struct apply_state *state, struct patch *patch)
  {
        char *path = patch->new_name;
        unsigned mode = patch->new_mode;
  
        if (!mode)
                mode = S_IFREG | 0644;
 -      create_one_file(path, mode, buf, size);
 +      create_one_file(state, path, mode, buf, size);
  
        if (patch->conflicted_threeway)
 -              add_conflicted_stages_file(patch);
 +              add_conflicted_stages_file(state, patch);
        else
 -              add_index_file(path, mode, buf, size);
 +              add_index_file(state, path, mode, buf, size);
  }
  
  /* phase zero is to remove, phase one is to create */
 -static void write_out_one_result(struct patch *patch, int phase)
 +static void write_out_one_result(struct apply_state *state,
 +                               struct patch *patch,
 +                               int phase)
  {
        if (patch->is_delete > 0) {
                if (phase == 0)
 -                      remove_file(patch, 1);
 +                      remove_file(state, patch, 1);
                return;
        }
        if (patch->is_new > 0 || patch->is_copy) {
                if (phase == 1)
 -                      create_file(patch);
 +                      create_file(state, patch);
                return;
        }
        /*
         * thing: remove the old, write the new
         */
        if (phase == 0)
 -              remove_file(patch, patch->is_rename);
 +              remove_file(state, patch, patch->is_rename);
        if (phase == 1)
 -              create_file(patch);
 +              create_file(state, patch);
  }
  
 -static int write_out_one_reject(struct patch *patch)
 +static int write_out_one_reject(struct apply_state *state, struct patch *patch)
  {
        FILE *rej;
        char namebuf[PATH_MAX];
        }
  
        if (!cnt) {
 -              if (apply_verbosely)
 +              if (state->apply_verbosely)
                        say_patch_name(stderr,
                                       _("Applied patch %s cleanly."), patch);
                return 0;
        return -1;
  }
  
 -static int write_out_results(struct patch *list)
 +static int write_out_results(struct apply_state *state, struct patch *list)
  {
        int phase;
        int errs = 0;
                        if (l->rejected)
                                errs = 1;
                        else {
 -                              write_out_one_result(l, phase);
 +                              write_out_one_result(state, l, phase);
                                if (phase == 1) {
 -                                      if (write_out_one_reject(l))
 +                                      if (write_out_one_reject(state, l))
                                                errs = 1;
                                        if (l->conflicted_threeway) {
                                                string_list_append(&cpath, l->new_name);
@@@ -4500,17 -4353,14 +4500,17 @@@ static struct lock_file lock_file
  #define INACCURATE_EOF        (1<<0)
  #define RECOUNT               (1<<1)
  
 -static int apply_patch(int fd, const char *filename, int options)
 +static int apply_patch(struct apply_state *state,
 +                     int fd,
 +                     const char *filename,
 +                     int options)
  {
        size_t offset;
        struct strbuf buf = STRBUF_INIT; /* owns the patch text */
        struct patch *list = NULL, **listp = &list;
        int skipped_patch = 0;
  
 -      patch_input_file = filename;
 +      state->patch_input_file = filename;
        read_patch_file(&buf, fd);
        offset = 0;
        while (offset < buf.len) {
                patch = xcalloc(1, sizeof(*patch));
                patch->inaccurate_eof = !!(options & INACCURATE_EOF);
                patch->recount =  !!(options & RECOUNT);
 -              nr = parse_chunk(buf.buf + offset, buf.len - offset, patch);
 +              nr = parse_chunk(state, buf.buf + offset, buf.len - offset, patch);
                if (nr < 0) {
                        free_patch(patch);
                        break;
                }
 -              if (apply_in_reverse)
 +              if (state->apply_in_reverse)
                        reverse_patches(patch);
 -              if (use_patch(patch)) {
 -                      patch_stats(patch);
 +              if (use_patch(state, patch)) {
 +                      patch_stats(state, patch);
                        *listp = patch;
                        listp = &patch->next;
                }
                else {
 -                      if (apply_verbosely)
 +                      if (state->apply_verbosely)
                                say_patch_name(stderr, _("Skipped patch '%s'."), patch);
                        free_patch(patch);
                        skipped_patch++;
        if (!list && !skipped_patch)
                die(_("unrecognized input"));
  
 -      if (whitespace_error && (ws_error_action == die_on_ws_error))
 -              apply = 0;
 +      if (state->whitespace_error && (state->ws_error_action == die_on_ws_error))
 +              state->apply = 0;
  
 -      update_index = check_index && apply;
 -      if (update_index && newfd < 0)
 -              newfd = hold_locked_index(&lock_file, 1);
 +      state->update_index = state->check_index && state->apply;
 +      if (state->update_index && state->newfd < 0)
 +              state->newfd = hold_locked_index(state->lock_file, 1);
  
 -      if (check_index) {
 +      if (state->check_index) {
                if (read_cache() < 0)
                        die(_("unable to read index file"));
        }
  
 -      if ((check || apply) &&
 -          check_patch_list(list) < 0 &&
 -          !apply_with_reject)
 +      if ((state->check || state->apply) &&
 +          check_patch_list(state, list) < 0 &&
 +          !state->apply_with_reject)
                exit(1);
  
 -      if (apply && write_out_results(list)) {
 -              if (apply_with_reject)
 +      if (state->apply && write_out_results(state, list)) {
 +              if (state->apply_with_reject)
                        exit(1);
                /* with --3way, we still need to write the index out */
                return 1;
        }
  
 -      if (fake_ancestor)
 -              build_fake_ancestor(list, fake_ancestor);
 +      if (state->fake_ancestor)
 +              build_fake_ancestor(list, state->fake_ancestor);
  
 -      if (diffstat)
 -              stat_patch_list(list);
 +      if (state->diffstat)
 +              stat_patch_list(state, list);
  
 -      if (numstat)
 -              numstat_patch_list(list);
 +      if (state->numstat)
 +              numstat_patch_list(state, list);
  
 -      if (summary)
 +      if (state->summary)
                summary_patch_list(list);
  
        free_patch_list(list);
        strbuf_release(&buf);
 -      string_list_clear(&fn_table, 0);
 +      string_list_clear(&state->fn_table, 0);
        return 0;
  }
  
@@@ -4596,284 -4446,220 +4596,284 @@@ static void git_apply_config(void
  static int option_parse_exclude(const struct option *opt,
                                const char *arg, int unset)
  {
 -      add_name_limit(arg, 1);
 +      struct apply_state *state = opt->value;
 +      add_name_limit(state, arg, 1);
        return 0;
  }
  
  static int option_parse_include(const struct option *opt,
                                const char *arg, int unset)
  {
 -      add_name_limit(arg, 0);
 -      has_include = 1;
 +      struct apply_state *state = opt->value;
 +      add_name_limit(state, arg, 0);
 +      state->has_include = 1;
        return 0;
  }
  
  static int option_parse_p(const struct option *opt,
 -                        const char *arg, int unset)
 +                        const char *arg,
 +                        int unset)
  {
 -      p_value = atoi(arg);
 -      p_value_known = 1;
 +      struct apply_state *state = opt->value;
 +      state->p_value = atoi(arg);
 +      state->p_value_known = 1;
        return 0;
  }
  
  static int option_parse_space_change(const struct option *opt,
 -                        const char *arg, int unset)
 +                                   const char *arg, int unset)
  {
 +      struct apply_state *state = opt->value;
        if (unset)
 -              ws_ignore_action = ignore_ws_none;
 +              state->ws_ignore_action = ignore_ws_none;
        else
 -              ws_ignore_action = ignore_ws_change;
 +              state->ws_ignore_action = ignore_ws_change;
        return 0;
  }
  
  static int option_parse_whitespace(const struct option *opt,
                                   const char *arg, int unset)
  {
 -      const char **whitespace_option = opt->value;
 -
 -      *whitespace_option = arg;
 -      parse_whitespace_option(arg);
 +      struct apply_state *state = opt->value;
 +      state->whitespace_option = arg;
 +      parse_whitespace_option(state, arg);
        return 0;
  }
  
  static int option_parse_directory(const struct option *opt,
                                  const char *arg, int unset)
  {
 -      strbuf_reset(&root);
 -      strbuf_addstr(&root, arg);
 -      strbuf_complete(&root, '/');
 +      struct apply_state *state = opt->value;
 +      strbuf_reset(&state->root);
 +      strbuf_addstr(&state->root, arg);
 +      strbuf_complete(&state->root, '/');
        return 0;
  }
  
 -int cmd_apply(int argc, const char **argv, const char *prefix_)
 +static void init_apply_state(struct apply_state *state,
 +                           const char *prefix,
 +                           struct lock_file *lock_file)
 +{
 +      memset(state, 0, sizeof(*state));
 +      state->prefix = prefix;
 +      state->prefix_length = state->prefix ? strlen(state->prefix) : 0;
 +      state->lock_file = lock_file;
 +      state->newfd = -1;
 +      state->apply = 1;
 +      state->line_termination = '\n';
 +      state->p_value = 1;
 +      state->p_context = UINT_MAX;
 +      state->squelch_whitespace_errors = 5;
 +      state->ws_error_action = warn_on_ws_error;
 +      state->ws_ignore_action = ignore_ws_none;
 +      state->linenr = 1;
 +      string_list_init(&state->fn_table, 0);
 +      string_list_init(&state->limit_by_name, 0);
 +      string_list_init(&state->symlink_changes, 0);
 +      strbuf_init(&state->root, 0);
 +
 +      git_apply_config();
 +      if (apply_default_whitespace)
 +              parse_whitespace_option(state, apply_default_whitespace);
 +      if (apply_default_ignorewhitespace)
 +              parse_ignorewhitespace_option(state, apply_default_ignorewhitespace);
 +}
 +
 +static void clear_apply_state(struct apply_state *state)
 +{
 +      string_list_clear(&state->limit_by_name, 0);
 +      string_list_clear(&state->symlink_changes, 0);
 +      strbuf_release(&state->root);
 +
 +      /* &state->fn_table is cleared at the end of apply_patch() */
 +}
 +
 +static void check_apply_state(struct apply_state *state, int force_apply)
 +{
 +      int is_not_gitdir = !startup_info->have_repository;
 +
 +      if (state->apply_with_reject && state->threeway)
 +              die("--reject and --3way cannot be used together.");
 +      if (state->cached && state->threeway)
 +              die("--cached and --3way cannot be used together.");
 +      if (state->threeway) {
 +              if (is_not_gitdir)
 +                      die(_("--3way outside a repository"));
 +              state->check_index = 1;
 +      }
 +      if (state->apply_with_reject)
 +              state->apply = state->apply_verbosely = 1;
 +      if (!force_apply && (state->diffstat || state->numstat || state->summary || state->check || state->fake_ancestor))
 +              state->apply = 0;
 +      if (state->check_index && is_not_gitdir)
 +              die(_("--index outside a repository"));
 +      if (state->cached) {
 +              if (is_not_gitdir)
 +                      die(_("--cached outside a repository"));
 +              state->check_index = 1;
 +      }
 +      if (state->check_index)
 +              state->unsafe_paths = 0;
 +      if (!state->lock_file)
 +              die("BUG: state->lock_file should not be NULL");
 +}
 +
 +static int apply_all_patches(struct apply_state *state,
 +                           int argc,
 +                           const char **argv,
 +                           int options)
  {
        int i;
        int errs = 0;
 -      int is_not_gitdir = !startup_info->have_repository;
 -      int force_apply = 0;
 +      int read_stdin = 1;
 +
 +      for (i = 0; i < argc; i++) {
 +              const char *arg = argv[i];
 +              int fd;
 +
 +              if (!strcmp(arg, "-")) {
 +                      errs |= apply_patch(state, 0, "<stdin>", options);
 +                      read_stdin = 0;
 +                      continue;
 +              } else if (0 < state->prefix_length)
 +                      arg = prefix_filename(state->prefix,
 +                                            state->prefix_length,
 +                                            arg);
 +
 +              fd = open(arg, O_RDONLY);
 +              if (fd < 0)
 +                      die_errno(_("can't open patch '%s'"), arg);
 +              read_stdin = 0;
 +              set_default_whitespace_mode(state);
 +              errs |= apply_patch(state, fd, arg, options);
 +              close(fd);
 +      }
 +      set_default_whitespace_mode(state);
 +      if (read_stdin)
 +              errs |= apply_patch(state, 0, "<stdin>", options);
 +
 +      if (state->whitespace_error) {
 +              if (state->squelch_whitespace_errors &&
 +                  state->squelch_whitespace_errors < state->whitespace_error) {
 +                      int squelched =
 +                              state->whitespace_error - state->squelch_whitespace_errors;
 +                      warning(Q_("squelched %d whitespace error",
 +                                 "squelched %d whitespace errors",
 +                                 squelched),
 +                              squelched);
 +              }
 +              if (state->ws_error_action == die_on_ws_error)
 +                      die(Q_("%d line adds whitespace errors.",
 +                             "%d lines add whitespace errors.",
 +                             state->whitespace_error),
 +                          state->whitespace_error);
 +              if (state->applied_after_fixing_ws && state->apply)
 +                      warning("%d line%s applied after"
 +                              " fixing whitespace errors.",
 +                              state->applied_after_fixing_ws,
 +                              state->applied_after_fixing_ws == 1 ? "" : "s");
 +              else if (state->whitespace_error)
 +                      warning(Q_("%d line adds whitespace errors.",
 +                                 "%d lines add whitespace errors.",
 +                                 state->whitespace_error),
 +                              state->whitespace_error);
 +      }
 +
 +      if (state->update_index) {
 +              if (write_locked_index(&the_index, state->lock_file, COMMIT_LOCK))
 +                      die(_("Unable to write new index file"));
 +              state->newfd = -1;
 +      }
 +
 +      return !!errs;
 +}
  
 -      const char *whitespace_option = NULL;
 +int cmd_apply(int argc, const char **argv, const char *prefix)
 +{
 +      int force_apply = 0;
 +      int options = 0;
 +      int ret;
 +      struct apply_state state;
  
        struct option builtin_apply_options[] = {
 -              { OPTION_CALLBACK, 0, "exclude", NULL, N_("path"),
 +              { OPTION_CALLBACK, 0, "exclude", &state, N_("path"),
                        N_("don't apply changes matching the given path"),
                        0, option_parse_exclude },
 -              { OPTION_CALLBACK, 0, "include", NULL, N_("path"),
 +              { OPTION_CALLBACK, 0, "include", &state, N_("path"),
                        N_("apply changes matching the given path"),
                        0, option_parse_include },
 -              { OPTION_CALLBACK, 'p', NULL, NULL, N_("num"),
 +              { OPTION_CALLBACK, 'p', NULL, &state, N_("num"),
                        N_("remove <num> leading slashes from traditional diff paths"),
                        0, option_parse_p },
 -              OPT_BOOL(0, "no-add", &no_add,
 +              OPT_BOOL(0, "no-add", &state.no_add,
                        N_("ignore additions made by the patch")),
 -              OPT_BOOL(0, "stat", &diffstat,
 +              OPT_BOOL(0, "stat", &state.diffstat,
                        N_("instead of applying the patch, output diffstat for the input")),
                OPT_NOOP_NOARG(0, "allow-binary-replacement"),
                OPT_NOOP_NOARG(0, "binary"),
 -              OPT_BOOL(0, "numstat", &numstat,
 +              OPT_BOOL(0, "numstat", &state.numstat,
                        N_("show number of added and deleted lines in decimal notation")),
 -              OPT_BOOL(0, "summary", &summary,
 +              OPT_BOOL(0, "summary", &state.summary,
                        N_("instead of applying the patch, output a summary for the input")),
 -              OPT_BOOL(0, "check", &check,
 +              OPT_BOOL(0, "check", &state.check,
                        N_("instead of applying the patch, see if the patch is applicable")),
 -              OPT_BOOL(0, "index", &check_index,
 +              OPT_BOOL(0, "index", &state.check_index,
                        N_("make sure the patch is applicable to the current index")),
 -              OPT_BOOL(0, "cached", &cached,
 +              OPT_BOOL(0, "cached", &state.cached,
                        N_("apply a patch without touching the working tree")),
 -              OPT_BOOL(0, "unsafe-paths", &unsafe_paths,
 +              OPT_BOOL(0, "unsafe-paths", &state.unsafe_paths,
                        N_("accept a patch that touches outside the working area")),
                OPT_BOOL(0, "apply", &force_apply,
                        N_("also apply the patch (use with --stat/--summary/--check)")),
 -              OPT_BOOL('3', "3way", &threeway,
 +              OPT_BOOL('3', "3way", &state.threeway,
                         N_( "attempt three-way merge if a patch does not apply")),
 -              OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor,
 +              OPT_FILENAME(0, "build-fake-ancestor", &state.fake_ancestor,
                        N_("build a temporary index based on embedded index information")),
                /* Think twice before adding "--nul" synonym to this */
 -              OPT_SET_INT('z', NULL, &line_termination,
 +              OPT_SET_INT('z', NULL, &state.line_termination,
                        N_("paths are separated with NUL character"), '\0'),
 -              OPT_INTEGER('C', NULL, &p_context,
 +              OPT_INTEGER('C', NULL, &state.p_context,
                                N_("ensure at least <n> lines of context match")),
 -              { OPTION_CALLBACK, 0, "whitespace", &whitespace_option, N_("action"),
 +              { OPTION_CALLBACK, 0, "whitespace", &state, N_("action"),
                        N_("detect new or modified lines that have whitespace errors"),
                        0, option_parse_whitespace },
 -              { OPTION_CALLBACK, 0, "ignore-space-change", NULL, NULL,
 +              { OPTION_CALLBACK, 0, "ignore-space-change", &state, NULL,
                        N_("ignore changes in whitespace when finding context"),
                        PARSE_OPT_NOARG, option_parse_space_change },
 -              { OPTION_CALLBACK, 0, "ignore-whitespace", NULL, NULL,
 +              { OPTION_CALLBACK, 0, "ignore-whitespace", &state, NULL,
                        N_("ignore changes in whitespace when finding context"),
                        PARSE_OPT_NOARG, option_parse_space_change },
 -              OPT_BOOL('R', "reverse", &apply_in_reverse,
 +              OPT_BOOL('R', "reverse", &state.apply_in_reverse,
                        N_("apply the patch in reverse")),
 -              OPT_BOOL(0, "unidiff-zero", &unidiff_zero,
 +              OPT_BOOL(0, "unidiff-zero", &state.unidiff_zero,
                        N_("don't expect at least one line of context")),
 -              OPT_BOOL(0, "reject", &apply_with_reject,
 +              OPT_BOOL(0, "reject", &state.apply_with_reject,
                        N_("leave the rejected hunks in corresponding *.rej files")),
 -              OPT_BOOL(0, "allow-overlap", &allow_overlap,
 +              OPT_BOOL(0, "allow-overlap", &state.allow_overlap,
                        N_("allow overlapping hunks")),
 -              OPT__VERBOSE(&apply_verbosely, N_("be verbose")),
 +              OPT__VERBOSE(&state.apply_verbosely, N_("be verbose")),
                OPT_BIT(0, "inaccurate-eof", &options,
                        N_("tolerate incorrectly detected missing new-line at the end of file"),
                        INACCURATE_EOF),
                OPT_BIT(0, "recount", &options,
                        N_("do not trust the line counts in the hunk headers"),
                        RECOUNT),
 -              { OPTION_CALLBACK, 0, "directory", NULL, N_("root"),
 +              { OPTION_CALLBACK, 0, "directory", &state, N_("root"),
                        N_("prepend <root> to all filenames"),
                        0, option_parse_directory },
                OPT_END()
        };
  
 -      prefix = prefix_;
 -      prefix_length = prefix ? strlen(prefix) : 0;
 -      git_apply_config();
 -      if (apply_default_whitespace)
 -              parse_whitespace_option(apply_default_whitespace);
 -      if (apply_default_ignorewhitespace)
 -              parse_ignorewhitespace_option(apply_default_ignorewhitespace);
 +      init_apply_state(&state, prefix, &lock_file);
  
 -      argc = parse_options(argc, argv, prefix, builtin_apply_options,
 +      argc = parse_options(argc, argv, state.prefix, builtin_apply_options,
                        apply_usage, 0);
  
 -      if (apply_with_reject && threeway)
 -              die("--reject and --3way cannot be used together.");
 -      if (cached && threeway)
 -              die("--cached and --3way cannot be used together.");
 -      if (threeway) {
 -              if (is_not_gitdir)
 -                      die(_("--3way outside a repository"));
 -              check_index = 1;
 -      }
 -      if (apply_with_reject)
 -              apply = apply_verbosely = 1;
 -      if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))
 -              apply = 0;
 -      if (check_index && is_not_gitdir)
 -              die(_("--index outside a repository"));
 -      if (cached) {
 -              if (is_not_gitdir)
 -                      die(_("--cached outside a repository"));
 -              check_index = 1;
 -      }
 -      if (check_index)
 -              unsafe_paths = 0;
 +      check_apply_state(&state, force_apply);
  
 -      for (i = 0; i < argc; i++) {
 -              const char *arg = argv[i];
 -              int fd;
 +      ret = apply_all_patches(&state, argc, argv, options);
  
 -              if (!strcmp(arg, "-")) {
 -                      errs |= apply_patch(0, "<stdin>", options);
 -                      read_stdin = 0;
 -                      continue;
 -              } else if (0 < prefix_length)
 -                      arg = prefix_filename(prefix, prefix_length, arg);
 +      clear_apply_state(&state);
  
 -              fd = open(arg, O_RDONLY);
 -              if (fd < 0)
 -                      die_errno(_("can't open patch '%s'"), arg);
 -              read_stdin = 0;
 -              set_default_whitespace_mode(whitespace_option);
 -              errs |= apply_patch(fd, arg, options);
 -              close(fd);
 -      }
 -      set_default_whitespace_mode(whitespace_option);
 -      if (read_stdin)
 -              errs |= apply_patch(0, "<stdin>", options);
 -      if (whitespace_error) {
 -              if (squelch_whitespace_errors &&
 -                  squelch_whitespace_errors < whitespace_error) {
 -                      int squelched =
 -                              whitespace_error - squelch_whitespace_errors;
 -                      warning(Q_("squelched %d whitespace error",
 -                                 "squelched %d whitespace errors",
 -                                 squelched),
 -                              squelched);
 -              }
 -              if (ws_error_action == die_on_ws_error)
 -                      die(Q_("%d line adds whitespace errors.",
 -                             "%d lines add whitespace errors.",
 -                             whitespace_error),
 -                          whitespace_error);
 -              if (applied_after_fixing_ws && apply)
 -                      warning("%d line%s applied after"
 -                              " fixing whitespace errors.",
 -                              applied_after_fixing_ws,
 -                              applied_after_fixing_ws == 1 ? "" : "s");
 -              else if (whitespace_error)
 -                      warning(Q_("%d line adds whitespace errors.",
 -                                 "%d lines add whitespace errors.",
 -                                 whitespace_error),
 -                              whitespace_error);
 -      }
 -
 -      if (update_index) {
 -              if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
 -                      die(_("Unable to write new index file"));
 -      }
 -
 -      return !!errs;
 +      return ret;
  }
diff --combined builtin/checkout.c
index c3486bdec364fde395cf3523b778ec4dc9c3223a,05c7b71ca806aef86b8286e59db13edf38547a0c..27c1a05246c21278a730698bd7de85eccc96d721
@@@ -276,7 -276,7 +276,7 @@@ static int checkout_paths(const struct 
  
        hold_locked_index(lock_file, 1);
        if (read_cache_preload(&opts->pathspec) < 0)
-               return error(_("corrupt index file"));
+               return error(_("index file corrupt"));
  
        if (opts->source_tree)
                read_tree_some(opts->source_tree, &opts->pathspec);
@@@ -470,7 -470,7 +470,7 @@@ static int merge_working_tree(const str
  
        hold_locked_index(lock_file, 1);
        if (read_cache_preload(NULL) < 0)
-               return error(_("corrupt index file"));
+               return error(_("index file corrupt"));
  
        resolve_undo_clear();
        if (opts->force) {
                         * entries in the index.
                         */
  
 -                      add_files_to_cache(NULL, NULL, 0);
 +                      add_files_to_cache(NULL, NULL, 0, 0);
                        /*
                         * NEEDSWORK: carrying over local changes
                         * when branches have different end-of-line
@@@ -1138,7 -1138,7 +1138,7 @@@ int cmd_checkout(int argc, const char *
                OPT_STRING('B', NULL, &opts.new_branch_force, N_("branch"),
                           N_("create/reset and checkout a branch")),
                OPT_BOOL('l', NULL, &opts.new_branch_log, N_("create reflog for new branch")),
-               OPT_BOOL(0, "detach", &opts.force_detach, N_("detach the HEAD at named commit")),
+               OPT_BOOL(0, "detach", &opts.force_detach, N_("detach HEAD at named commit")),
                OPT_SET_INT('t', "track",  &opts.track, N_("set upstream info for new branch"),
                        BRANCH_TRACK_EXPLICIT),
                OPT_STRING(0, "orphan", &opts.new_orphan_branch, N_("new-branch"), N_("new unparented branch")),
diff --combined builtin/pull.c
index 897a7f4e4e040089b4021a9a0e217fbb63e7c6ec,a980dcfe9b28e40402be6227e6fb5531f77e6a77..398aae16c006f5386ba6d65e3ef266b4ddfe1e74
@@@ -815,9 -815,6 +815,9 @@@ static int run_rebase(const unsigned ch
                argv_array_push(&args, "--no-autostash");
        else if (opt_autostash == 1)
                argv_array_push(&args, "--autostash");
 +      if (opt_verify_signatures &&
 +          !strcmp(opt_verify_signatures, "--verify-signatures"))
 +              warning(_("ignoring --verify-signatures for rebase"));
  
        argv_array_push(&args, "--onto");
        argv_array_push(&args, sha1_to_hex(merge_head));
@@@ -855,7 -852,7 +855,7 @@@ int cmd_pull(int argc, const char **arg
        git_config(git_pull_config, NULL);
  
        if (read_cache_unmerged())
-               die_resolve_conflict("Pull");
+               die_resolve_conflict("pull");
  
        if (file_exists(git_path("MERGE_HEAD")))
                die_conclude_merge();
diff --combined builtin/remote.c
index 5ded3018afcf8c44fccac5062aa34df9ba013169,7f0f78b8fc22d3b74d242f179eeaba0d11f8f4ca..a4d9c1a8e9c7f0cd36136e26581ba4a3ee828fe8
@@@ -247,7 -247,7 +247,7 @@@ struct branch_info 
        enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
  };
  
 -static struct string_list branch_list;
 +static struct string_list branch_list = STRING_LIST_INIT_NODUP;
  
  static const char *abbrev_ref(const char *name, const char *prefix)
  {
@@@ -952,7 -952,7 +952,7 @@@ static int show_local_info_item(struct 
        struct show_info *show_info = cb_data;
        struct branch_info *branch_info = item->util;
        struct string_list *merge = &branch_info->merge;
-       const char *also;
+       int width = show_info->width + 4;
        int i;
  
        if (branch_info->rebase && branch_info->merge.nr > 1) {
  
        printf("    %-*s ", show_info->width, item->string);
        if (branch_info->rebase) {
-               printf_ln(_(branch_info->rebase == INTERACTIVE_REBASE ?
-                       "rebases interactively onto remote %s" :
-                       "rebases onto remote %s"), merge->items[0].string);
+               printf_ln(branch_info->rebase == INTERACTIVE_REBASE
+                         ? _("rebases interactively onto remote %s")
+                         : _("rebases onto remote %s"), merge->items[0].string);
                return 0;
        } else if (show_info->any_rebase) {
                printf_ln(_(" merges with remote %s"), merge->items[0].string);
-               also = _("    and with remote");
+               width++;
        } else {
                printf_ln(_("merges with remote %s"), merge->items[0].string);
-               also = _("   and with remote");
        }
        for (i = 1; i < merge->nr; i++)
-               printf("    %-*s %s %s\n", show_info->width, "", also,
+               printf(_("%-*s    and with remote %s\n"), width, "",
                       merge->items[i].string);
  
        return 0;
@@@ -1158,11 -1157,11 +1157,11 @@@ static int show(int argc, const char **
                           the one in "  Fetch URL: %s" translation */
                        printf_ln(_("  Push  URL: %s"), url[i]);
                if (!i)
-                       printf_ln(_("  Push  URL: %s"), "(no URL)");
+                       printf_ln(_("  Push  URL: %s"), _("(no URL)"));
                if (no_query)
-                       printf_ln(_("  HEAD branch: %s"), "(not queried)");
+                       printf_ln(_("  HEAD branch: %s"), _("(not queried)"));
                else if (!states.heads.nr)
-                       printf_ln(_("  HEAD branch: %s"), "(unknown)");
+                       printf_ln(_("  HEAD branch: %s"), _("(unknown)"));
                else if (states.heads.nr == 1)
                        printf_ln(_("  HEAD branch: %s"), states.heads.items[0].string);
                else {
diff --combined builtin/repack.c
index f7b7409cb7f8e2d35b4428c82d87d7067020a398,01088196fb6005e3b135ced29850e7da82a95ed8..80dd06b4a2a8b784ab96899cb150b13006d7e402
@@@ -146,7 -146,6 +146,7 @@@ int cmd_repack(int argc, const char **a
        int pack_everything = 0;
        int delete_redundant = 0;
        const char *unpack_unreachable = NULL;
 +      int keep_unreachable = 0;
        const char *window = NULL, *window_memory = NULL;
        const char *depth = NULL;
        const char *max_pack_size = NULL;
                                N_("write bitmap index")),
                OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"),
                                N_("with -A, do not loosen objects older than this")),
 +              OPT_BOOL('k', "keep-unreachable", &keep_unreachable,
 +                              N_("with -a, repack unreachable objects")),
                OPT_STRING(0, "window", &window, N_("n"),
                                N_("size of the window used for delta compression")),
                OPT_STRING(0, "window-memory", &window_memory, N_("bytes"),
        if (delete_redundant && repository_format_precious_objects)
                die(_("cannot delete packs in a precious-objects repo"));
  
 +      if (keep_unreachable &&
 +          (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE)))
 +              die(_("--keep-unreachable and -A are incompatible"));
 +
        if (pack_kept_objects < 0)
                pack_kept_objects = write_bitmaps;
  
                        } else if (pack_everything & LOOSEN_UNREACHABLE) {
                                argv_array_push(&cmd.args,
                                                "--unpack-unreachable");
 +                      } else if (keep_unreachable) {
 +                              argv_array_push(&cmd.args, "--keep-unreachable");
 +                              argv_array_push(&cmd.args, "--pack-loose-unreachable");
                        } else {
                                argv_array_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
                        }
                                          item->string,
                                          exts[ext].name);
                        if (remove_path(fname))
-                               warning(_("removing '%s' failed"), fname);
+                               warning(_("failed to remove '%s'"), fname);
                        free(fname);
                }
        }
index 05f22e43ccfe485b2a676f96ddec1a99f7a84612,a545d92c269618f50c0d4989b3ae940c728b64a4..068b16722af16fd09d63dedd5ce30c3204080d4f
@@@ -128,7 -128,7 +128,7 @@@ mark_action_done () 
        if test "$last_count" != "$new_count"
        then
                last_count=$new_count
-               printf "Rebasing (%d/%d)\r" $new_count $total
+               eval_gettext "Rebasing (\$new_count/\$total)"; printf "\r"
                test -z "$verbose" || echo
        fi
  }
@@@ -144,29 -144,28 +144,28 @@@ reschedule_last_action () 
  }
  
  append_todo_help () {
-       git stripspace --comment-lines >>"$todo" <<\EOF
+       gettext "
  Commands:
   p, pick = use commit
   r, reword = use commit, but edit the commit message
   e, edit = use commit, but stop for amending
   s, squash = use commit, but meld into previous commit
-  f, fixup = like "squash", but discard this commit's log message
+  f, fixup = like \"squash\", but discard this commit's log message
   x, exec = run command (the rest of the line) using shell
   d, drop = remove commit
  
  These lines can be re-ordered; they are executed from top to bottom.
+ " | git stripspace --comment-lines >>"$todo"
  
- EOF
        if test $(get_missing_commit_check_level) = error
        then
-               git stripspace --comment-lines >>"$todo" <<\EOF
+               gettext "
  Do not remove any line. Use 'drop' explicitly to remove a commit.
- EOF
+ " | git stripspace --comment-lines >>"$todo"
        else
-               git stripspace --comment-lines >>"$todo" <<\EOF
+               gettext "
  If you remove a line here THAT COMMIT WILL BE LOST.
- EOF
+ " | git stripspace --comment-lines >>"$todo"
        fi
  }
  
@@@ -192,6 -191,7 +191,6 @@@ make_patch () 
  die_with_patch () {
        echo "$1" > "$state_dir"/stopped-sha
        make_patch "$1"
 -      git rerere
        die "$2"
  }
  
@@@ -200,13 -200,14 +199,14 @@@ exit_with_patch () 
        make_patch $1
        git rev-parse --verify HEAD > "$amend"
        gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}
-       warn "You can amend the commit now, with"
-       warn
-       warn "  git commit --amend $gpg_sign_opt_quoted"
-       warn
-       warn "Once you are satisfied with your changes, run"
-       warn
-       warn "  git rebase --continue"
+       warn "$(eval_gettext "\
+ You can amend the commit now, with
+       git commit --amend \$gpg_sign_opt_quoted
+ Once you are satisfied with your changes, run
+       git rebase --continue")"
        warn
        exit $2
  }
@@@ -221,10 -222,12 +221,12 @@@ has_action () 
  }
  
  is_empty_commit() {
-       tree=$(git rev-parse -q --verify "$1"^{tree} 2>/dev/null ||
-               die "$1: not a commit that can be picked")
-       ptree=$(git rev-parse -q --verify "$1"^^{tree} 2>/dev/null ||
-               ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904)
+       tree=$(git rev-parse -q --verify "$1"^{tree} 2>/dev/null) || {
+               sha1=$1
+               die "$(eval_gettext "\$sha1: not a commit that can be picked")"
+       }
+       ptree=$(git rev-parse -q --verify "$1"^^{tree} 2>/dev/null) ||
+               ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904
        test "$tree" = "$ptree"
  }
  
@@@ -260,7 -263,7 +262,7 @@@ pick_one () 
  
        case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
        case "$force_rebase" in '') ;; ?*) ff= ;; esac
-       output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
+       output git rev-parse --verify $sha1 || die "$(eval_gettext "Invalid commit name: \$sha1")"
  
        if is_empty_commit "$sha1"
        then
@@@ -302,7 -305,7 +304,7 @@@ pick_one_preserving_merges () 
                                git rev-parse HEAD > "$rewritten"/$current_commit
                        done <"$state_dir"/current-commit
                        rm "$state_dir"/current-commit ||
-                       die "Cannot write current commit's replacement sha1"
+                               die "$(gettext "Cannot write current commit's replacement sha1")"
                fi
        fi
  
        done
        case $fast_forward in
        t)
-               output warn "Fast-forward to $sha1"
+               output warn "$(eval_gettext "Fast-forward to \$sha1")"
                output git reset --hard $sha1 ||
-                       die "Cannot fast-forward to $sha1"
+                       die "$(eval_gettext "Cannot fast-forward to \$sha1")"
                ;;
        f)
                first_parent=$(expr "$new_parents" : ' \([^ ]*\)')
                then
                        # detach HEAD to current parent
                        output git checkout $first_parent 2> /dev/null ||
-                               die "Cannot move HEAD to $first_parent"
+                               die "$(eval_gettext "Cannot move HEAD to \$first_parent")"
                fi
  
                case "$new_parents" in
                ' '*' '*)
-                       test "a$1" = a-n && die "Refusing to squash a merge: $sha1"
+                       test "a$1" = a-n && die "$(eval_gettext "Refusing to squash a merge: \$sha1")"
  
                        # redo merge
                        author_script_content=$(get_author_ident_from_commit $sha1)
                                $merge_args $strategy_args -m "$msg_content" $new_parents'
                        then
                                printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
-                               die_with_patch $sha1 "Error redoing merge $sha1"
+                               die_with_patch $sha1 "$(eval_gettext "Error redoing merge \$sha1")"
                        fi
                        echo "$sha1 $(git rev-parse HEAD^0)" >> "$rewritten_list"
                        ;;
                        output eval git cherry-pick \
                                ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                                "$strategy_args" "$@" ||
-                               die_with_patch $sha1 "Could not pick $sha1"
+                               die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")"
                        ;;
                esac
                ;;
        esac
  }
  
- nth_string () {
-       case "$1" in
-       *1[0-9]|*[04-9]) echo "$1"th;;
-       *1) echo "$1"st;;
-       *2) echo "$1"nd;;
-       *3) echo "$1"rd;;
+ this_nth_commit_message () {
+       n=$1
+       case "$n" in
+       1) gettext "This is the 1st commit message:";;
+       2) gettext "This is the 2nd commit message:";;
+       3) gettext "This is the 3rd commit message:";;
+       4) gettext "This is the 4th commit message:";;
+       5) gettext "This is the 5th commit message:";;
+       6) gettext "This is the 6th commit message:";;
+       7) gettext "This is the 7th commit message:";;
+       8) gettext "This is the 8th commit message:";;
+       9) gettext "This is the 9th commit message:";;
+       10) gettext "This is the 10th commit message:";;
+       # TRANSLATORS: if the language you are translating into
+       # doesn't allow you to compose a sentence in this fashion,
+       # consider translating as if this and the following few strings
+       # were "This is the commit message ${n}:"
+       *1[0-9]|*[04-9]) eval_gettext "This is the \${n}th commit message:";;
+       *1) eval_gettext "This is the \${n}st commit message:";;
+       *2) eval_gettext "This is the \${n}nd commit message:";;
+       *3) eval_gettext "This is the \${n}rd commit message:";;
+       *) eval_gettext "This is the commit message \${n}:";;
+       esac
+ }
+ skip_nth_commit_message () {
+       n=$1
+       case "$n" in
+       1) gettext "The 1st commit message will be skipped:";;
+       2) gettext "The 2nd commit message will be skipped:";;
+       3) gettext "The 3rd commit message will be skipped:";;
+       4) gettext "The 4th commit message will be skipped:";;
+       5) gettext "The 5th commit message will be skipped:";;
+       6) gettext "The 6th commit message will be skipped:";;
+       7) gettext "The 7th commit message will be skipped:";;
+       8) gettext "The 8th commit message will be skipped:";;
+       9) gettext "The 9th commit message will be skipped:";;
+       10) gettext "The 10th commit message will be skipped:";;
+       # TRANSLATORS: if the language you are translating into
+       # doesn't allow you to compose a sentence in this fashion,
+       # consider translating as if this and the following few strings
+       # were "The commit message ${n} will be skipped:"
+       *1[0-9]|*[04-9]) eval_gettext "The \${n}th commit message will be skipped:";;
+       *1) eval_gettext "The \${n}st commit message will be skipped:";;
+       *2) eval_gettext "The \${n}nd commit message will be skipped:";;
+       *3) eval_gettext "The \${n}rd commit message will be skipped:";;
+       *) eval_gettext "The commit message \${n} will be skipped:";;
        esac
  }
  
@@@ -412,20 -455,23 +454,23 @@@ update_squash_messages () 
        if test -f "$squash_msg"; then
                mv "$squash_msg" "$squash_msg".bak || exit
                count=$(($(sed -n \
-                       -e "1s/^. This is a combination of \(.*\) commits\./\1/p" \
+                       -e "1s/^$comment_char.*\([0-9][0-9]*\).*/\1/p" \
                        -e "q" < "$squash_msg".bak)+1))
                {
-                       printf '%s\n' "$comment_char This is a combination of $count commits."
+                       printf '%s\n' "$comment_char $(eval_ngettext \
+                               "This is a combination of \$count commit." \
+                               "This is a combination of \$count commits." \
+                               $count)"
                        sed -e 1d -e '2,/^./{
                                /^$/d
                        }' <"$squash_msg".bak
                } >"$squash_msg"
        else
-               commit_message HEAD > "$fixup_msg" || die "Cannot write $fixup_msg"
+               commit_message HEAD > "$fixup_msg" || die "$(gettext "Cannot write \$fixup_msg")"
                count=2
                {
-                       printf '%s\n' "$comment_char This is a combination of 2 commits."
-                       printf '%s\n' "$comment_char The first commit's message is:"
+                       printf '%s\n' "$comment_char $(gettext "This is a combination of 2 commits.")"
+                       printf '%s\n' "$comment_char $(gettext "This is the 1st commit message:")"
                        echo
                        cat "$fixup_msg"
                } >"$squash_msg"
        squash)
                rm -f "$fixup_msg"
                echo
-               printf '%s\n' "$comment_char This is the $(nth_string $count) commit message:"
+               printf '%s\n' "$comment_char $(this_nth_commit_message $count)"
                echo
                commit_message $2
                ;;
        fixup)
                echo
-               printf '%s\n' "$comment_char The $(nth_string $count) commit message will be skipped:"
+               printf '%s\n' "$comment_char $(skip_nth_commit_message $count)"
                echo
                # Change the space after the comment character to TAB:
                commit_message $2 | git stripspace --comment-lines | sed -e 's/ /       /'
@@@ -459,12 -505,14 +504,14 @@@ peek_next_command () 
  # messages, effectively causing the combined commit to be used as the
  # new basis for any further squash/fixups.  Args: sha1 rest
  die_failed_squash() {
+       sha1=$1
+       rest=$2
        mv "$squash_msg" "$msg" || exit
        rm -f "$fixup_msg"
        cp "$msg" "$GIT_DIR"/MERGE_MSG || exit
        warn
-       warn "Could not apply $1... $2"
-       die_with_patch $1 ""
+       warn "$(eval_gettext "Could not apply \$sha1... \$rest")"
+       die_with_patch $sha1 ""
  }
  
  flush_rewritten_pending() {
@@@ -488,6 -536,8 +535,8 @@@ record_in_rewritten() 
  }
  
  do_pick () {
+       sha1=$1
+       rest=$2
        if test "$(git rev-parse HEAD)" = "$squash_onto"
        then
                # Set the correct commit message and author info on the
                # resolve before manually running git commit --amend then git
                # rebase --continue.
                git commit --allow-empty --allow-empty-message --amend \
-                          --no-post-rewrite -n -q -C $1 &&
-                       pick_one -n $1 &&
+                          --no-post-rewrite -n -q -C $sha1 &&
+                       pick_one -n $sha1 &&
                        git commit --allow-empty --allow-empty-message \
-                                  --amend --no-post-rewrite -n -q -C $1 \
+                                  --amend --no-post-rewrite -n -q -C $sha1 \
                                   ${gpg_sign_opt:+"$gpg_sign_opt"} ||
-                       die_with_patch $1 "Could not apply $1... $2"
+                                  die_with_patch $sha1 "$(eval_gettext "Could not apply \$sha1... \$rest")"
        else
-               pick_one $1 ||
-                       die_with_patch $1 "Could not apply $1... $2"
+               pick_one $sha1 ||
+                       die_with_patch $sha1 "$(eval_gettext "Could not apply \$sha1... \$rest")"
        fi
  }
  
@@@ -535,10 -585,11 +584,11 @@@ do_next () 
                mark_action_done
                do_pick $sha1 "$rest"
                git commit --amend --no-post-rewrite ${gpg_sign_opt:+"$gpg_sign_opt"} || {
-                       warn "Could not amend commit after successfully picking $sha1... $rest"
-                       warn "This is most likely due to an empty commit message, or the pre-commit hook"
-                       warn "failed. If the pre-commit hook failed, you may need to resolve the issue before"
-                       warn "you are able to reword the commit."
+                       warn "$(eval_gettext "\
+ Could not amend commit after successfully picking \$sha1... \$rest
+ This is most likely due to an empty commit message, or the pre-commit hook
+ failed. If the pre-commit hook failed, you may need to resolve the issue before
+ you are able to reword the commit.")"
                        exit_with_patch $sha1 1
                }
                record_in_rewritten $sha1
                mark_action_done
                do_pick $sha1 "$rest"
                sha1_abbrev=$(git rev-parse --short $sha1)
-               warn "Stopped at $sha1_abbrev... $rest"
+               warn "$(eval_gettext "Stopped at \$sha1_abbrev... \$rest")"
                exit_with_patch $sha1 0
                ;;
        squash|s|fixup|f)
                comment_for_reflog $squash_style
  
                test -f "$done" && has_action "$done" ||
-                       die "Cannot '$squash_style' without a previous commit"
+                       die "$(eval_gettext "Cannot '\$squash_style' without a previous commit")"
  
                mark_action_done
                update_squash_messages $squash_style $sha1
        x|"exec")
                read -r command rest < "$todo"
                mark_action_done
-               printf 'Executing: %s\n' "$rest"
+               eval_gettextln "Executing: \$rest"
                "${SHELL:-@SHELL_PATH@}" -c "$rest" # Actual execution
                status=$?
                # Run in subshell because require_clean_work_tree can die.
                (require_clean_work_tree "rebase" 2>/dev/null) || dirty=t
                if test "$status" -ne 0
                then
-                       warn "Execution failed: $rest"
+                       warn "$(eval_gettext "Execution failed: \$rest")"
                        test "$dirty" = f ||
-                       warn "and made changes to the index and/or the working tree"
+                               warn "$(gettext "and made changes to the index and/or the working tree")"
  
-                       warn "You can fix the problem, and then run"
-                       warn
-                       warn "  git rebase --continue"
+                       warn "$(gettext "\
+ You can fix the problem, and then run
+       git rebase --continue")"
                        warn
                        if test $status -eq 127         # command not found
                        then
                        exit "$status"
                elif test "$dirty" = t
                then
-                       warn "Execution succeeded: $rest"
-                       warn "but left changes to the index and/or the working tree"
-                       warn "Commit or stash your changes, and then run"
-                       warn
-                       warn "  git rebase --continue"
+                       # TRANSLATORS: after these lines is a command to be issued by the user
+                       warn "$(eval_gettext "\
+ Execution succeeded: \$rest
+ but left changes to the index and/or the working tree
+ Commit or stash your changes, and then run
+       git rebase --continue")"
                        warn
                        exit 1
                fi
                ;;
        *)
-               warn "Unknown command: $command $sha1 $rest"
-               fixtodo="Please fix this using 'git rebase --edit-todo'."
+               warn "$(eval_gettext "Unknown command: \$command \$sha1 \$rest")"
+               fixtodo="$(gettext "Please fix this using 'git rebase --edit-todo'.")"
                if git rev-parse --verify -q "$sha1" >/dev/null
                then
                        die_with_patch $sha1 "$fixtodo"
                "$hook" rebase < "$rewritten_list"
                true # we don't care if this hook failed
        fi &&
-       warn "Successfully rebased and updated $head_name."
+               warn "$(eval_gettext "Successfully rebased and updated \$head_name.")"
  
        return 1 # not failure; just to break the do_rest loop
  }
@@@ -722,7 -776,7 +775,7 @@@ skip_unnecessary_picks () 
                record_in_rewritten "$onto"
                ;;
        esac ||
-       die "Could not skip unnecessary pick commands"
+               die "$(gettext "Could not skip unnecessary pick commands")"
  }
  
  transform_todo_ids () {
@@@ -880,9 -934,9 +933,9 @@@ check_commit_sha () 
        if test $badsha -ne 0
        then
                line="$(sed -n -e "${2}p" "$3")"
-               warn "Warning: the SHA-1 is missing or isn't" \
-                       "a commit in the following line:"
-               warn " - $line"
+               warn "$(eval_gettext "\
+ Warning: the SHA-1 is missing or isn't a commit in the following line:
+  - \$line")"
                warn
        fi
  
@@@ -913,9 -967,9 +966,9 @@@ check_bad_cmd_and_sha () 
                        ;;
                *)
                        line="$(sed -n -e "${lineno}p" "$1")"
-                       warn "Warning: the command isn't recognized" \
-                               "in the following line:"
-                       warn " - $line"
+                       warn "$(eval_gettext "\
+ Warning: the command isn't recognized in the following line:
+  - \$line")"
                        warn
                        retval=1
                        ;;
@@@ -952,7 -1006,7 +1005,7 @@@ warn_lines () 
  # Switch to the branch in $into and notify it in the reflog
  checkout_onto () {
        GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
-       output git checkout $onto || die_abort "could not detach HEAD"
+       output git checkout $onto || die_abort "$(gettext "could not detach HEAD")"
        git update-ref ORIG_HEAD $orig_head
  }
  
@@@ -990,28 -1044,26 +1043,26 @@@ check_todo_list () 
                then
                        test "$check_level" = error && raise_error=t
  
-                       warn "Warning: some commits may have been dropped" \
-                               "accidentally."
                      warn "Dropped commits (newer to older):"
+                       warn "$(gettext "\
+ Warning: some commits may have been dropped accidentally.
Dropped commits (newer to older):")"
  
                        # Make the list user-friendly and display
                        opt="--no-walk=sorted --format=oneline --abbrev-commit --stdin"
                        git rev-list $opt <"$todo".miss | warn_lines
  
-                       warn "To avoid this message, use \"drop\" to" \
-                               "explicitly remove a commit."
-                       warn
-                       warn "Use 'git config rebase.missingCommitsCheck' to change" \
-                               "the level of warnings."
-                       warn "The possible behaviours are: ignore, warn, error."
+                       warn "$(gettext "\
+ To avoid this message, use \"drop\" to explicitly remove a commit.
+ Use 'git config rebase.missingCommitsCheck' to change the level of warnings.
+ The possible behaviours are: ignore, warn, error.")"
                        warn
                fi
                ;;
        ignore)
                ;;
        *)
-               warn "Unrecognized setting $check_level for option" \
-                       "rebase.missingCommitsCheck. Ignoring."
+               warn "$(eval_gettext "Unrecognized setting \$check_level for option rebase.missingCommitsCheck. Ignoring.")"
                ;;
        esac
  
                # placed before the commit of the next action
                checkout_onto
  
-               warn "You can fix this with 'git rebase --edit-todo'."
-               die "Or you can abort the rebase with 'git rebase --abort'."
+               warn "$(gettext "You can fix this with 'git rebase --edit-todo'.")"
+               die "$(gettext "Or you can abort the rebase with 'git rebase --abort'.")"
        fi
  }
  
  # below were not inside any function, and expected to return
  # to the function that dot-sourced us.
  #
 -# However, FreeBSD /bin/sh misbehaves on such a construct and
 -# continues to run the statements that follow such a "return".
 +# However, older (9.x) versions of FreeBSD /bin/sh misbehave on such a
 +# construct and continue to run the statements that follow such a "return".
  # As a work-around, we introduce an extra layer of a function
  # here, and immediately call it after defining it.
  git_rebase__interactive () {
@@@ -1053,41 -1105,43 +1104,43 @@@ continue
  
                test ! -f "$GIT_DIR"/CHERRY_PICK_HEAD ||
                rm "$GIT_DIR"/CHERRY_PICK_HEAD ||
-               die "Could not remove CHERRY_PICK_HEAD"
+               die "$(gettext "Could not remove CHERRY_PICK_HEAD")"
        else
                if ! test -f "$author_script"
                then
                        gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}
-                       die "You have staged changes in your working tree. If these changes are meant to be
+                       die "$(eval_gettext "\
+ You have staged changes in your working tree.
+ If these changes are meant to be
  squashed into the previous commit, run:
  
-   git commit --amend $gpg_sign_opt_quoted
+   git commit --amend \$gpg_sign_opt_quoted
  
  If they are meant to go into a new commit, run:
  
-   git commit $gpg_sign_opt_quoted
+   git commit \$gpg_sign_opt_quoted
  
  In both case, once you're done, continue with:
  
    git rebase --continue
- "
+ ")"
                fi
                . "$author_script" ||
-                       die "Error trying to find the author identity to amend commit"
+                       die "$(gettext "Error trying to find the author identity to amend commit")"
                if test -f "$amend"
                then
                        current_head=$(git rev-parse --verify HEAD)
                        test "$current_head" = $(cat "$amend") ||
-                       die "\
- You have uncommitted changes in your working tree. Please, commit them
- first and then run 'git rebase --continue' again."
+                       die "$(gettext "\
+ You have uncommitted changes in your working tree. Please commit them
+ first and then run 'git rebase --continue' again.")"
                        do_with_author git commit --amend --no-verify -F "$msg" -e \
                                ${gpg_sign_opt:+"$gpg_sign_opt"} ||
-                               die "Could not commit staged changes."
+                               die "$(gettext "Could not commit staged changes.")"
                else
                        do_with_author git commit --no-verify -F "$msg" -e \
                                ${gpg_sign_opt:+"$gpg_sign_opt"} ||
-                               die "Could not commit staged changes."
+                               die "$(gettext "Could not commit staged changes.")"
                fi
        fi
  
@@@ -1111,16 -1165,15 +1164,15 @@@ edit-todo
        mv -f "$todo".new "$todo"
        collapse_todo_ids
        append_todo_help
-       git stripspace --comment-lines >>"$todo" <<\EOF
+       gettext "
  You are editing the todo file of an ongoing interactive rebase.
  To continue rebase after editing, run:
      git rebase --continue
  
- EOF
+ " | git stripspace --comment-lines >>"$todo"
  
        git_sequence_editor "$todo" ||
-               die "Could not execute editor"
+               die "$(gettext "Could not execute editor")"
        expand_todo_ids
  
        exit
  esac
  
  git var GIT_COMMITTER_IDENT >/dev/null ||
-       die "You need to set your committer info first"
+       die "$(gettext "You need to set your committer info first")"
  
  comment_for_reflog start
  
@@@ -1136,15 -1189,15 +1188,15 @@@ if test ! -z "$switch_to
  then
        GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to"
        output git checkout "$switch_to" -- ||
-       die "Could not checkout $switch_to"
+               die "$(eval_gettext "Could not checkout \$switch_to")"
  
        comment_for_reflog start
  fi
  
- orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?"
- mkdir -p "$state_dir" || die "Could not create temporary $state_dir"
+ orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
+ mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")"
  
- : > "$state_dir"/interactive || die "Could not mark as interactive"
+ : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
  write_basic_state
  if test t = "$preserve_merges"
  then
                for c in $(git merge-base --all $orig_head $upstream)
                do
                        echo $onto > "$rewritten"/$c ||
-                               die "Could not init rewritten commits"
+                               die "$(gettext "Could not init rewritten commits")"
                done
        else
                mkdir "$rewritten" &&
                echo $onto > "$rewritten"/root ||
-                       die "Could not init rewritten commits"
+                       die "$(gettext "Could not init rewritten commits")"
        fi
        # No cherry-pick because our first pass is to determine
        # parents to rewrite and skipping dropped commits would
@@@ -1258,18 -1311,20 +1310,20 @@@ todocount=${todocount##* 
  
  cat >>"$todo" <<EOF
  
- $comment_char Rebase $shortrevisions onto $shortonto ($todocount command(s))
+ $comment_char $(eval_ngettext \
+       "Rebase \$shortrevisions onto \$shortonto (\$todocount command)" \
+       "Rebase \$shortrevisions onto \$shortonto (\$todocount commands)" \
+       "$todocount")
  EOF
  append_todo_help
- git stripspace --comment-lines >>"$todo" <<\EOF
+ gettext "
  However, if you remove everything, the rebase will be aborted.
  
- EOF
+ " | git stripspace --comment-lines >>"$todo"
  
  if test -z "$keep_empty"
  then
-       printf '%s\n' "$comment_char Note that empty commits are commented out" >>"$todo"
+       printf '%s\n' "$comment_char $(gettext "Note that empty commits are commented out")" >>"$todo"
  fi
  
  
@@@ -1279,7 -1334,7 +1333,7 @@@ has_action "$todo" |
  cp "$todo" "$todo".backup
  collapse_todo_ids
  git_sequence_editor "$todo" ||
-       die_abort "Could not execute editor"
+       die_abort "$(gettext "Could not execute editor")"
  
  has_action "$todo" ||
        return 2
diff --combined git-sh-setup.sh
index 85db5f1c63c3c6fa0fff95a747538e47f02ec46d,2eda134800b08e3dfcdc2084b221280b8d95e178..0c34aa62f6b1b33be67f4221290c9c5ce55beabe
@@@ -2,6 -2,9 +2,9 @@@
  # to set up some variables pointing at the normal git directories and
  # a few helper shell functions.
  
+ # Source git-sh-i18n for gettext support.
+ . git-sh-i18n
  # Having this variable in your environment would break scripts because
  # you would cause "cd" to be taken to unexpected places.  If you
  # like CDPATH, define it for your interactive shell sessions without
@@@ -83,16 -86,16 +86,16 @@@ if test -n "$OPTIONS_SPEC"; the
  else
        dashless=$(basename -- "$0" | sed -e 's/-/ /')
        usage() {
-               die "usage: $dashless $USAGE"
+               die "$(eval_gettext "usage: \$dashless \$USAGE")"
        }
  
        if [ -z "$LONG_USAGE" ]
        then
-               LONG_USAGE="usage: $dashless $USAGE"
+               LONG_USAGE="$(eval_gettext "usage: \$dashless \$USAGE")"
        else
-               LONG_USAGE="usage: $dashless $USAGE
+               LONG_USAGE="$(eval_gettext "usage: \$dashless \$USAGE
  
- $LONG_USAGE"
+ $LONG_USAGE")"
        fi
  
        case "$1" in
@@@ -160,8 -163,8 +163,8 @@@ git_pager() 
        else
                GIT_PAGER=cat
        fi
 -      : ${LESS=-FRX}
 -      : ${LV=-c}
 +      : "${LESS=-FRX}"
 +      : "${LV=-c}"
        export LESS LV
  
        eval "$GIT_PAGER" '"$@"'
@@@ -182,7 -185,7 +185,7 @@@ is_bare_repository () 
  cd_to_toplevel () {
        cdup=$(git rev-parse --show-toplevel) &&
        cd "$cdup" || {
-               echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree"
+               gettextln "Cannot chdir to \$cdup, the toplevel of the working tree" >&2
                exit 1
        }
  }
  require_work_tree_exists () {
        if test "z$(git rev-parse --is-bare-repository)" != zfalse
        then
-               die "fatal: $0 cannot be used without a working tree."
+               program_name=$0
+               die "$(gettext "fatal: \$program_name cannot be used without a working tree.")"
        fi
  }
  
  require_work_tree () {
-       test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = true ||
-       die "fatal: $0 cannot be used without a working tree."
+       test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = true || {
+               program_name=$0
+               die "$(gettext "fatal: \$program_name cannot be used without a working tree.")"
+       }
  }
  
  require_clean_work_tree () {
  
        if ! git diff-files --quiet --ignore-submodules
        then
-               echo >&2 "Cannot $1: You have unstaged changes."
+               action=$1
+               case "$action" in
+               rebase)
+                       gettextln "Cannot rebase: You have unstaged changes." >&2
+                       ;;
+               "rewrite branches")
+                       gettextln "Cannot rewrite branches: You have unstaged changes." >&2
+                       ;;
+               "pull with rebase")
+                       gettextln "Cannot pull with rebase: You have unstaged changes." >&2
+                       ;;
+               *)
+                       eval_gettextln "Cannot \$action: You have unstaged changes." >&2
+                       ;;
+               esac
                err=1
        fi
  
        if ! git diff-index --cached --quiet --ignore-submodules HEAD --
        then
-               if [ $err = 0 ]
+               if test $err = 0
                then
-                   echo >&2 "Cannot $1: Your index contains uncommitted changes."
+                       action=$1
+                       case "$action" in
+                       rebase)
+                               gettextln "Cannot rebase: Your index contains uncommitted changes." >&2
+                               ;;
+                       "pull with rebase")
+                               gettextln "Cannot pull with rebase: Your index contains uncommitted changes." >&2
+                               ;;
+                       *)
+                               eval_gettextln "Cannot \$action: Your index contains uncommitted changes." >&2
+                               ;;
+                       esac
                else
-                   echo >&2 "Additionally, your index contains uncommitted changes."
+                   gettextln "Additionally, your index contains uncommitted changes." >&2
                fi
                err=1
        fi
  
-       if [ $err = 1 ]
+       if test $err = 1
        then
-               test -n "$2" && echo >&2 "$2"
+               test -n "$2" && echo "$2" >&2
                exit 1
        fi
  }
@@@ -336,15 -367,15 +367,15 @@@ git_dir_init () 
        then
                test -z "$(git rev-parse --show-cdup)" || {
                        exit=$?
-                       echo >&2 "You need to run this command from the toplevel of the working tree."
+                       gettextln "You need to run this command from the toplevel of the working tree." >&2
                        exit $exit
                }
        fi
        test -n "$GIT_DIR" && GIT_DIR=$(cd "$GIT_DIR" && pwd) || {
-               echo >&2 "Unable to determine absolute path of git directory"
+               gettextln "Unable to determine absolute path of git directory" >&2
                exit 1
        }
 -      : ${GIT_OBJECT_DIRECTORY="$(git rev-parse --git-path objects)"}
 +      : "${GIT_OBJECT_DIRECTORY="$(git rev-parse --git-path objects)"}"
  }
  
  if test -z "$NONGIT_OK"
diff --combined git-submodule.sh
index 7c62b53cc0dfcf47770a8f30a59f625c8657c948,37c61f1652f5835f2516e81c93d44b077dd31d3b..4ec7546f1eb5617b85169cb6e926b9f490e1d6dc
@@@ -9,14 -9,13 +9,13 @@@ USAGE="[--quiet] add [-b <branch>] [-f|
     or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
     or: $dashless [--quiet] init [--] [<path>...]
     or: $dashless [--quiet] deinit [-f|--force] (--all| [--] <path>...)
 -   or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--reference <repository>] [--recursive] [--] [<path>...]
 +   or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--] [<path>...]
     or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
     or: $dashless [--quiet] foreach [--recursive] <command>
     or: $dashless [--quiet] sync [--recursive] [--] [<path>...]"
  OPTIONS_SPEC=
  SUBDIRECTORY_OK=Yes
  . git-sh-setup
- . git-sh-i18n
  . git-parse-remote
  require_work_tree
  wt_prefix=$(git rev-parse --show-prefix)
@@@ -46,6 -45,41 +45,6 @@@ prefix
  custom_name=
  depth=
  
 -# Resolve a path to be relative to another path.  This is intended for
 -# converting submodule paths when git-submodule is run in a subdirectory
 -# and only handles paths where the directory separator is '/'.
 -#
 -# The output is the first argument as a path relative to the second argument,
 -# which defaults to $wt_prefix if it is omitted.
 -relative_path ()
 -{
 -      local target curdir result
 -      target=$1
 -      curdir=${2-$wt_prefix}
 -      curdir=${curdir%/}
 -      result=
 -
 -      while test -n "$curdir"
 -      do
 -              case "$target" in
 -              "$curdir/"*)
 -                      target=${target#"$curdir"/}
 -                      break
 -                      ;;
 -              esac
 -
 -              result="${result}../"
 -              if test "$curdir" = "${curdir%/*}"
 -              then
 -                      curdir=
 -              else
 -                      curdir="${curdir%/*}"
 -              fi
 -      done
 -
 -      echo "$result$target"
 -}
 -
  die_if_unmatched ()
  {
        if test "$1" = "#unmatched"
@@@ -240,14 -274,15 +239,15 @@@ Use -f if you really want to add it." >
                then
                        if test -z "$force"
                        then
-                               echo >&2 "$(eval_gettext "A git directory for '\$sm_name' is found locally with remote(s):")"
+                               eval_gettextln >&2 "A git directory for '\$sm_name' is found locally with remote(s):"
                                GIT_DIR=".git/modules/$sm_name" GIT_WORK_TREE=. git remote -v | grep '(fetch)' | sed -e s,^,"  ", -e s,' (fetch)',, >&2
-                               echo >&2 "$(eval_gettext "If you want to reuse this local git directory instead of cloning again from")"
-                               echo >&2 "  $realrepo"
-                               echo >&2 "$(eval_gettext "use the '--force' option. If the local git directory is not the correct repo")"
-                               die "$(eval_gettext "or you are unsure what this means choose another name with the '--name' option.")"
+                               die "$(eval_gettextln "\
+ If you want to reuse this local git directory instead of cloning again from
+   \$realrepo
+ use the '--force' option. If the local git directory is not the correct repo
+ or you are unsure what this means choose another name with the '--name' option.")"
                        else
-                               echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")"
+                               eval_gettextln "Reactivating local git directory for submodule '\$sm_name'."
                        fi
                fi
                git submodule--helper clone ${GIT_QUIET:+--quiet} --prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo" ${reference:+"$reference"} ${depth:+"$depth"} || exit
@@@ -310,23 -345,20 +310,23 @@@ cmd_foreach(
        # command in the subshell (and a recursive call to this function)
        exec 3<&0
  
 -      git submodule--helper list --prefix "$wt_prefix"|
 +      {
 +              git submodule--helper list --prefix "$wt_prefix" ||
 +              echo "#unmatched"
 +      } |
        while read mode sha1 stage sm_path
        do
                die_if_unmatched "$mode"
                if test -e "$sm_path"/.git
                then
 -                      displaypath=$(relative_path "$prefix$sm_path")
 +                      displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
                        say "$(eval_gettext "Entering '\$displaypath'")"
                        name=$(git submodule--helper name "$sm_path")
                        (
                                prefix="$prefix$sm_path/"
                                sanitize_submodule_env
                                cd "$sm_path" &&
 -                              sm_path=$(relative_path "$sm_path") &&
 +                              sm_path=$(git submodule--helper relative-path "$sm_path" "$wt_prefix") &&
                                # we make $path available to scripts ...
                                path=$sm_path &&
                                if test $# -eq 1
@@@ -421,16 -453,13 +421,16 @@@ cmd_deinit(
                die "$(eval_gettext "Use '--all' if you really want to deinitialize all submodules")"
        fi
  
 -      git submodule--helper list --prefix "$wt_prefix" "$@" |
 +      {
 +              git submodule--helper list --prefix "$wt_prefix" "$@" ||
 +              echo "#unmatched"
 +      } |
        while read mode sha1 stage sm_path
        do
                die_if_unmatched "$mode"
                name=$(git submodule--helper name "$sm_path") || exit
  
 -              displaypath=$(relative_path "$sm_path")
 +              displaypath=$(git submodule--helper relative-path "$sm_path" "$wt_prefix")
  
                # Remove the submodule work tree (unless the user already did it)
                if test -d "$sm_path"
                        # Protect submodules containing a .git directory
                        if test -d "$sm_path/.git"
                        then
-                               echo >&2 "$(eval_gettext "Submodule work tree '\$displaypath' contains a .git directory")"
-                               die "$(eval_gettext "(use 'rm -rf' if you really want to remove it including all of its history)")"
+                               die "$(eval_gettext "\
+ Submodule work tree '\$displaypath' contains a .git directory
+ (use 'rm -rf' if you really want to remove it including all of its history)")"
                        fi
  
                        if test -z "$force"
@@@ -530,12 -560,6 +531,12 @@@ cmd_update(
                --checkout)
                        update="checkout"
                        ;;
 +              --recommend-shallow)
 +                      recommend_shallow="--recommend-shallow"
 +                      ;;
 +              --no-recommend-shallow)
 +                      recommend_shallow="--no-recommend-shallow"
 +                      ;;
                --depth)
                        case "$2" in '') usage ;; esac
                        depth="--depth=$2"
                ${update:+--update "$update"} \
                ${reference:+--reference "$reference"} \
                ${depth:+--depth "$depth"} \
 +              ${recommend_shallow:+"$recommend_shallow"} \
                ${jobs:+$jobs} \
                "$@" || echo "#unmatched"
        } | {
                        fi
                fi
  
 -              displaypath=$(relative_path "$prefix$sm_path")
 +              displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
  
                if test $just_cloned -eq 1
                then
                        if test -z "$nofetch"
                        then
                                # Fetch remote before determining tracking $sha1
 -                              (sanitize_submodule_env; cd "$sm_path" && git-fetch) ||
 +                              fetch_in_submodule "$sm_path" ||
                                die "$(eval_gettext "Unable to fetch in submodule path '\$sm_path'")"
                        fi
                        remote_name=$(sanitize_submodule_env; cd "$sm_path" && get_default_remote)
                        sha1=$(sanitize_submodule_env; cd "$sm_path" &&
                                git rev-parse --verify "${remote_name}/${branch}") ||
-                       die "$(eval_gettext "Unable to find current ${remote_name}/${branch} revision in submodule path '\$sm_path'")"
+                       die "$(eval_gettext "Unable to find current \${remote_name}/\${branch} revision in submodule path '\$sm_path'")"
                fi
  
                if test "$subsha1" != "$sha1" || test -n "$force"
                                # not be reachable from any of the refs
                                is_tip_reachable "$sm_path" "$sha1" ||
                                fetch_in_submodule "$sm_path" "$sha1" ||
-                               die "$(eval_gettext "Fetched in submodule path '\$displaypath', but it did not contain $sha1. Direct fetching of that commit failed.")"
+                               die "$(eval_gettext "Fetched in submodule path '\$displaypath', but it did not contain \$sha1. Direct fetching of that commit failed.")"
                        fi
  
                        must_die_on_failure=
                if test -n "$recursive"
                then
                        (
 -                              prefix=$(relative_path "$prefix$sm_path/")
 +                              prefix=$(git submodule--helper relative-path "$prefix$sm_path/" "$wt_prefix")
                                wt_prefix=
                                sanitize_submodule_env
                                cd "$sm_path" &&
                        if test $res -gt 0
                        then
                                die_msg="$(eval_gettext "Failed to recurse into submodule path '\$displaypath'")"
 -                              if test $res -eq 1
 +                              if test $res -ne 2
                                then
                                        err="${err};$die_msg"
                                        continue
@@@ -879,7 -902,7 +880,7 @@@ cmd_summary() 
                ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
                missing_dst=t
  
 -              display_name=$(relative_path "$name")
 +              display_name=$(git submodule--helper relative-path "$name" "$wt_prefix")
  
                total_commits=
                case "$missing_src,$missing_dst" in
@@@ -991,16 -1014,13 +992,16 @@@ cmd_status(
                shift
        done
  
 -      git submodule--helper list --prefix "$wt_prefix" "$@" |
 +      {
 +              git submodule--helper list --prefix "$wt_prefix" "$@" ||
 +              echo "#unmatched"
 +      } |
        while read mode sha1 stage sm_path
        do
                die_if_unmatched "$mode"
                name=$(git submodule--helper name "$sm_path") || exit
                url=$(git config submodule."$name".url)
 -              displaypath=$(relative_path "$prefix$sm_path")
 +              displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
                if test "$stage" = U
                then
                        say "U$sha1 $displaypath"
@@@ -1072,10 -1092,7 +1073,10 @@@ cmd_sync(
                esac
        done
        cd_to_toplevel
 -      git submodule--helper list --prefix "$wt_prefix" "$@" |
 +      {
 +              git submodule--helper list --prefix "$wt_prefix" "$@" ||
 +              echo "#unmatched"
 +      } |
        while read mode sha1 stage sm_path
        do
                die_if_unmatched "$mode"
  
                if git config "submodule.$name.url" >/dev/null 2>/dev/null
                then
 -                      displaypath=$(relative_path "$prefix$sm_path")
 +                      displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
                        say "$(eval_gettext "Synchronizing submodule url for '\$displaypath'")"
                        git config submodule."$name".url "$super_config_url"
  
diff --combined sequencer.c
index a33c39b64fbd9cf42e5bd531488f7d2366bd167b,e916387e481afd8e01f2d2c4b595391d70c71df5..cdfac82b117e9ff1084f3fbe36eeb85f45ce056c
@@@ -190,7 -190,7 +190,7 @@@ static void write_message(struct strbu
                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)
@@@ -225,7 -225,7 +225,7 @@@ static int fast_forward_to(const unsign
        if (checkout_fast_forward(from, to, 1))
                exit(128); /* the callee should have complained already */
  
-       strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
+       strbuf_addf(&sb, _("%s: fast-forward"), action_name(opts));
  
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
@@@ -544,8 -544,10 +544,8 @@@ static int do_pick_commit(struct commi
                 * information followed by "\n\n".
                 */
                p = strstr(msg.message, "\n\n");
 -              if (p) {
 -                      p += 2;
 -                      strbuf_addstr(&msgbuf, p);
 -              }
 +              if (p)
 +                      strbuf_addstr(&msgbuf, skip_blank_lines(p + 2));
  
                if (opts->record_origin) {
                        if (!has_conforming_footer(&msgbuf, NULL, 0))
@@@ -695,9 -697,14 +695,14 @@@ static struct commit *parse_insn_line(c
         * opts; we don't support arbitrary instructions
         */
        if (action != opts->action) {
-               const char *action_str;
-               action_str = action == REPLAY_REVERT ? "revert" : "cherry-pick";
-               error(_("Cannot %s during a %s"), action_str, action_name(opts));
+               if (action == REPLAY_REVERT)
+                     error((opts->action == REPLAY_REVERT)
+                           ? _("Cannot revert during a another revert.")
+                           : _("Cannot revert during a cherry-pick."));
+               else
+                     error((opts->action == REPLAY_REVERT)
+                           ? _("Cannot cherry-pick during a revert.")
+                           : _("Cannot cherry-pick during another cherry-pick."));
                return NULL;
        }
  
@@@ -886,10 -893,6 +891,10 @@@ static int sequencer_rollback(struct re
                        git_path_head_file());
                goto fail;
        }
 +      if (is_null_sha1(sha1)) {
 +              error(_("cannot abort from a branch yet to be born"));
 +              goto fail;
 +      }
        if (reset_for_rollback(sha1))
                goto fail;
        remove_sequencer_state();
@@@ -1088,8 -1091,11 +1093,8 @@@ int sequencer_pick_revisions(struct rep
        walk_revs_populate_todo(&todo_list, opts);
        if (create_seq_dir() < 0)
                return -1;
 -      if (get_sha1("HEAD", sha1)) {
 -              if (opts->action == REPLAY_REVERT)
 -                      return error(_("Can't revert as initial commit"));
 -              return error(_("Can't cherry-pick into empty head"));
 -      }
 +      if (get_sha1("HEAD", sha1) && (opts->action == REPLAY_REVERT))
 +              return error(_("Can't revert as initial commit"));
        save_head(sha1_to_hex(sha1));
        save_opts(opts);
        return pick_commits(todo_list, opts);
diff --combined t/t0008-ignores.sh
index b425f3a0d21cc9e99ce5de0c436e090e32e8f7d9,43aa2bd8f8682eae6c984505e12852ec5856ea59..d27f438bf410d06f37ec76a6ce040316218a8138
@@@ -34,7 -34,7 +34,7 @@@ expect_from_stdin () 
  test_stderr () {
        expected="$1"
        expect_in stderr "$1" &&
-       test_cmp "$HOME/expected-stderr" "$HOME/stderr"
+       test_i18ncmp "$HOME/expected-stderr" "$HOME/stderr"
  }
  
  broken_c_unquote () {
@@@ -47,7 -47,7 +47,7 @@@ broken_c_unquote_verbose () 
  
  stderr_contains () {
        regexp="$1"
-       if grep "$regexp" "$HOME/stderr"
+       if test_i18ngrep "$regexp" "$HOME/stderr"
        then
                return 0
        else
@@@ -605,7 -605,7 +605,7 @@@ cat <<-EOF >expected-verbos
        a/b/.gitignore:8:!on*   a/b/one
        a/b/.gitignore:8:!on*   a/b/one one
        a/b/.gitignore:8:!on*   a/b/one two
 -      a/b/.gitignore:8:!on*   "a/b/one\"three"
 +      a/b/.gitignore:8:!on*   "a/b/one\\"three"
        a/b/.gitignore:9:!two   a/b/two
        a/.gitignore:1:two*     a/b/twooo
        $global_excludes:2:!globaltwo   globaltwo
@@@ -686,7 -686,7 +686,7 @@@ cat <<-EOF >expected-al
        a/b/.gitignore:8:!on*   b/one
        a/b/.gitignore:8:!on*   b/one one
        a/b/.gitignore:8:!on*   b/one two
 -      a/b/.gitignore:8:!on*   "b/one\"three"
 +      a/b/.gitignore:8:!on*   "b/one\\"three"
        a/b/.gitignore:9:!two   b/two
        ::      b/not-ignored
        a/.gitignore:1:two*     b/twooo
diff --combined t/t1308-config-set.sh
index cf716b469f10f37a591b32ef2d3eb6da4ba63f78,cd6206351f94ab37b756fbb10a9b5d5fd3373a16..a06e71ceeda8261dc7773d24f5f264ee6bdc2893
@@@ -197,14 -197,14 +197,14 @@@ test_expect_success 'proper error on er
        echo "[" >>.git/config &&
        echo "fatal: bad config line 34 in file .git/config" >expect &&
        test_expect_code 128 test-config get_value foo.bar 2>actual &&
-       test_cmp expect actual
+       test_i18ncmp expect actual
  '
  
  test_expect_success 'proper error on error in custom config files' '
        echo "[" >>syntax-error &&
        echo "fatal: bad config line 1 in file syntax-error" >expect &&
        test_expect_code 128 test-config configset_get_value foo.bar syntax-error 2>actual &&
-       test_cmp expect actual
+       test_i18ncmp expect actual
  '
  
  test_expect_success 'check line errors for malformed values' '
@@@ -229,31 -229,4 +229,31 @@@ test_expect_success 'error on modifyin
        )
  '
  
 +cmdline_config="'foo.bar=from-cmdline'"
 +test_expect_success 'iteration shows correct origins' '
 +      echo "[foo]bar = from-repo" >.git/config &&
 +      echo "[foo]bar = from-home" >.gitconfig &&
 +      cat >expect <<-EOF &&
 +      key=foo.bar
 +      value=from-home
 +      origin=file
 +      name=$HOME/.gitconfig
 +      scope=global
 +
 +      key=foo.bar
 +      value=from-repo
 +      origin=file
 +      name=.git/config
 +      scope=repo
 +
 +      key=foo.bar
 +      value=from-cmdline
 +      origin=command line
 +      name=
 +      scope=cmdline
 +      EOF
 +      GIT_CONFIG_PARAMETERS=$cmdline_config test-config iterate >actual &&
 +      test_cmp expect actual
 +'
 +
  test_done
diff --combined t/t5520-pull.sh
index 3159956fde89639354fe5ed4d3cdf083a2cbbb0f,45e44cac6be8d8f719893853719882774f07432d..37ebbcfbbf0fd7815f598cf54d9c2c2825341f41
@@@ -211,7 -211,7 +211,7 @@@ test_expect_success 'fail if the index 
        test -n "$(git ls-files -u)" &&
        cp file expected &&
        test_must_fail git pull . second 2>err &&
-       test_i18ngrep "Pull is not possible because you have unmerged files" err &&
+       test_i18ngrep "Pulling is not possible because you have unmerged files." err &&
        test_cmp expected file &&
        git add file &&
        test -z "$(git ls-files -u)" &&
@@@ -341,22 -341,6 +341,22 @@@ test_expect_success 'branch.to-rebase.r
        test new = "$(git show HEAD:file2)"
  '
  
 +test_expect_success "pull --rebase warns on --verify-signatures" '
 +      git reset --hard before-rebase &&
 +      git pull --rebase --verify-signatures . copy 2>err &&
 +      test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" &&
 +      test new = "$(git show HEAD:file2)" &&
 +      test_i18ngrep "ignoring --verify-signatures for rebase" err
 +'
 +
 +test_expect_success "pull --rebase does not warn on --no-verify-signatures" '
 +      git reset --hard before-rebase &&
 +      git pull --rebase --no-verify-signatures . copy 2>err &&
 +      test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" &&
 +      test new = "$(git show HEAD:file2)" &&
 +      test_i18ngrep ! "verify-signatures" err
 +'
 +
  # add a feature branch, keep-merge, that is merged into master, so the
  # test can try preserving the merge commit (or not) with various
  # --rebase flags/pull.rebase settings.
index 5503ec067fa8e5d62b5308ceb7f538ad6e7dc81f,b8690b193224b003c032937f8186a298222b4e23..0726799e74e7a587e920c35f356b3364737b70d2
@@@ -62,13 -62,13 +62,13 @@@ test_expect_success 'change submodule' 
  '
  
  reset_submodule_urls () {
 -      local root
 -      root=$(pwd) &&
        (
 +              root=$(pwd) &&
                cd super-clone/submodule &&
                git config remote.origin.url "$root/submodule"
        ) &&
        (
 +              root=$(pwd) &&
                cd super-clone/submodule/sub-submodule &&
                git config remote.origin.url "$root/submodule"
        )
@@@ -157,7 -157,7 +157,7 @@@ test_expect_success '"git submodule syn
                cd sub &&
                git submodule sync >../../output
        ) &&
-       grep "\\.\\./submodule" output &&
+       test_i18ngrep "\\.\\./submodule" output &&
        test -d "$(
                cd super-clone/submodule &&
                git config remote.origin.url
@@@ -188,7 -188,7 +188,7 @@@ test_expect_success '"git submodule syn
                cd sub &&
                git submodule sync --recursive >../../output
        ) &&
-       grep "\\.\\./submodule/sub-submodule" output &&
+       test_i18ngrep "\\.\\./submodule/sub-submodule" output &&
        test -d "$(
                cd super-clone/submodule &&
                git config remote.origin.url
diff --combined wt-status.c
index 4ce4e35ac3f3542c42c9f71e7bb3f0c5e2c67492,5a9127985e322d540b5fd519be22f934e6002383..c19b52ce8708ebe997f5bc728124a4653014543f
@@@ -263,7 -263,7 +263,7 @@@ static const char *wt_status_unmerged_s
        case 7:
                return _("both modified:");
        default:
-               die(_("bug: unhandled unmerged status %x"), stagemask);
+               die("bug: unhandled unmerged status %x", stagemask);
        }
  }
  
@@@ -388,7 -388,7 +388,7 @@@ static void wt_status_print_change_data
        status_printf(s, color(WT_STATUS_HEADER, s), "\t");
        what = wt_status_diff_status_string(status);
        if (!what)
-               die(_("bug: unhandled diff status %c"), status);
+               die("bug: unhandled diff status %c", status);
        len = label_width - utf8_strwidth(what);
        assert(len >= 0);
        if (status == DIFF_STATUS_COPIED || status == DIFF_STATUS_RENAMED)
@@@ -1554,7 -1554,7 +1554,7 @@@ void wt_status_print(struct wt_status *
                        else
                                printf(_("nothing to commit\n"));
                } else
 -                      printf(_("nothing to commit, working directory clean\n"));
 +                      printf(_("nothing to commit, working tree clean\n"));
        }
  }