Merge branch 'pg/maint-apply-remove-unused-variable'
authorJunio C Hamano <gitster@pobox.com>
Wed, 22 Aug 2012 18:51:33 +0000 (11:51 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 22 Aug 2012 18:51:33 +0000 (11:51 -0700)
Remove an unused field.

* pg/maint-apply-remove-unused-variable:
apply: delete unused deflate_origlen from patch struct

1  2 
builtin/apply.c
diff --combined builtin/apply.c
index d453c833782c6aae4dd04fb9f9f68c3a8211d3d5,74f47486fed456eb9559113a6884067decbecd4c..3bf71dc4522564463945673aaba0501a51141bb2
  #include "builtin.h"
  #include "string-list.h"
  #include "dir.h"
 +#include "diff.h"
  #include "parse-options.h"
 +#include "xdiff-interface.h"
 +#include "ll-merge.h"
 +#include "rerere.h"
  
  /*
   *  --check turns on checking that the working tree matches the
@@@ -49,12 -45,11 +49,12 @@@ static int apply_with_reject
  static int apply_verbosely;
  static int allow_overlap;
  static int no_add;
 +static int threeway;
  static const char *fake_ancestor;
  static int line_termination = '\n';
  static unsigned int p_context = UINT_MAX;
  static const char * const apply_usage[] = {
 -      "git apply [options] [<patch>...]",
 +      N_("git apply [options] [<patch>...]"),
        NULL
  };
  
@@@ -107,7 -102,7 +107,7 @@@ static void parse_whitespace_option(con
                ws_error_action = correct_ws_error;
                return;
        }
 -      die("unrecognized whitespace option '%s'", option);
 +      die(_("unrecognized whitespace option '%s'"), option);
  }
  
  static void parse_ignorewhitespace_option(const char *option)
                ws_ignore_action = ignore_ws_change;
                return;
        }
 -      die("unrecognized whitespace ignore option '%s'", option);
 +      die(_("unrecognized whitespace ignore option '%s'"), option);
  }
  
  static void set_default_whitespace_mode(const char *whitespace_option)
@@@ -156,14 -151,9 +156,14 @@@ struct fragment 
        unsigned long leading, trailing;
        unsigned long oldpos, oldlines;
        unsigned long newpos, newlines;
 +      /*
 +       * 'patch' is usually borrowed from buf in apply_patch(),
 +       * but some codepaths store an allocated buffer.
 +       */
        const char *patch;
 +      unsigned free_patch:1,
 +              rejected:1;
        int size;
 -      int rejected;
        int linenr;
        struct fragment *next;
  };
@@@ -188,7 -178,6 +188,6 @@@ struct patch 
        int is_new, is_delete;  /* -1 = unknown, 0 = false, 1 = true */
        int rejected;
        unsigned ws_rule;
-       unsigned long deflate_origlen;
        int lines_added, lines_deleted;
        int score;
        unsigned int is_toplevel_relative:1;
        unsigned int is_copy:1;
        unsigned int is_rename:1;
        unsigned int recount:1;
 +      unsigned int conflicted_threeway:1;
 +      unsigned int direct_to_threeway:1;
        struct fragment *fragments;
        char *result;
        size_t resultsize;
        char old_sha1_prefix[41];
        char new_sha1_prefix[41];
        struct patch *next;
 +
 +      /* three-way fallback result */
 +      unsigned char threeway_stage[3][20];
  };
  
 +static void free_fragment_list(struct fragment *list)
 +{
 +      while (list) {
 +              struct fragment *next = list->next;
 +              if (list->free_patch)
 +                      free((char *)list->patch);
 +              free(list);
 +              list = next;
 +      }
 +}
 +
 +static void free_patch(struct patch *patch)
 +{
 +      free_fragment_list(patch->fragments);
 +      free(patch->def_name);
 +      free(patch->old_name);
 +      free(patch->new_name);
 +      free(patch->result);
 +      free(patch);
 +}
 +
 +static void free_patch_list(struct patch *list)
 +{
 +      while (list) {
 +              struct patch *next = list->next;
 +              free_patch(list);
 +              list = next;
 +      }
 +}
 +
  /*
   * A line in a file, len-bytes long (includes the terminating LF,
   * except for an incomplete line at the end if the file ends with
@@@ -295,6 -249,9 +294,6 @@@ static int fuzzy_matchlines(const char 
        const char *last2 = s2 + n2 - 1;
        int result = 0;
  
 -      if (n1 < 0 || n2 < 0)
 -              return 0;
 -
        /* ignore line endings */
        while ((*last1 == '\r') || (*last1 == '\n'))
                last1--;
@@@ -346,11 -303,6 +345,11 @@@ static void add_line_info(struct image 
        img->nr++;
  }
  
 +/*
 + * "buf" has the file contents to be patched (read from various sources).
 + * attach it to "image" and add line-based index to it.
 + * "image" now owns the "buf".
 + */
  static void prepare_image(struct image *image, char *buf, size_t len,
                          int prepare_linetable)
  {
  static void clear_image(struct image *image)
  {
        free(image->buf);
 -      image->buf = NULL;
 -      image->len = 0;
 +      free(image->line_allocated);
 +      memset(image, 0, sizeof(*image));
  }
  
 -static void say_patch_name(FILE *output, const char *pre,
 -                         struct patch *patch, const char *post)
 +/* fmt must contain _one_ %s and no other substitution */
 +static void say_patch_name(FILE *output, const char *fmt, struct patch *patch)
  {
 -      fputs(pre, output);
 +      struct strbuf sb = STRBUF_INIT;
 +
        if (patch->old_name && patch->new_name &&
            strcmp(patch->old_name, patch->new_name)) {
 -              quote_c_style(patch->old_name, NULL, output, 0);
 -              fputs(" => ", output);
 -              quote_c_style(patch->new_name, NULL, output, 0);
 +              quote_c_style(patch->old_name, &sb, NULL, 0);
 +              strbuf_addstr(&sb, " => ");
 +              quote_c_style(patch->new_name, &sb, NULL, 0);
        } else {
                const char *n = patch->new_name;
                if (!n)
                        n = patch->old_name;
 -              quote_c_style(n, NULL, output, 0);
 +              quote_c_style(n, &sb, NULL, 0);
        }
 -      fputs(post, output);
 +      fprintf(output, fmt, sb.buf);
 +      fputc('\n', output);
 +      strbuf_release(&sb);
  }
  
 -#define CHUNKSIZE (8192)
  #define SLOP (16)
  
  static void read_patch_file(struct strbuf *sb, int fd)
@@@ -467,7 -417,7 +466,7 @@@ static char *squash_slash(char *name
        return name;
  }
  
 -static char *find_name_gnu(const char *line, char *def, int p_value)
 +static char *find_name_gnu(const char *line, const char *def, int p_value)
  {
        struct strbuf name = STRBUF_INIT;
        char *cp;
                cp++;
        }
  
 -      /* name can later be freed, so we need
 -       * to memmove, not just return cp
 -       */
        strbuf_remove(&name, 0, cp - name.buf);
 -      free(def);
        if (root)
                strbuf_insert(&name, 0, root, root_len);
        return squash_slash(strbuf_detach(&name, NULL));
@@@ -655,13 -609,8 +654,13 @@@ static size_t diff_timestamp_len(const 
        return line + len - end;
  }
  
 -static char *find_name_common(const char *line, char *def, int p_value,
 -                              const char *end, int terminate)
 +static char *null_strdup(const char *s)
 +{
 +      return s ? xstrdup(s) : NULL;
 +}
 +
 +static char *find_name_common(const char *line, const char *def,
 +                            int p_value, const char *end, int terminate)
  {
        int len;
        const char *start = NULL;
                        start = line;
        }
        if (!start)
 -              return squash_slash(def);
 +              return squash_slash(null_strdup(def));
        len = line - start;
        if (!len)
 -              return squash_slash(def);
 +              return squash_slash(null_strdup(def));
  
        /*
         * Generally we prefer the shorter name, especially
        if (def) {
                int deflen = strlen(def);
                if (deflen < len && !strncmp(start, def, deflen))
 -                      return squash_slash(def);
 -              free(def);
 +                      return squash_slash(xstrdup(def));
        }
  
        if (root) {
@@@ -821,7 -771,7 +820,7 @@@ static int has_epoch_timestamp(const ch
        if (!stamp) {
                stamp = xmalloc(sizeof(*stamp));
                if (regcomp(stamp, stamp_regexp, REG_EXTENDED)) {
 -                      warning("Cannot prepare timestamp regexp %s",
 +                      warning(_("Cannot prepare timestamp regexp %s"),
                                stamp_regexp);
                        return 0;
                }
        status = regexec(stamp, timestamp, ARRAY_SIZE(m), m, 0);
        if (status) {
                if (status != REG_NOMATCH)
 -                      warning("regexec returned %d for input: %s",
 +                      warning(_("regexec returned %d for input: %s"),
                                status, timestamp);
                return 0;
        }
@@@ -893,10 -843,8 +892,10 @@@ static void parse_traditional_patch(con
                name = find_name_traditional(first, NULL, p_value);
                patch->old_name = name;
        } else {
 -              name = find_name_traditional(first, NULL, p_value);
 -              name = find_name_traditional(second, name, p_value);
 +              char *first_name;
 +              first_name = find_name_traditional(first, NULL, p_value);
 +              name = find_name_traditional(second, first_name, p_value);
 +              free(first_name);
                if (has_epoch_timestamp(first)) {
                        patch->is_new = 1;
                        patch->is_delete = 0;
                        patch->is_delete = 1;
                        patch->old_name = name;
                } else {
 -                      patch->old_name = patch->new_name = name;
 +                      patch->old_name = name;
 +                      patch->new_name = xstrdup(name);
                }
        }
        if (!name)
 -              die("unable to find filename in patch at line %d", linenr);
 +              die(_("unable to find filename in patch at line %d"), linenr);
  }
  
  static int gitdiff_hdrend(const char *line, struct patch *patch)
   * their names against any previous information, just
   * to make sure..
   */
 -static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name, const char *oldnew)
 +#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)
  {
        if (!orig_name && !isnull)
                return find_name(line, NULL, p_value, TERM_TAB);
                name = orig_name;
                len = strlen(name);
                if (isnull)
 -                      die("git apply: bad git-diff - expected /dev/null, got %s on line %d", name, linenr);
 +                      die(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"), name, linenr);
                another = find_name(line, NULL, p_value, TERM_TAB);
                if (!another || memcmp(another, name, len + 1))
 -                      die("git apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr);
 +                      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);
                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);
 +                      die(_("git apply: bad git-diff - expected /dev/null on line %d"), linenr);
                return NULL;
        }
  }
  
  static int gitdiff_oldname(const char *line, struct patch *patch)
  {
 -      patch->old_name = gitdiff_verify_name(line, patch->is_new, patch->old_name, "old");
 +      char *orig = patch->old_name;
 +      patch->old_name = gitdiff_verify_name(line, patch->is_new, patch->old_name,
 +                                            DIFF_OLD_NAME);
 +      if (orig != patch->old_name)
 +              free(orig);
        return 0;
  }
  
  static int gitdiff_newname(const char *line, struct patch *patch)
  {
 -      patch->new_name = gitdiff_verify_name(line, patch->is_delete, patch->new_name, "new");
 +      char *orig = patch->new_name;
 +      patch->new_name = gitdiff_verify_name(line, patch->is_delete, patch->new_name,
 +                                            DIFF_NEW_NAME);
 +      if (orig != patch->new_name)
 +              free(orig);
        return 0;
  }
  
