Merge branch 'tb/apply-with-crlf'
[git/git.git] / apply.c
diff --git a/apply.c b/apply.c
index 956f56a..8666621 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -219,6 +219,7 @@ struct patch {
        unsigned int recount:1;
        unsigned int conflicted_threeway:1;
        unsigned int direct_to_threeway:1;
+       unsigned int crlf_in_old:1;
        struct fragment *fragments;
        char *result;
        size_t resultsize;
@@ -1661,6 +1662,19 @@ static void check_whitespace(struct apply_state *state,
        record_ws_error(state, result, line + 1, len - 2, state->linenr);
 }
 
+/*
+ * Check if the patch has context lines with CRLF or
+ * the patch wants to remove lines with CRLF.
+ */
+static void check_old_for_crlf(struct patch *patch, const char *line, int len)
+{
+       if (len >= 2 && line[len-1] == '\n' && line[len-2] == '\r') {
+               patch->ws_rule |= WS_CR_AT_EOL;
+               patch->crlf_in_old = 1;
+       }
+}
+
+
 /*
  * Parse a unified diff. Note that this really needs to parse each
  * fragment separately, since the only way to know the difference
@@ -1711,11 +1725,14 @@ static int parse_fragment(struct apply_state *state,
                        if (!deleted && !added)
                                leading++;
                        trailing++;
+                       check_old_for_crlf(patch, line, len);
                        if (!state->apply_in_reverse &&
                            state->ws_error_action == correct_ws_error)
                                check_whitespace(state, line, len, patch->ws_rule);
                        break;
                case '-':
+                       if (!state->apply_in_reverse)
+                               check_old_for_crlf(patch, line, len);
                        if (state->apply_in_reverse &&
                            state->ws_error_action != nowarn_ws_error)
                                check_whitespace(state, line, len, patch->ws_rule);
@@ -1724,6 +1741,8 @@ static int parse_fragment(struct apply_state *state,
                        trailing = 0;
                        break;
                case '+':
+                       if (state->apply_in_reverse)
+                               check_old_for_crlf(patch, line, len);
                        if (!state->apply_in_reverse &&
                            state->ws_error_action != nowarn_ws_error)
                                check_whitespace(state, line, len, patch->ws_rule);
@@ -2266,8 +2285,11 @@ static void show_stats(struct apply_state *state, struct patch *patch)
                add, pluses, del, minuses);
 }
 
-static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
+static int read_old_data(struct stat *st, struct patch *patch,
+                        const char *path, struct strbuf *buf)
 {
+       enum safe_crlf safe_crlf = patch->crlf_in_old ?
+               SAFE_CRLF_KEEP_CRLF : SAFE_CRLF_RENORMALIZE;
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
                if (strbuf_readlink(buf, path, st->st_size) < 0)
@@ -2276,7 +2298,15 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
        case S_IFREG:
                if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
                        return error(_("unable to open or read %s"), path);
-               convert_to_git(&the_index, path, buf->buf, buf->len, buf, 0);
+               /*
+                * "git apply" without "--index/--cached" should never look
+                * at the index; the target file may not have been added to
+                * the index yet, and we may not even be in any Git repository.
+                * Pass NULL to convert_to_git() to stress this; the function
+                * should never look at the index when explicit crlf option
+                * is given.
+                */
+               convert_to_git(NULL, path, buf->buf, buf->len, buf, safe_crlf);
                return 0;
        default:
                return -1;
@@ -3379,6 +3409,7 @@ static int load_patch_target(struct apply_state *state,
                             struct strbuf *buf,
                             const struct cache_entry *ce,
                             struct stat *st,
+                            struct patch *patch,
                             const char *name,
                             unsigned expected_mode)
 {
@@ -3394,7 +3425,7 @@ static int load_patch_target(struct apply_state *state,
                } else if (has_symlink_leading_path(name, strlen(name))) {
                        return error(_("reading from '%s' beyond a symbolic link"), name);
                } else {
-                       if (read_old_data(st, name, buf))
+                       if (read_old_data(st, patch, name, buf))
                                return error(_("failed to read %s"), name);
                }
        }
@@ -3427,7 +3458,7 @@ static int load_preimage(struct apply_state *state,
                /* We have a patched copy in memory; use that. */
                strbuf_add(&buf, previous->result, previous->resultsize);
        } else {
-               status = load_patch_target(state, &buf, ce, st,
+               status = load_patch_target(state, &buf, ce, st, patch,
                                           patch->old_name, patch->old_mode);
                if (status < 0)
                        return status;
@@ -3515,7 +3546,7 @@ static int load_current(struct apply_state *state,
        if (verify_index_match(ce, &st))
                return error(_("%s: does not match index"), name);
 
-       status = load_patch_target(state, &buf, ce, &st, name, mode);
+       status = load_patch_target(state, &buf, ce, &st, patch, name, mode);
        if (status < 0)
                return status;
        else if (status)