From: Torsten Bögershausen <tboegi@xxxxxx> To compare a file in working tree with the index, convert_to_git() is used, the the result is hashed and the hash value compared with ce->sha1. Deep down would_convert_crlf_at_commit() is invoked, to check if CRLF are converted or not: When a CRLF had been in the index before, CRLF in the working tree are not converted. While in a merge, a file name in the working tree has different blobs in the index with different hash values. Forwarding ce->sha1 from ce_compare_data() into crlf_to_git() makes sure the would_convert_crlf_at_commit() looks at the appropriate blob. Signed-off-by: Torsten Bögershausen <tboegi@xxxxxx> --- cache.h | 1 + convert.c | 34 ++++++++++++++++++++++------------ convert.h | 23 +++++++++++++++++++---- read-cache.c | 4 +++- sha1_file.c | 17 +++++++++++++---- 5 files changed, 58 insertions(+), 21 deletions(-) diff --git a/cache.h b/cache.h index 15a2a10..a5136c0 100644 --- a/cache.h +++ b/cache.h @@ -605,6 +605,7 @@ extern int ie_modified(const struct index_state *, const struct cache_entry *, s #define HASH_WRITE_OBJECT 1 #define HASH_FORMAT_CHECK 2 +#define HASH_CE_HAS_SHA1 4 extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags); extern int index_path(unsigned char *sha1, const char *path, struct stat *st, unsigned flags); diff --git a/convert.c b/convert.c index f524b8d..c972d14 100644 --- a/convert.c +++ b/convert.c @@ -217,21 +217,28 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action, } } -static int has_cr_in_index(const char *path) +static int has_cr_in_index(const char *path, const unsigned char *sha1) { unsigned long sz; void *data; - int has_cr; - - data = read_blob_data_from_cache(path, &sz); + int has_cr = 0; + enum object_type type; + if (!sha1) + sha1 = get_sha1_from_cache(path); + if (!sha1) + return 0; + data = read_sha1_file(sha1, &type, &sz); if (!data) return 0; - has_cr = memchr(data, '\r', sz) != NULL; + if (type == OBJ_BLOB) + has_cr = memchr(data, '\r', sz) != NULL; + free(data); return has_cr; } -static int crlf_to_git(const char *path, const char *src, size_t len, +static int crlf_to_git(const char *path, const unsigned char *sha1, + const char *src, size_t len, struct strbuf *buf, enum crlf_action crlf_action, enum safe_crlf checksafe) { @@ -260,7 +267,7 @@ static int crlf_to_git(const char *path, const char *src, size_t len, * If the file in the index has any CR in it, do not convert. * This is the new safer autocrlf handling. */ - if (has_cr_in_index(path)) + if (has_cr_in_index(path, sha1)) return 0; } } @@ -852,8 +859,9 @@ const char *get_convert_attr_ascii(const char *path) return ""; } -int convert_to_git(const char *path, const char *src, size_t len, - struct strbuf *dst, enum safe_crlf checksafe) +int convert_to_git_ce_sha1(const char *path, const unsigned char *sha1, + const char *src, size_t len, + struct strbuf *dst, enum safe_crlf checksafe) { int ret = 0; const char *filter = NULL; @@ -874,7 +882,7 @@ int convert_to_git(const char *path, const char *src, size_t len, src = dst->buf; len = dst->len; } - ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe); + ret |= crlf_to_git(path, sha1, src, len, dst, ca.crlf_action, checksafe); if (ret && dst) { src = dst->buf; len = dst->len; @@ -882,7 +890,9 @@ int convert_to_git(const char *path, const char *src, size_t len, return ret | ident_to_git(path, src, len, dst, ca.ident); } -void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst, +void convert_to_git_filter_fd(const char *path, + const unsigned char *sha1, + int fd, struct strbuf *dst, enum safe_crlf checksafe) { struct conv_attrs ca; @@ -894,7 +904,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst, if (!apply_filter(path, NULL, 0, fd, dst, ca.drv->clean)) die("%s: clean filter '%s' failed", path, ca.drv->name); - crlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe); + crlf_to_git(path, sha1, dst->buf, dst->len, dst, ca.crlf_action, checksafe); ident_to_git(path, dst->buf, dst->len, dst, ca.ident); } diff --git a/convert.h b/convert.h index ccf436b..1634d37 100644 --- a/convert.h +++ b/convert.h @@ -37,8 +37,16 @@ extern const char *get_wt_convert_stats_ascii(const char *path); extern const char *get_convert_attr_ascii(const char *path); /* returns 1 if *dst was used */ -extern int convert_to_git(const char *path, const char *src, size_t len, - struct strbuf *dst, enum safe_crlf checksafe); +extern int convert_to_git_ce_sha1(const char *path, const unsigned char *sha1, + const char *src, size_t len, + struct strbuf *dst, enum safe_crlf checksafe); + +static inline int convert_to_git(const char *path, const char *src, size_t len, + struct strbuf *dst, enum safe_crlf checksafe) +{ + return convert_to_git_ce_sha1(path, NULL, src, len, dst, checksafe); +} + extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst); extern int renormalize_buffer(const char *path, const char *src, size_t len, @@ -47,9 +55,16 @@ static inline int would_convert_to_git(const char *path) { return convert_to_git(path, NULL, 0, NULL, 0); } +static inline int would_convert_to_git_ce_sha1(const char *path, + const unsigned char *sha1) +{ + return convert_to_git_ce_sha1(path, sha1, NULL, 0, NULL, 0); +} + /* Precondition: would_convert_to_git_filter_fd(path) == true */ -extern void convert_to_git_filter_fd(const char *path, int fd, - struct strbuf *dst, +extern void convert_to_git_filter_fd(const char *path, + const unsigned char *sha1, + int fd, struct strbuf *dst, enum safe_crlf checksafe); extern int would_convert_to_git_filter_fd(const char *path); diff --git a/read-cache.c b/read-cache.c index a3ef967..0ebc237 100644 --- a/read-cache.c +++ b/read-cache.c @@ -163,7 +163,9 @@ static int ce_compare_data(const struct cache_entry *ce, struct stat *st) if (fd >= 0) { unsigned char sha1[20]; - if (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, 0)) + unsigned flags = HASH_CE_HAS_SHA1; + memcpy(sha1, ce->sha1, sizeof(sha1)); + if (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, flags)) match = hashcmp(sha1, ce->sha1); /* index_fd() closed the file descriptor already */ } diff --git a/sha1_file.c b/sha1_file.c index d0f2aa0..dd013d5 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -3275,6 +3275,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size, { int ret, re_allocated = 0; int write_object = flags & HASH_WRITE_OBJECT; + const int valid_sha1 = flags & HASH_CE_HAS_SHA1; if (!type) type = OBJ_BLOB; @@ -3284,8 +3285,11 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size, */ if ((type == OBJ_BLOB) && path) { struct strbuf nbuf = STRBUF_INIT; - if (convert_to_git(path, buf, size, &nbuf, - write_object ? safe_crlf : SAFE_CRLF_FALSE)) { + if (convert_to_git_ce_sha1(path, + valid_sha1 ? sha1 : NULL, + buf, size, &nbuf, + write_object ? safe_crlf : SAFE_CRLF_FALSE)){ + buf = strbuf_detach(&nbuf, &size); re_allocated = 1; } @@ -3313,12 +3317,15 @@ static int index_stream_convert_blob(unsigned char *sha1, int fd, { int ret; const int write_object = flags & HASH_WRITE_OBJECT; + const int valid_sha1 = flags & HASH_CE_HAS_SHA1; struct strbuf sbuf = STRBUF_INIT; assert(path); assert(would_convert_to_git_filter_fd(path)); - convert_to_git_filter_fd(path, fd, &sbuf, + convert_to_git_filter_fd(path, + valid_sha1 ? sha1 : NULL, + fd, &sbuf, write_object ? safe_crlf : SAFE_CRLF_FALSE); if (write_object) @@ -3396,6 +3403,8 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags) { int ret; + const unsigned char *sha1_ce; + sha1_ce = flags & HASH_CE_HAS_SHA1 ? sha1 : NULL; /* * Call xsize_t() only when needed to avoid potentially unnecessary @@ -3406,7 +3415,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, else if (!S_ISREG(st->st_mode)) ret = index_pipe(sha1, fd, type, path, flags); else if (st->st_size <= big_file_threshold || type != OBJ_BLOB || - (path && would_convert_to_git(path))) + (path && would_convert_to_git_ce_sha1(path,sha1_ce))) ret = index_core(sha1, fd, xsize_t(st->st_size), type, path, flags); else -- 2.0.0.rc1.6318.g0c2c796 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html