@@@ -995,23 -929,20 +994,23 @@@ static int gitdiff_newmode(const char *
  static int gitdiff_delete(const char *line, struct patch *patch)
  {
        patch->is_delete = 1;
 -      patch->old_name = patch->def_name;
 +      free(patch->old_name);
 +      patch->old_name = null_strdup(patch->def_name);
        return gitdiff_oldmode(line, patch);
  }
  
  static int gitdiff_newfile(const char *line, struct patch *patch)
  {
        patch->is_new = 1;
 -      patch->new_name = patch->def_name;
 +      free(patch->new_name);
 +      patch->new_name = null_strdup(patch->def_name);
        return gitdiff_newmode(line, patch);
  }
  
  static int gitdiff_copysrc(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);
        return 0;
  }
  static int gitdiff_copydst(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);
        return 0;
  }
  static int gitdiff_renamesrc(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);
        return 0;
  }
  static int gitdiff_renamedst(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);
        return 0;
  }
@@@ -1117,7 -1045,7 +1116,7 @@@ static const char *stop_at_slash(const 
   * 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(char *line, int llen)
 +static char *git_header_name(const char *line, int llen)
  {
        const char *name;
        const char *second = NULL;
  }
  
  /* Verify that we recognize the lines following a git header */
 -static int parse_git_header(char *line, int len, unsigned int size, struct patch *patch)
 +static int parse_git_header(const char *line, int len, unsigned int size, struct patch *patch)
  {
        unsigned long offset;
  
@@@ -1360,7 -1288,7 +1359,7 @@@ static int parse_range(const char *line
        return offset + ex;
  }
  
 -static void recount_diff(char *line, int size, struct fragment *fragment)
 +static void recount_diff(const char *line, int size, struct fragment *fragment)
  {
        int oldlines = 0, newlines = 0, ret = 0;
  
                        break;
                }
                if (ret) {
 -                      warning("recount: unexpected line: %.*s",
 +                      warning(_("recount: unexpected line: %.*s"),
                                (int)linelen(line, size), line);
                        return;
                }
   * Parse a unified diff fragment header of the
   * form "@@ -a,b +c,d @@"
   */
 -static int parse_fragment_header(char *line, int len, struct fragment *fragment)
 +static int parse_fragment_header(const char *line, int len, struct fragment *fragment)
  {
        int offset;
  
        return offset;
  }
  
 -static int find_header(char *line, unsigned long size, int *hdrsize, struct patch *patch)
 +static int find_header(const char *line, unsigned long size, int *hdrsize, struct patch *patch)
  {
        unsigned long offset, len;
  
                        struct fragment dummy;
                        if (parse_fragment_header(line, len, &dummy) < 0)
                                continue;
 -                      die("patch fragment without header at line %d: %.*s",
 +                      die(_("patch fragment without header at line %d: %.*s"),
                            linenr, (int)len-1, line);
                }
  
                                continue;
                        if (!patch->old_name && !patch->new_name) {
                                if (!patch->def_name)
 -                                      die("git diff header lacks filename information when removing "
 -                                          "%d leading pathname components (line %d)" , p_value, linenr);
 -                              patch->old_name = patch->new_name = patch->def_name;
 +                                      die(Q_("git diff header lacks filename information when removing "
 +                                             "%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);
 +                              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);
                        patch->is_toplevel_relative = 1;
                        *hdrsize = git_hdr_len;
                        return offset;
@@@ -1544,7 -1464,7 +1543,7 @@@ static void check_whitespace(const cha
   * 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(char *line, unsigned long size,
 +static int parse_fragment(const char *line, unsigned long size,
                          struct patch *patch, struct fragment *fragment)
  {
        int added, deleted;
        patch->lines_deleted += deleted;
  
        if (0 < patch->is_new && oldlines)
 -              return error("new file depends on old contents");
 +              return error(_("new file depends on old contents"));
        if (0 < patch->is_delete && newlines)
 -              return error("deleted file still has contents");
 +              return error(_("deleted file still has contents"));
        return offset;
  }
  
 -static int parse_single_patch(char *line, unsigned long size, struct patch *patch)
 +/*
 + * We have seen "diff --git a/... b/..." header (or a traditional patch
 + * header).  Read hunks that belong to this patch into fragments and hang
 + * them to the given patch structure.
 + *
 + * 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)
  {
        unsigned long offset = 0;
        unsigned long oldlines = 0, newlines = 0, context = 0;
                fragment->linenr = linenr;
                len = parse_fragment(line, size, patch, fragment);
                if (len <= 0)
 -                      die("corrupt patch at line %d", linenr);
 +                      die(_("corrupt patch at line %d"), linenr);
                fragment->patch = line;
                fragment->size = len;
                oldlines += fragment->oldlines;
                patch->is_delete = 0;
  
        if (0 < patch->is_new && oldlines)
 -              die("new file %s depends on old contents", patch->new_name);
 +              die(_("new file %s depends on old contents"), patch->new_name);
        if (0 < patch->is_delete && newlines)
 -              die("deleted file %s still has contents", patch->old_name);
 +              die(_("deleted file %s still has contents"), patch->old_name);
        if (!patch->is_delete && !newlines && context)
 -              fprintf(stderr, "** warning: file %s becomes empty but "
 -                      "is not deleted\n", patch->new_name);
 +              fprintf_ln(stderr,
 +                         _("** warning: "
 +                           "file %s becomes empty but is not deleted"),
 +                         patch->new_name);
  
        return offset;
  }
@@@ -1743,11 -1653,6 +1742,11 @@@ static char *inflate_it(const void *dat
        return out;
  }
  
 +/*
 + * Read a binary hunk and return a new fragment; fragment->patch
 + * 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,
                                          unsigned long *sz_p,
                                          int *status_p,
  
        frag = xcalloc(1, sizeof(*frag));
        frag->patch = inflate_it(data, hunk_size, origlen);
 +      frag->free_patch = 1;
        if (!frag->patch)
                goto corrupt;
        free(data);
   corrupt:
        free(data);
        *status_p = -1;
 -      error("corrupt binary patch at line %d: %.*s",
 +      error(_("corrupt binary patch at line %d: %.*s"),
              linenr-1, llen-1, buffer);
        return NULL;
  }
@@@ -1878,7 -1782,7 +1877,7 @@@ static int parse_binary(char *buffer, u
        forward = parse_binary_hunk(&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"), linenr-1);
        if (status)
                /* otherwise we already gave an error message */
                return status;
        return used;
  }
  
 +/*
 + * Read the patch text in "buffer" taht extends for "size" bytes; stop
 + * reading after seeing a single patch (i.e. changes to a single file).
 + * Create fragments (i.e. patch hunks) and hang them to the given patch.
 + * 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)
  {
        int hdrsize, patchsize;
                 */
                if ((apply || check) &&
                    (!patch->is_binary && !metadata_changes(patch)))
 -                      die("patch with only garbage at line %d", linenr);
 +                      die(_("patch with only garbage at line %d"), linenr);
        }
  
        return offset + hdrsize + patchsize;
@@@ -2054,11 -1951,11 +2053,11 @@@ static int read_old_data(struct stat *s
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
                if (strbuf_readlink(buf, path, st->st_size) < 0)
 -                      return error("unable to read symlink %s", path);
 +                      return error(_("unable to read symlink %s"), path);
                return 0;
        case S_IFREG:
                if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
 -                      return error("unable to open or read %s", path);
 +                      return error(_("unable to open or read %s"), path);
                convert_to_git(path, buf->buf, buf->len, buf, 0);
                return 0;
        default:
@@@ -2129,7 -2026,7 +2128,7 @@@ static void update_pre_post_images(stru
                        ctx++;
                }
                if (preimage->nr <= ctx)
 -                      die("oops");
 +                      die(_("oops"));
  
                /* and copy it in, while fixing the line length */
                len = preimage->line[ctx].len;
@@@ -2468,11 -2365,6 +2467,11 @@@ static void remove_last_line(struct ima
        img->len -= img->line[--img->nr].len;
  }
  
 +/*
 + * The change from "preimage" and "postimage" has been found to
 + * 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,
                         int applied_pos,
                         struct image *preimage,
        img->nr = nr;
  }
  
 +/*
 + * Use the patch-hunk text in "frag" to prepare two images (preimage and
 + * 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,
                              int inaccurate_eof, unsigned ws_rule,
                              int nth_fragment)
        char *old, *oldlines;
        struct strbuf newlines;
        int new_blank_lines_at_end = 0;
 +      int found_new_blank_lines_at_end = 0;
 +      int hunk_linenr = frag->linenr;
        unsigned long leading, trailing;
        int pos, applied_pos;
        struct image preimage;
                        break;
                default:
                        if (apply_verbosely)
 -                              error("invalid start of line: '%c'", first);
 +                              error(_("invalid start of line: '%c'"), first);
                        return -1;
                }
 -              if (added_blank_line)
 +              if (added_blank_line) {
 +                      if (!new_blank_lines_at_end)
 +                              found_new_blank_lines_at_end = hunk_linenr;
                        new_blank_lines_at_end++;
 +              }
                else if (is_blank_context)
                        ;
                else
                        new_blank_lines_at_end = 0;
                patch += len;
                size -= len;
 +              hunk_linenr++;
        }
        if (inaccurate_eof &&
            old > oldlines && old[-1] == '\n' &&
                    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, frag->linenr);
 +                      record_ws_error(WS_BLANK_AT_EOF, "+", 1,
 +                                      found_new_blank_lines_at_end);
                        if (ws_error_action == correct_ws_error) {
                                while (new_blank_lines_at_end--)
                                        remove_last_line(&postimage);
                        int offset = applied_pos - pos;
                        if (apply_in_reverse)
                                offset = 0 - offset;
 -                      fprintf(stderr,
 -                              "Hunk #%d succeeded at %d (offset %d lines).\n",
 -                              nth_fragment, applied_pos + 1, offset);
 +                      fprintf_ln(stderr,
 +                                 Q_("Hunk #%d succeeded at %d (offset %d line).",
 +                                    "Hunk #%d succeeded at %d (offset %d lines).",
 +                                    offset),
 +                                 nth_fragment, applied_pos + 1, offset);
                }
  
                /*
                 */
                if ((leading != frag->leading) ||
                    (trailing != frag->trailing))
 -                      fprintf(stderr, "Context reduced to (%ld/%ld)"
 -                              " to apply fragment at %d\n",
 -                              leading, trailing, applied_pos+1);
 +                      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);
        } else {
                if (apply_verbosely)
 -                      error("while searching for:\n%.*s",
 +                      error(_("while searching for:\n%.*s"),
                              (int)(old - oldlines), oldlines);
        }
  
@@@ -2806,7 -2684,7 +2805,7 @@@ static int apply_binary_fragment(struc
        void *dst;
  
        if (!fragment)
 -              return error("missing binary patch data for '%s'",
 +              return error(_("missing binary patch data for '%s'"),
                             patch->new_name ?
                             patch->new_name :
                             patch->old_name);
        return -1;
  }
  
 +/*
 + * Replace "img" with the result of applying the binary patch.
 + * The binary patch data itself in patch->fragment is still kept
 + * 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)
  {
        const char *name = patch->old_name ? patch->old_name : patch->new_name;
                 * in the patch->fragments->{patch,size}.
                 */
                if (apply_binary_fragment(img, patch))
 -                      return error("binary patch does not apply to '%s'",
 +                      return error(_("binary patch does not apply to '%s'"),
                                     name);
  
                /* verify that the result matches */
                hash_sha1_file(img->buf, img->len, blob_type, sha1);
                if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
 -                      return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)",
 +                      return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
                                name, patch->new_sha1_prefix, sha1_to_hex(sha1));
        }
  
@@@ -2936,7 -2808,7 +2935,7 @@@ static int apply_fragments(struct imag
        while (frag) {
                nth++;
                if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule, nth)) {
 -                      error("patch failed: %s:%ld", name, frag->oldpos);
 +                      error(_("patch failed: %s:%ld"), name, frag->oldpos);
                        if (!apply_with_reject)
                                return -1;
                        frag->rejected = 1;
        return 0;
  }
  
 -static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
 +static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode)
  {
 -      if (!ce)
 -              return 0;
 -
 -      if (S_ISGITLINK(ce->ce_mode)) {
 +      if (S_ISGITLINK(mode)) {
                strbuf_grow(buf, 100);
 -              strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
 +              strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(sha1));
        } else {
                enum object_type type;
                unsigned long sz;
                char *result;
  
 -              result = read_sha1_file(ce->sha1, &type, &sz);
 +              result = read_sha1_file(sha1, &type, &sz);
                if (!result)
                        return -1;
                /* XXX read_sha1_file NUL-terminates */
        return 0;
  }
  
 +static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
 +{
 +      if (!ce)
 +              return 0;
 +      return read_blob_object(buf, ce->sha1, ce->ce_mode);
 +}
 +
  static struct patch *in_fn_table(const char *name)
  {
        struct string_list_item *item;
   * item->util in the filename table records the status of the path.
   * Usually it points at a patch (whose result records the contents
   * of it after applying it), but it could be PATH_WAS_DELETED for a
 - * path that a previously applied patch has already removed.
 + * path that a previously applied patch has already removed, or
 + * PATH_TO_BE_DELETED for a path that a later patch would remove.
 + *
 + * The latter is needed to deal with a case where two paths A and B
 + * are swapped by first renaming A to B and then renaming B to A;
 + * moving A to B should not be prevented due to presense of B as we
 + * will remove it in a later patch.
   */
 - #define PATH_TO_BE_DELETED ((struct patch *) -2)
 +#define PATH_TO_BE_DELETED ((struct patch *) -2)
  #define PATH_WAS_DELETED ((struct patch *) -1)
  
  static int to_be_deleted(struct patch *patch)
@@@ -3050,346 -2912,152 +3049,346 @@@ static void prepare_fn_table(struct pat
        }
  }
  
 -static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
 +static int checkout_target(struct cache_entry *ce, struct stat *st)
 +{
 +      struct checkout costate;
 +
 +      memset(&costate, 0, sizeof(costate));
 +      costate.base_dir = "";
 +      costate.refresh_cache = 1;
 +      if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))
 +              return error(_("cannot checkout %s"), ce->name);
 +      return 0;
 +}
 +
 +static struct patch *previous_patch(struct patch *patch, int *gone)
 +{
 +      struct patch *previous;
 +
 +      *gone = 0;
 +      if (patch->is_copy || patch->is_rename)
 +              return NULL; /* "git" patches do not depend on the order */
 +
 +      previous = in_fn_table(patch->old_name);
 +      if (!previous)
 +              return NULL;
 +
 +      if (to_be_deleted(previous))
 +              return NULL; /* the deletion hasn't happened yet */
 +
 +      if (was_deleted(previous))
 +              *gone = 1;
 +
 +      return previous;
 +}
 +
 +static int verify_index_match(struct cache_entry *ce, struct stat *st)
 +{
 +      if (S_ISGITLINK(ce->ce_mode)) {
 +              if (!S_ISDIR(st->st_mode))
 +                      return -1;
 +              return 0;
 +      }
 +      return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
 +}
 +
 +#define SUBMODULE_PATCH_WITHOUT_INDEX 1
 +
 +static int load_patch_target(struct strbuf *buf,
 +                           struct cache_entry *ce,
 +                           struct stat *st,
 +                           const char *name,
 +                           unsigned expected_mode)
 +{
 +      if (cached) {
 +              if (read_file_or_gitlink(ce, buf))
 +                      return error(_("read of %s failed"), name);
 +      } else if (name) {
 +              if (S_ISGITLINK(expected_mode)) {
 +                      if (ce)
 +                              return read_file_or_gitlink(ce, buf);
 +                      else
 +                              return SUBMODULE_PATCH_WITHOUT_INDEX;
 +              } else {
 +                      if (read_old_data(st, name, buf))
 +                              return error(_("read of %s failed"), name);
 +              }
 +      }
 +      return 0;
 +}
 +
 +/*
 + * We are about to apply "patch"; populate the "image" with the
 + * current version we have, from the working tree or from the index,
 + * depending on the situation e.g. --cached/--index.  If we are
 + * 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,
 +                       struct patch *patch, struct stat *st, struct cache_entry *ce)
  {
        struct strbuf buf = STRBUF_INIT;
 -      struct image image;
        size_t len;
        char *img;
 -      struct patch *tpatch;
 +      struct patch *previous;
 +      int status;
  
 -      if (!(patch->is_copy || patch->is_rename) &&
 -          (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) {
 -              if (was_deleted(tpatch)) {
 -                      return error("patch %s has been renamed/deleted",
 -                              patch->old_name);
 -              }
 -              /* We have a patched copy in memory use that */
 -              strbuf_add(&buf, tpatch->result, tpatch->resultsize);
 -      } else if (cached) {
 -              if (read_file_or_gitlink(ce, &buf))
 -                      return error("read of %s failed", patch->old_name);
 -      } else if (patch->old_name) {
 -              if (S_ISGITLINK(patch->old_mode)) {
 -                      if (ce) {
 -                              read_file_or_gitlink(ce, &buf);
 -                      } else {
 -                              /*
 -                               * There is no way to apply subproject
 -                               * patch without looking at the index.
 -                               */
 -                              patch->fragments = NULL;
 -                      }
 -              } else {
 -                      if (read_old_data(st, patch->old_name, &buf))
 -                              return error("read of %s failed", patch->old_name);
 +      previous = previous_patch(patch, &status);
 +      if (status)
 +              return error(_("path %s has been renamed/deleted"),
 +                           patch->old_name);
 +      if (previous) {
 +              /* We have a patched copy in memory; use that. */
 +              strbuf_add(&buf, previous->result, previous->resultsize);
 +      } else {
 +              status = load_patch_target(&buf, ce, st,
 +                                         patch->old_name, patch->old_mode);
 +              if (status < 0)
 +                      return status;
 +              else if (status == SUBMODULE_PATCH_WITHOUT_INDEX) {
 +                      /*
 +                       * There is no way to apply subproject
 +                       * patch without looking at the index.
 +                       * NEEDSWORK: shouldn't this be flagged
 +                       * as an error???
 +                       */
 +                      free_fragment_list(patch->fragments);
 +                      patch->fragments = NULL;
 +              } else if (status) {
 +                      return error(_("read of %s failed"), patch->old_name);
                }
        }
  
        img = strbuf_detach(&buf, &len);
 -      prepare_image(&image, img, len, !patch->is_binary);
 +      prepare_image(image, img, len, !patch->is_binary);
 +      return 0;
 +}
  
 -      if (apply_fragments(&image, patch) < 0)
 -              return -1; /* note with --reject this succeeds. */
 -      patch->result = image.buf;
 -      patch->resultsize = image.len;
 -      add_to_fn_table(patch);
 -      free(image.line_allocated);
 +static int three_way_merge(struct image *image,
 +                         char *path,
 +                         const unsigned char *base,
 +                         const unsigned char *ours,
 +                         const unsigned char *theirs)
 +{
 +      mmfile_t base_file, our_file, their_file;
 +      mmbuffer_t result = { NULL };
 +      int status;
  
 -      if (0 < patch->is_delete && patch->resultsize)
 -              return error("removal patch leaves file contents");
 +      read_mmblob(&base_file, base);
 +      read_mmblob(&our_file, ours);
 +      read_mmblob(&their_file, theirs);
 +      status = ll_merge(&result, path,
 +                        &base_file, "base",
 +                        &our_file, "ours",
 +                        &their_file, "theirs", NULL);
 +      free(base_file.ptr);
 +      free(our_file.ptr);
 +      free(their_file.ptr);
 +      if (status < 0 || !result.ptr) {
 +              free(result.ptr);
 +              return -1;
 +      }
 +      clear_image(image);
 +      image->buf = result.ptr;
 +      image->len = result.size;
 +
 +      return status;
 +}
  
 +/*
 + * When directly falling back to add/add three-way merge, we read from
 + * 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)
 +{
 +      struct strbuf buf = STRBUF_INIT;
 +      int status, pos;
 +      size_t len;
 +      char *img;
 +      struct stat st;
 +      struct cache_entry *ce;
 +      char *name = patch->new_name;
 +      unsigned mode = patch->new_mode;
 +
 +      if (!patch->is_new)
 +              die("BUG: patch to %s is not a creation", patch->old_name);
 +
 +      pos = cache_name_pos(name, strlen(name));
 +      if (pos < 0)
 +              return error(_("%s: does not exist in index"), name);
 +      ce = active_cache[pos];
 +      if (lstat(name, &st)) {
 +              if (errno != ENOENT)
 +                      return error(_("%s: %s"), name, strerror(errno));
 +              if (checkout_target(ce, &st))
 +                      return -1;
 +      }
 +      if (verify_index_match(ce, &st))
 +              return error(_("%s: does not match index"), name);
 +
 +      status = load_patch_target(&buf, ce, &st, name, mode);
 +      if (status < 0)
 +              return status;
 +      else if (status)
 +              return -1;
 +      img = strbuf_detach(&buf, &len);
 +      prepare_image(image, img, len, !patch->is_binary);
        return 0;
  }
  
 -static int check_to_create_blob(const char *new_name, int ok_if_exists)
 +static int try_threeway(struct image *image, struct patch *patch,
 +                      struct stat *st, struct cache_entry *ce)
  {
 -      struct stat nst;
 -      if (!lstat(new_name, &nst)) {
 -              if (S_ISDIR(nst.st_mode) || ok_if_exists)
 -                      return 0;
 -              /*
 -               * A leading component of new_name might be a symlink
 -               * that is going to be removed with this patch, but
 -               * still pointing at somewhere that has the path.
 -               * In such a case, path "new_name" does not exist as
 -               * far as git is concerned.
 -               */
 -              if (has_symlink_leading_path(new_name, strlen(new_name)))
 -                      return 0;
 +      unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
 +      struct strbuf buf = STRBUF_INIT;
 +      size_t len;
 +      int status;
 +      char *img;
 +      struct image tmp_image;
 +
 +      /* No point falling back to 3-way merge in these cases */
 +      if (patch->is_delete ||
 +          S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode))
 +              return -1;
  
 -              return error("%s: already exists in working directory", new_name);
 +      /* Preimage the patch was prepared for */
 +      if (patch->is_new)
 +              write_sha1_file("", 0, blob_type, pre_sha1);
 +      else if (get_sha1(patch->old_sha1_prefix, pre_sha1) ||
 +               read_blob_object(&buf, pre_sha1, patch->old_mode))
 +              return error("repository lacks the necessary blob to fall back on 3-way merge.");
 +
 +      fprintf(stderr, "Falling back to three-way merge...\n");
 +
 +      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) {
 +              clear_image(&tmp_image);
 +              return -1;
 +      }
 +      /* post_sha1[] is theirs */
 +      write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_sha1);
 +      clear_image(&tmp_image);
 +
 +      /* our_sha1[] is ours */
 +      if (patch->is_new) {
 +              if (load_current(&tmp_image, patch))
 +                      return error("cannot read the current contents of '%s'",
 +                                   patch->new_name);
 +      } else {
 +              if (load_preimage(&tmp_image, patch, st, ce))
 +                      return error("cannot read the current contents of '%s'",
 +                                   patch->old_name);
 +      }
 +      write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_sha1);
 +      clear_image(&tmp_image);
 +
 +      /* in-core three-way merge between post and our using pre as base */
 +      status = three_way_merge(image, patch->new_name,
 +                               pre_sha1, our_sha1, post_sha1);
 +      if (status < 0) {
 +              fprintf(stderr, "Failed to fall back on three-way merge...\n");
 +              return status;
 +      }
 +
 +      if (status) {
 +              patch->conflicted_threeway = 1;
 +              if (patch->is_new)
 +                      hashclr(patch->threeway_stage[0]);
 +              else
 +                      hashcpy(patch->threeway_stage[0], pre_sha1);
 +              hashcpy(patch->threeway_stage[1], our_sha1);
 +              hashcpy(patch->threeway_stage[2], post_sha1);
 +              fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name);
 +      } else {
 +              fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name);
        }
 -      else if ((errno != ENOENT) && (errno != ENOTDIR))
 -              return error("%s: %s", new_name, strerror(errno));
        return 0;
  }
  
 -static int verify_index_match(struct cache_entry *ce, struct stat *st)
 +static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
  {
 -      if (S_ISGITLINK(ce->ce_mode)) {
 -              if (!S_ISDIR(st->st_mode))
 +      struct image image;
 +
 +      if (load_preimage(&image, patch, st, ce) < 0)
 +              return -1;
 +
 +      if (patch->direct_to_threeway ||
 +          apply_fragments(&image, patch) < 0) {
 +              /* Note: with --reject, apply_fragments() returns 0 */
 +              if (!threeway || try_threeway(&image, patch, st, ce) < 0)
                        return -1;
 -              return 0;
        }
 -      return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
 +      patch->result = image.buf;
 +      patch->resultsize = image.len;
 +      add_to_fn_table(patch);
 +      free(image.line_allocated);
 +
 +      if (0 < patch->is_delete && patch->resultsize)
 +              return error(_("removal patch leaves file contents"));
 +
 +      return 0;
  }
  
 +/*
 + * If "patch" that we are looking at modifies or deletes what we have,
 + * we would want it not to lose any local modification we have, either
 + * in the working tree or in the index.
 + *
 + * This also decides if a non-git patch is a creation patch or a
 + * modification to an existing empty file.  We do not check the state
 + * of the current tree for a creation patch in this function; the caller
 + * 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)
  {
        const char *old_name = patch->old_name;
 -      struct patch *tpatch = NULL;
 -      int stat_ret = 0;
 +      struct patch *previous = NULL;
 +      int stat_ret = 0, status;
        unsigned st_mode = 0;
  
 -      /*
 -       * Make sure that we do not have local modifications from the
 -       * index when we are looking at the index.  Also make sure
 -       * we have the preimage file to be patched in the work tree,
 -       * unless --cached, which tells git to apply only in the index.
 -       */
        if (!old_name)
                return 0;
  
        assert(patch->is_new <= 0);
 +      previous = previous_patch(patch, &status);
  
 -      if (!(patch->is_copy || patch->is_rename) &&
 -          (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) {
 -              if (was_deleted(tpatch))
 -                      return error("%s: has been deleted/renamed", old_name);
 -              st_mode = tpatch->new_mode;
 +      if (status)
 +              return error(_("path %s has been renamed/deleted"), old_name);
 +      if (previous) {
 +              st_mode = previous->new_mode;
        } else if (!cached) {
                stat_ret = lstat(old_name, st);
                if (stat_ret && errno != ENOENT)
 -                      return error("%s: %s", old_name, strerror(errno));
 +                      return error(_("%s: %s"), old_name, strerror(errno));
        }
  
 -      if (to_be_deleted(tpatch))
 -              tpatch = NULL;
 -
 -      if (check_index && !tpatch) {
 +      if (check_index && !previous) {
                int pos = cache_name_pos(old_name, strlen(old_name));
                if (pos < 0) {
                        if (patch->is_new < 0)
                                goto is_new;
 -                      return error("%s: does not exist in index", old_name);
 +                      return error(_("%s: does not exist in index"), old_name);
                }
                *ce = active_cache[pos];
                if (stat_ret < 0) {
 -                      struct checkout costate;
 -                      /* checkout */
 -                      memset(&costate, 0, sizeof(costate));
 -                      costate.base_dir = "";
 -                      costate.refresh_cache = 1;
 -                      if (checkout_entry(*ce, &costate, NULL) ||
 -                          lstat(old_name, st))
 +                      if (checkout_target(*ce, st))
                                return -1;
                }
                if (!cached && verify_index_match(*ce, st))
 -                      return error("%s: does not match index", old_name);
 +                      return error(_("%s: does not match index"), old_name);
                if (cached)
                        st_mode = (*ce)->ce_mode;
        } else if (stat_ret < 0) {
                if (patch->is_new < 0)
                        goto is_new;
 -              return error("%s: %s", old_name, strerror(errno));
 +              return error(_("%s: %s"), old_name, strerror(errno));
        }
  
 -      if (!cached && !tpatch)
 +      if (!cached && !previous)
                st_mode = ce_mode_from_stat(*ce, st->st_mode);
  
        if (patch->is_new < 0)
        if (!patch->old_mode)
                patch->old_mode = st_mode;
        if ((st_mode ^ patch->old_mode) & S_IFMT)
 -              return error("%s: wrong type", old_name);
 +              return error(_("%s: wrong type"), old_name);
        if (st_mode != patch->old_mode)
 -              warning("%s has type %o, expected %o",
 +              warning(_("%s has type %o, expected %o"),
                        old_name, st_mode, patch->old_mode);
        if (!patch->new_mode && !patch->is_delete)
                patch->new_mode = st_mode;
   is_new:
        patch->is_new = 1;
        patch->is_delete = 0;
 +      free(patch->old_name);
        patch->old_name = NULL;
        return 0;
  }
  
 +
 +#define EXISTS_IN_INDEX 1
 +#define EXISTS_IN_WORKTREE 2
 +
 +static int check_to_create(const char *new_name, int ok_if_exists)
 +{
 +      struct stat nst;
 +
 +      if (check_index &&
 +          cache_name_pos(new_name, strlen(new_name)) >= 0 &&
 +          !ok_if_exists)
 +              return EXISTS_IN_INDEX;
 +      if (cached)
 +              return 0;
 +
 +      if (!lstat(new_name, &nst)) {
 +              if (S_ISDIR(nst.st_mode) || ok_if_exists)
 +                      return 0;
 +              /*
 +               * A leading component of new_name might be a symlink
 +               * that is going to be removed with this patch, but
 +               * still pointing at somewhere that has the path.
 +               * In such a case, path "new_name" does not exist as
 +               * far as git is concerned.
 +               */
 +              if (has_symlink_leading_path(new_name, strlen(new_name)))
 +                      return 0;
 +
 +              return EXISTS_IN_WORKTREE;
 +      } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
 +              return error("%s: %s", new_name, strerror(errno));
 +      }
 +      return 0;
 +}
 +
 +/*
 + * 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)
  {
        struct stat st;
                return status;
        old_name = patch->old_name;
  
 +      /*
 +       * A type-change diff is always split into a patch to delete
 +       * old, immediately followed by a patch to create new (see
 +       * diff.c::run_diff()); in such a case it is Ok that the entry
 +       * to be deleted by the previous patch is still in the working
 +       * tree and in the index.
 +       *
 +       * A patch to swap-rename between A and B would first rename A
 +       * to B and then rename B to A.  While applying the first one,
 +       * the presense of B should not stop A from getting renamed to
 +       * B; ask to_be_deleted() about the later rename.  Removal of
 +       * B and rename from A to B is handled the same way by asking
 +       * was_deleted().
 +       */
        if ((tpatch = in_fn_table(new_name)) &&
 -                      (was_deleted(tpatch) || to_be_deleted(tpatch)))
 -              /*
 -               * A type-change diff is always split into a patch to
 -               * delete old, immediately followed by a patch to
 -               * create new (see diff.c::run_diff()); in such a case
 -               * it is Ok that the entry to be deleted by the
 -               * previous patch is still in the working tree and in
 -               * the index.
 -               */
 +          (was_deleted(tpatch) || to_be_deleted(tpatch)))
                ok_if_exists = 1;
        else
                ok_if_exists = 0;
  
        if (new_name &&
            ((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) {
 -              if (check_index &&
 -                  cache_name_pos(new_name, strlen(new_name)) >= 0 &&
 -                  !ok_if_exists)
 -                      return error("%s: already exists in index", new_name);
 -              if (!cached) {
 -                      int err = check_to_create_blob(new_name, ok_if_exists);
 -                      if (err)
 -                              return err;
 +              int err = check_to_create(new_name, ok_if_exists);
 +
 +              if (err && threeway) {
 +                      patch->direct_to_threeway = 1;
 +              } else switch (err) {
 +              case 0:
 +                      break; /* happy */
 +              case EXISTS_IN_INDEX:
 +                      return error(_("%s: already exists in index"), new_name);
 +                      break;
 +              case EXISTS_IN_WORKTREE:
 +                      return error(_("%s: already exists in working directory"),
 +                                   new_name);
 +              default:
 +                      return err;
                }
 +
                if (!patch->new_mode) {
                        if (0 < patch->is_new)
                                patch->new_mode = S_IFREG | 0644;
                int same = !strcmp(old_name, new_name);
                if (!patch->new_mode)
                        patch->new_mode = patch->old_mode;
 -              if ((patch->old_mode ^ patch->new_mode) & S_IFMT)
 -                      return error("new mode (%o) of %s does not match old mode (%o)%s%s",
 -                              patch->new_mode, new_name, patch->old_mode,
 -                              same ? "" : " of ", same ? "" : old_name);
 +              if ((patch->old_mode ^ patch->new_mode) & S_IFMT) {
 +                      if (same)
 +                              return error(_("new mode (%o) of %s does not "
 +                                             "match old mode (%o)"),
 +                                      patch->new_mode, new_name,
 +                                      patch->old_mode);
 +                      else
 +                              return error(_("new mode (%o) of %s does not "
 +                                             "match old mode (%o) of %s"),
 +                                      patch->new_mode, new_name,
 +                                      patch->old_mode, old_name);
 +              }
        }
  
        if (apply_data(patch, &st, ce) < 0)
 -              return error("%s: patch does not apply", name);
 +              return error(_("%s: patch does not apply"), name);
        patch->rejected = 0;
        return 0;
  }
@@@ -3549,7 -3155,7 +3548,7 @@@ static int check_patch_list(struct patc
        while (patch) {
                if (apply_verbosely)
                        say_patch_name(stderr,
 -                                     "Checking patch ", patch, "...\n");
 +                                     _("Checking patch %s..."), patch);
                err |= check_patch(patch);
                patch = patch->next;
        }
@@@ -3589,7 -3195,7 +3588,7 @@@ static void build_fake_ancestor(struct 
                name = patch->old_name ? patch->old_name : patch->new_name;
                if (0 < patch->is_new)
                        continue;
 -              else if (get_sha1(patch->old_sha1_prefix, sha1))
 +              else if (get_sha1_blob(patch->old_sha1_prefix, sha1))
                        /* git diff has no index line for mode/type changes */
                        if (!patch->lines_added && !patch->lines_deleted) {
                                if (get_current_sha1(patch->old_name, sha1))
  
                ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0);
                if (!ce)
 -                      die("make_cache_entry failed for path '%s'", name);
 +                      die(_("make_cache_entry failed for path '%s'"), name);
                if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))
                        die ("Could not add %s to temporary index", name);
        }
@@@ -3627,7 -3233,7 +3626,7 @@@ static void stat_patch_list(struct patc
                show_stats(patch);
        }
  
 -      printf(" %d files changed, %d insertions(+), %d deletions(-)\n", files, adds, dels);
 +      print_stat_summary(stdout, files, adds, dels);
  }
  
  static void numstat_patch_list(struct patch *patch)
@@@ -3747,7 -3353,7 +3746,7 @@@ static void remove_file(struct patch *p
  {
        if (update_index) {
                if (remove_file_from_cache(patch->old_name) < 0)
 -                      die("unable to remove %s from index", patch->old_name);
 +                      die(_("unable to remove %s from index"), patch->old_name);
        }
        if (!cached) {
                if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
@@@ -3769,25 -3375,24 +3768,25 @@@ static void add_index_file(const char *
        ce = xcalloc(1, ce_size);
        memcpy(ce->name, path, namelen);
        ce->ce_mode = create_ce_mode(mode);
 -      ce->ce_flags = namelen;
 +      ce->ce_flags = create_ce_flags(0);
 +      ce->ce_namelen = namelen;
        if (S_ISGITLINK(mode)) {
                const char *s = buf;
  
                if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1))
 -                      die("corrupt patch for subproject %s", path);
 +                      die(_("corrupt patch for subproject %s"), path);
        } else {
                if (!cached) {
                        if (lstat(path, &st) < 0)
 -                              die_errno("unable to stat newly created file '%s'",
 +                              die_errno(_("unable to stat newly created file '%s'"),
                                          path);
                        fill_stat_cache_info(ce, &st);
                }
                if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
 -                      die("unable to create backing store for newly created file %s", path);
 +                      die(_("unable to create backing store for newly created file %s"), path);
        }
        if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
 -              die("unable to add cache entry for %s", path);
 +              die(_("unable to add cache entry for %s"), path);
  }
  
  static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
        strbuf_release(&nbuf);
  
        if (close(fd) < 0)
 -              die_errno("closing file '%s'", path);
 +              die_errno(_("closing file '%s'"), path);
        return 0;
  }
  
@@@ -3869,34 -3474,7 +3868,34 @@@ static void create_one_file(char *path
                        ++nr;
                }
        }
 -      die_errno("unable to write file '%s' mode %o", path, mode);
 +      die_errno(_("unable to write file '%s' mode %o"), path, mode);
 +}
 +
 +static void add_conflicted_stages_file(struct patch *patch)
 +{
 +      int stage, namelen;
 +      unsigned ce_size, mode;
 +      struct cache_entry *ce;
 +
 +      if (!update_index)
 +              return;
 +      namelen = strlen(patch->new_name);
 +      ce_size = cache_entry_size(namelen);
 +      mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
 +
 +      remove_file_from_cache(patch->new_name);
 +      for (stage = 1; stage < 4; stage++) {
 +              if (is_null_sha1(patch->threeway_stage[stage - 1]))
 +                      continue;
 +              ce = xcalloc(1, ce_size);
 +              memcpy(ce->name, patch->new_name, namelen);
 +              ce->ce_mode = create_ce_mode(mode);
 +              ce->ce_flags = create_ce_flags(stage);
 +              ce->ce_namelen = namelen;
 +              hashcpy(ce->sha1, patch->threeway_stage[stage - 1]);
 +              if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
 +                      die(_("unable to add cache entry for %s"), patch->new_name);
 +      }
  }
  
  static void create_file(struct patch *patch)
        if (!mode)
                mode = S_IFREG | 0644;
        create_one_file(path, mode, buf, size);
 -      add_index_file(path, mode, buf, size);
 +
 +      if (patch->conflicted_threeway)
 +              add_conflicted_stages_file(patch);
 +      else
 +              add_index_file(path, mode, buf, size);
  }
  
  /* phase zero is to remove, phase one is to create */
@@@ -3945,7 -3519,6 +3944,7 @@@ static int write_out_one_reject(struct 
        char namebuf[PATH_MAX];
        struct fragment *frag;
        int cnt = 0;
 +      struct strbuf sb = STRBUF_INIT;
  
        for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) {
                if (!frag->rejected)
        if (!cnt) {
                if (apply_verbosely)
                        say_patch_name(stderr,
 -                                     "Applied patch ", patch, " cleanly.\n");
 +                                     _("Applied patch %s cleanly."), patch);
                return 0;
        }
  
         * contents are marked "rejected" at the patch level.
         */
        if (!patch->new_name)
 -              die("internal error");
 +              die(_("internal error"));
  
        /* Say this even without --verbose */
 -      say_patch_name(stderr, "Applying patch ", patch, " with");
 -      fprintf(stderr, " %d rejects...\n", cnt);
 +      strbuf_addf(&sb, Q_("Applying patch %%s with %d reject...",
 +                          "Applying patch %%s with %d rejects...",
 +                          cnt),
 +                  cnt);
 +      say_patch_name(stderr, sb.buf, patch);
 +      strbuf_release(&sb);
  
        cnt = strlen(patch->new_name);
        if (ARRAY_SIZE(namebuf) <= cnt + 5) {
                cnt = ARRAY_SIZE(namebuf) - 5;
 -              warning("truncating .rej filename to %.*s.rej",
 +              warning(_("truncating .rej filename to %.*s.rej"),
                        cnt - 1, patch->new_name);
        }
        memcpy(namebuf, patch->new_name, cnt);
  
        rej = fopen(namebuf, "w");
        if (!rej)
 -              return error("cannot open %s: %s", namebuf, strerror(errno));
 +              return error(_("cannot open %s: %s"), namebuf, strerror(errno));
  
        /* Normal git tools never deal with .rej, so do not pretend
         * this is a git patch by saying --git nor give extended
             frag;
             cnt++, frag = frag->next) {
                if (!frag->rejected) {
 -                      fprintf(stderr, "Hunk #%d applied cleanly.\n", cnt);
 +                      fprintf_ln(stderr, _("Hunk #%d applied cleanly."), cnt);
                        continue;
                }
 -              fprintf(stderr, "Rejected hunk #%d.\n", cnt);
 +              fprintf_ln(stderr, _("Rejected hunk #%d."), cnt);
                fprintf(rej, "%.*s", frag->size, frag->patch);
                if (frag->patch[frag->size-1] != '\n')
                        fputc('\n', rej);
        return -1;
  }
  
 -static int write_out_results(struct patch *list, int skipped_patch)
 +static int write_out_results(struct patch *list)
  {
        int phase;
        int errs = 0;
        struct patch *l;
 -
 -      if (!list && !skipped_patch)
 -              return error("No changes");
 +      struct string_list cpath = STRING_LIST_INIT_DUP;
  
        for (phase = 0; phase < 2; phase++) {
                l = list;
                                errs = 1;
                        else {
                                write_out_one_result(l, phase);
 -                              if (phase == 1 && write_out_one_reject(l))
 -                                      errs = 1;
 +                              if (phase == 1) {
 +                                      if (write_out_one_reject(l))
 +                                              errs = 1;
 +                                      if (l->conflicted_threeway) {
 +                                              string_list_append(&cpath, l->new_name);
 +                                              errs = 1;
 +                                      }
 +                              }
                        }
                        l = l->next;
                }
        }
 +
 +      if (cpath.nr) {
 +              struct string_list_item *item;
 +
 +              sort_string_list(&cpath);
 +              for_each_string_list_item(item, &cpath)
 +                      fprintf(stderr, "U %s\n", item->string);
 +              string_list_clear(&cpath, 0);
 +
 +              rerere(0);
 +      }
 +
        return errs;
  }
  
@@@ -4106,8 -3659,15 +4105,8 @@@ static void prefix_patches(struct patc
        if (!prefix || p->is_toplevel_relative)
                return;
        for ( ; p; p = p->next) {
 -              if (p->new_name == p->old_name) {
 -                      char *prefixed = p->new_name;
 -                      prefix_one(&prefixed);
 -                      p->new_name = p->old_name = prefixed;
 -              }
 -              else {
 -                      prefix_one(&p->new_name);
 -                      prefix_one(&p->old_name);
 -              }
 +              prefix_one(&p->new_name);
 +              prefix_one(&p->old_name);
        }
  }
  
  static int apply_patch(int fd, const char *filename, int options)
  {
        size_t offset;
 -      struct strbuf buf = STRBUF_INIT;
 +      struct strbuf buf = STRBUF_INIT; /* owns the patch text */
        struct patch *list = NULL, **listp = &list;
        int skipped_patch = 0;
  
 -      /* FIXME - memory leak when using multiple patch files as inputs */
 -      memset(&fn_table, 0, sizeof(struct string_list));
        patch_input_file = filename;
        read_patch_file(&buf, fd);
        offset = 0;
                        listp = &patch->next;
                }
                else {
 -                      /* perhaps free it a bit better? */
 -                      free(patch);
 +                      free_patch(patch);
                        skipped_patch++;
                }
                offset += nr;
        }
  
 +      if (!list && !skipped_patch)
 +              die(_("unrecognized input"));
 +
        if (whitespace_error && (ws_error_action == die_on_ws_error))
                apply = 0;
  
  
        if (check_index) {
                if (read_cache() < 0)
 -                      die("unable to read index file");
 +                      die(_("unable to read index file"));
        }
  
        if ((check || apply) &&
            !apply_with_reject)
                exit(1);
  
 -      if (apply && write_out_results(list, skipped_patch))
 -              exit(1);
 +      if (apply && write_out_results(list)) {
 +              if (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 (summary)
                summary_patch_list(list);
  
 +      free_patch_list(list);
        strbuf_release(&buf);
 +      string_list_clear(&fn_table, 0);
        return 0;
  }
  
@@@ -4276,73 -3830,76 +4275,73 @@@ int cmd_apply(int argc, const char **ar
        int i;
        int errs = 0;
        int is_not_gitdir = !startup_info->have_repository;
 -      int binary;
        int force_apply = 0;
  
        const char *whitespace_option = NULL;
  
        struct option builtin_apply_options[] = {
 -              { OPTION_CALLBACK, 0, "exclude", NULL, "path",
 -                      "don't apply changes matching the given path",
 +              { OPTION_CALLBACK, 0, "exclude", NULL, N_("path"),
 +                      N_("don't apply changes matching the given path"),
                        0, option_parse_exclude },
 -              { OPTION_CALLBACK, 0, "include", NULL, "path",
 -                      "apply changes matching the given path",
 +              { OPTION_CALLBACK, 0, "include", NULL, N_("path"),
 +                      N_("apply changes matching the given path"),
                        0, option_parse_include },
 -              { OPTION_CALLBACK, 'p', NULL, NULL, "num",
 -                      "remove <num> leading slashes from traditional diff paths",
 +              { OPTION_CALLBACK, 'p', NULL, NULL, N_("num"),
 +                      N_("remove <num> leading slashes from traditional diff paths"),
                        0, option_parse_p },
                OPT_BOOLEAN(0, "no-add", &no_add,
 -                      "ignore additions made by the patch"),
 +                      N_("ignore additions made by the patch")),
                OPT_BOOLEAN(0, "stat", &diffstat,
 -                      "instead of applying the patch, output diffstat for the input"),
 -              { OPTION_BOOLEAN, 0, "allow-binary-replacement", &binary,
 -                NULL, "old option, now no-op",
 -                PARSE_OPT_HIDDEN | PARSE_OPT_NOARG },
 -              { OPTION_BOOLEAN, 0, "binary", &binary,
 -                NULL, "old option, now no-op",
 -                PARSE_OPT_HIDDEN | PARSE_OPT_NOARG },
 +                      N_("instead of applying the patch, output diffstat for the input")),
 +              OPT_NOOP_NOARG(0, "allow-binary-replacement"),
 +              OPT_NOOP_NOARG(0, "binary"),
                OPT_BOOLEAN(0, "numstat", &numstat,
 -                      "shows number of added and deleted lines in decimal notation"),
 +                      N_("shows number of added and deleted lines in decimal notation")),
                OPT_BOOLEAN(0, "summary", &summary,
 -                      "instead of applying the patch, output a summary for the input"),
 +                      N_("instead of applying the patch, output a summary for the input")),
                OPT_BOOLEAN(0, "check", &check,
 -                      "instead of applying the patch, see if the patch is applicable"),
 +                      N_("instead of applying the patch, see if the patch is applicable")),
                OPT_BOOLEAN(0, "index", &check_index,
 -                      "make sure the patch is applicable to the current index"),
 +                      N_("make sure the patch is applicable to the current index")),
                OPT_BOOLEAN(0, "cached", &cached,
 -                      "apply a patch without touching the working tree"),
 +                      N_("apply a patch without touching the working tree")),
                OPT_BOOLEAN(0, "apply", &force_apply,
 -                      "also apply the patch (use with --stat/--summary/--check)"),
 +                      N_("also apply the patch (use with --stat/--summary/--check)")),
 +              OPT_BOOL('3', "3way", &threeway,
 +                       N_( "attempt three-way merge if a patch does not apply")),
                OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor,
 -                      "build a temporary index based on embedded index information"),
 +                      N_("build a temporary index based on embedded index information")),
                { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
 -                      "paths are separated with NUL character",
 +                      N_("paths are separated with NUL character"),
                        PARSE_OPT_NOARG, option_parse_z },
                OPT_INTEGER('C', NULL, &p_context,
 -                              "ensure at least <n> lines of context match"),
 -              { OPTION_CALLBACK, 0, "whitespace", &whitespace_option, "action",
 -                      "detect new or modified lines that have whitespace errors",
 +                              N_("ensure at least <n> lines of context match")),
 +              { OPTION_CALLBACK, 0, "whitespace", &whitespace_option, N_("action"),
 +                      N_("detect new or modified lines that have whitespace errors"),
                        0, option_parse_whitespace },
                { OPTION_CALLBACK, 0, "ignore-space-change", NULL, NULL,
 -                      "ignore changes in whitespace when finding context",
 +                      N_("ignore changes in whitespace when finding context"),
                        PARSE_OPT_NOARG, option_parse_space_change },
                { OPTION_CALLBACK, 0, "ignore-whitespace", NULL, NULL,
 -                      "ignore changes in whitespace when finding context",
 +                      N_("ignore changes in whitespace when finding context"),
                        PARSE_OPT_NOARG, option_parse_space_change },
                OPT_BOOLEAN('R', "reverse", &apply_in_reverse,
 -                      "apply the patch in reverse"),
 +                      N_("apply the patch in reverse")),
                OPT_BOOLEAN(0, "unidiff-zero", &unidiff_zero,
 -                      "don't expect at least one line of context"),
 +                      N_("don't expect at least one line of context")),
                OPT_BOOLEAN(0, "reject", &apply_with_reject,
 -                      "leave the rejected hunks in corresponding *.rej files"),
 +                      N_("leave the rejected hunks in corresponding *.rej files")),
                OPT_BOOLEAN(0, "allow-overlap", &allow_overlap,
 -                      "allow overlapping hunks"),
 -              OPT__VERBOSE(&apply_verbosely, "be verbose"),
 +                      N_("allow overlapping hunks")),
 +              OPT__VERBOSE(&apply_verbosely, N_("be verbose")),
                OPT_BIT(0, "inaccurate-eof", &options,
 -                      "tolerate incorrectly detected missing new-line at the end of file",
 +                      N_("tolerate incorrectly detected missing new-line at the end of file"),
                        INACCURATE_EOF),
                OPT_BIT(0, "recount", &options,
 -                      "do not trust the line counts in the hunk headers",
 +                      N_("do not trust the line counts in the hunk headers"),
                        RECOUNT),
 -              { OPTION_CALLBACK, 0, "directory", NULL, "root",
 -                      "prepend <root> to all filenames",
 +              { OPTION_CALLBACK, 0, "directory", NULL, N_("root"),
 +                      N_("prepend <root> to all filenames"),
                        0, option_parse_directory },
                OPT_END()
        };
        argc = parse_options(argc, argv, 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");
 +              die(_("--index outside a repository"));
        if (cached) {
                if (is_not_gitdir)
 -                      die("--cached outside a repository");
 +                      die(_("--cached outside a repository"));
                check_index = 1;
        }
        for (i = 0; i < argc; i++) {
  
                fd = open(arg, O_RDONLY);
                if (fd < 0)
 -                      die_errno("can't open patch '%s'", arg);
 +                      die_errno(_("can't open patch '%s'"), arg);
                read_stdin = 0;
                set_default_whitespace_mode(whitespace_option);
                errs |= apply_patch(fd, arg, options);
                    squelch_whitespace_errors < whitespace_error) {
                        int squelched =
                                whitespace_error - squelch_whitespace_errors;
 -                      warning("squelched %d "
 -                              "whitespace error%s",
 -                              squelched,
 -                              squelched == 1 ? "" : "s");
 +                      warning(Q_("squelched %d whitespace error",
 +                                 "squelched %d whitespace errors",
 +                                 squelched),
 +                              squelched);
                }
                if (ws_error_action == die_on_ws_error)
 -                      die("%d line%s add%s whitespace errors.",
 -                          whitespace_error,
 -                          whitespace_error == 1 ? "" : "s",
 -                          whitespace_error == 1 ? "s" : "");
 +                      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("%d line%s add%s whitespace errors.",
 -                              whitespace_error,
 -                              whitespace_error == 1 ? "" : "s",
 -                              whitespace_error == 1 ? "s" : "");
 +                      warning(Q_("%d line adds whitespace errors.",
 +                                 "%d lines add whitespace errors.",
 +                                 whitespace_error),
 +                              whitespace_error);
        }
  
        if (update_index) {
                if (write_cache(newfd, active_cache, active_nr) ||
                    commit_locked_index(&lock_file))
 -                      die("Unable to write new index file");
 +                      die(_("Unable to write new index file"));
        }
  
        return !!errs;