{"thread":{"id":"41391","subject":"[PATCH 1/3] git reset --hard gives clean working tree","startedAt":"2016-02-11T16:16:06Z","lastAt":"2017-04-12T11:48:19Z","messageCount":126,"participants":["tboegi@web.de","Junio C Hamano","Torsten Bögershausen","Duy Nguyen","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"277944","messageId":"1455207366-24892-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"Message-Id=xmqqio26nqk8.fsf@gitster.mtv.corp.google.com","subject":"[PATCH 1/3] git reset --hard gives clean working tree","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-02-11T16:16:06Z","receivedAt":"2016-02-11T16:16:06Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWe define the working tree file is clean if either:\n\n  * the result of running convert_to_git() on the working tree\n    contents matches what is in the index (because that would mean\n    doing another \"git add\" on the path is a no-op); OR\n\n  * the result of running convert_to_working_tree() on the content\n    in the index matches what is in the working tree (because that\n    would mean doing another \"git checkout -f\" on the path is a\n    no-op).\n\nAdd an extra check in ce_compare_data() in read_cache.c, and adjust\nthe test cases in t0025:\nWhen a file has CRLF in the index, and is checked out into the working tree,\nbut left unchabged, it is not normalized at the next commit.\nWhenever the file is changed in the working tree, a line is added/deleted\nor dos2unix is run, it may be normalized at the next commit,\ndepending on .gitattributes.\n\nThis patch is a result of a longer discussion on the mailing list,\nhow to fix the flaky t0025.\n\nSuggested-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\nThis is my attempt to help to fix flaky t0025:\n - steal the code from Junio\n - Add test case, change the existing if needed.\n - Spice with some optimizations\nThe commit messages may be in the state \"improvable\".\n\n read-cache.c         | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n t/t0025-crlf-auto.sh | 57 +++++++++++++++++++++++++++++++++++++++++++++------\n 2 files changed, 109 insertions(+), 6 deletions(-)\n\ndiff --git a/read-cache.c b/read-cache.c\nindex 394ce14..2948b8f 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -156,17 +156,75 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)\n \t\tce_mark_uptodate(ce);\n }\n \n+/*\n+ * Compare the data in buf with the data in the file pointed by fd and\n+ * return 0 if they are identical, and non-zero if they differ.\n+ */\n+static int compare_with_fd(const char *input, ssize_t len, int fd)\n+{\n+\tfor (;;) {\n+\t\tchar buf[1024 * 16];\n+\t\tssize_t chunk_len, read_len;\n+\n+\t\tchunk_len = sizeof(buf) < len ? sizeof(buf) : len;\n+\t\tread_len = xread(fd, buf, chunk_len ? chunk_len : 1);\n+\n+\t\tif (!read_len)\n+\t\t\t/* EOF on the working tree file */\n+\t\t\treturn !len ? 0 : -1;\n+\n+\t\tif (!len)\n+\t\t\t/* we expected there is nothing left */\n+\t\t\treturn -1;\n+\n+\t\tif (memcmp(buf, input, read_len))\n+\t\t\treturn -1;\n+\t\tinput += read_len;\n+\t\tlen -= read_len;\n+\t}\n+}\n+\n static int ce_compare_data(const struct cache_entry *ce, struct stat *st)\n {\n \tint match = -1;\n \tint fd = open(ce->name, O_RDONLY);\n \n+\t/*\n+\t * Would another \"git add\" on the path change what is in the\n+\t * index for the path?\n+\t */\n \tif (fd >= 0) {\n \t\tunsigned char sha1[20];\n \t\tif (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, 0))\n \t\t\tmatch = hashcmp(sha1, ce->sha1);\n \t\t/* index_fd() closed the file descriptor already */\n \t}\n+\tif (!match)\n+\t\treturn match;\n+\n+\t/*\n+\t * Would another \"git checkout -f\" out of the index change\n+\t * what is in the working tree file?\n+\t */\n+\tfd = open(ce->name, O_RDONLY);\n+\tif (fd >= 0) {\n+\t\tenum object_type type;\n+\t\tunsigned long size;\n+\t\tvoid *data = read_sha1_file(ce->sha1, &type, &size);\n+\n+\t\tif (type == OBJ_BLOB) {\n+\t\t\tstruct strbuf worktree = STRBUF_INIT;\n+\t\t\tif (convert_to_working_tree(ce->name, data, size,\n+\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&worktree)) {\n+\t\t\t\tfree(data);\n+\t\t\t\tdata = strbuf_detach(&worktree, &size);\n+\t\t\t}\n+\t\t\tif (!compare_with_fd(data, size, fd))\n+\t\t\t\tmatch = 0;\n+\t\t}\n+\t\tfree(data);\n+\t\tclose(fd);\n+\t}\n \treturn match;\n }\n \ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex c164b46..4a7e5c0 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -14,6 +14,8 @@ test_expect_success setup '\n \n \tfor w in Hello world how are you; do echo $w; done >LFonly &&\n \tfor w in I am very very fine thank you; do echo ${w}Q; done | q_to_cr >CRLFonly &&\n+\tcp CRLFonly CRLFonly1 &&\n+\tcp CRLFonly CRLFonly2 &&\n \tfor w in Oh here is a QNUL byte how alarming; do echo ${w}; done | q_to_nul >LFwithNUL &&\n \tgit add . &&\n \n@@ -23,6 +25,28 @@ test_expect_success setup '\n \tCRLFonly=$(git rev-parse HEAD:CRLFonly) &&\n \tLFwithNUL=$(git rev-parse HEAD:LFwithNUL) &&\n \n+\tcp CRLFonly CRLFonly.orig &&\n+\tfor w in I am very very fine thank YOU; do echo ${w}Q; done | q_to_cr >CRLFonly.changed &&\n+\tcat >expnorm  <<-EOF &&\n+\t\tMIQ\n+\t\tMamQ\n+\t\tMveryQ\n+\t\tMveryQ\n+\t\tMfineQ\n+\t\tMthankQ\n+\t\tMyouQ\n+\t\tPI\n+\t\tPam\n+\t\tPvery\n+\t\tPvery\n+\t\tPfine\n+\t\tPthank\n+\t\tPYOU\n+\tEOF\n+\tcat >expunor  <<-EOF &&\n+\t\tMyouQ\n+\t\tPYOUQ\n+\tEOF\n \techo happy.\n '\n \n@@ -39,7 +63,7 @@ test_expect_success 'default settings cause no changes' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n+test_expect_success 'crlf=true causes an unchanged CRLF file not to be normalized' '\n \n \t# Backwards compatibility check\n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n@@ -49,10 +73,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n-test_expect_success 'text=true causes a CRLF file to be normalized' '\n+test_expect_success 'text=true causes an unchanged CRLF file not to be normalized' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \techo \"CRLFonly text\" > .gitattributes &&\n@@ -61,7 +85,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' '\n@@ -114,7 +138,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n+test_expect_success 'text=auto, autocrlf=true  causes an unchanged CRLF file not to be normalized' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \tgit config core.autocrlf true &&\n@@ -126,7 +150,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n \tLFonlydiff=$(git diff LFonly) &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n \tLFwithNULdiff=$(git diff LFwithNUL) &&\n-\ttest -z \"$LFonlydiff\" -a -n \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n+\ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '\n@@ -152,4 +176,25 @@ test_expect_success 'eol=crlf _does_ normalize binary files' '\n \ttest -z \"$LFwithNULdiff\"\n '\n \n+test_expect_success 'crlf=true causes a changed CRLF file to be normalized' '\n+\tgit config core.autocrlf false &&\n+\techo \"CRLFonly1 crlf\" > .gitattributes &&\n+\t# Note, \"normalized\" means that git will normalize it if added\n+\tcp CRLFonly.changed CRLFonly1 &&\n+\tgit add CRLFonly1 &&\n+\tgit diff --cached CRLFonly1 |\n+\ttr \"\\015\" Q | sed -ne \"/^[+-][a-zA-Z]/p\" | tr \"+-\" PM >actual1 &&\n+\ttest_cmp expnorm actual1\n+'\n+\n+test_expect_success 'autocrlf=true causes a changed CRLF file not to be normalized' '\n+\tgit config core.autocrlf true &&\n+\techo > .gitattributes &&\n+\t# Note, \"normalized\" means that git will normalize it if added\n+\tcp CRLFonly.changed CRLFonly2 &&\n+\tgit add CRLFonly2 &&\n+\tgit diff --cached CRLFonly2 |\n+\ttr \"\\015\" Q  | sed -ne \"/^[+-][a-zA-Z]/p\" |\ttr \"+-\" PM >actual2 &&\n+\ttest_cmp expunor actual2\n+'\n test_done\n-- \n2.7.0.303.g2c4f448.dirty\n"},{"id":"277945","messageId":"1455207369-24931-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"Message-Id=xmqqio26nqk8.fsf@gitster.mtv.corp.google.com","subject":"[PATCH 2/3] Factor out convert_cmp_checkout() into convert.c","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-02-11T16:16:09Z","receivedAt":"2016-02-11T16:16:09Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nFactor out the code  from read_cache.c retrieveing the blob, converting to\nworktree format and comparing with the file on disc into convert.c.\n\nMove static compare_with_fd() from read_cache.c to convert.c as well.\n\nAdd a shortcut in convert_cmp_checkout(): When no converting attributes are\nset, no filters defined and core.autocrlf is false, skip the additional compare.\n\nTo avoid that attributes needs to be searched on the file system twice, change\nconvert_to_working_tree_internal() to take an additional parameter conv_attrs*.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n cache.h      |  2 ++\n convert.c    | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++---------\n read-cache.c | 21 +--------------\n 3 files changed, 78 insertions(+), 32 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 22ef4f1..a0dfa5e 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -568,6 +568,8 @@ extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b\n extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);\n extern int index_name_is_other(const struct index_state *, const char *, int);\n extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);\n+extern int convert_cmp_checkout(const char *);\n+\n \n /* do stat comparison even if CE_VALID is true */\n #define CE_MATCH_IGNORE_VALID\t\t01\ndiff --git a/convert.c b/convert.c\nindex 18af685..9cbc62c 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -217,6 +217,34 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \t}\n }\n \n+/*\n+ * Compare the data in buf with the data in the file pointed by fd and\n+ * return 0 if they are identical, and non-zero if they differ.\n+ */\n+static int compare_with_fd(const char *input, unsigned long len, int fd)\n+{\n+\tfor (;;) {\n+\t\tchar buf[1024 * 16];\n+\t\tssize_t chunk_len, read_len;\n+\n+\t\tchunk_len = sizeof(buf) < len ? sizeof(buf) : len;\n+\t\tread_len = xread(fd, buf, chunk_len ? chunk_len : 1);\n+\n+\t\tif (!read_len)\n+\t\t\t/* EOF on the working tree file */\n+\t\t\treturn !len ? 0 : -1;\n+\n+\t\tif (!len)\n+\t\t\t/* we expected there is nothing left */\n+\t\t\treturn -1;\n+\n+\t\tif (memcmp(buf, input, read_len))\n+\t\t\treturn -1;\n+\t\tinput += read_len;\n+\t\tlen -= read_len;\n+\t}\n+}\n+\n static int has_cr_in_index(const char *path)\n {\n \tunsigned long sz;\n@@ -807,6 +835,37 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tca->crlf_action = CRLF_AUTO_INPUT;\n }\n \n+int convert_cmp_checkout(const char *path)\n+{\n+\tstruct conv_attrs ca;\n+\tint match = -1; /* no match */\n+\tint fd;\n+\tconvert_attrs(&ca, path);\n+\tif (ca.crlf_action == CRLF_BINARY && !ca.drv && !ca.ident)\n+\t  return -1; /* No eol conversion, no ident, no filter */\n+\n+\tfd = open(path, O_RDONLY);\n+\tif (fd >= 0) {\n+\t\tunsigned long sz;\n+\t\tvoid *data;\n+\t\tdata = read_blob_data_from_cache(path, &sz);\n+\t\tif (!data)\n+\t\t\tmatch = -1;\n+\t\telse {\n+\t\t\tstruct strbuf worktree = STRBUF_INIT;\n+\t\t\tif (convert_to_working_tree(path, data, sz, &worktree)) {\n+\t\t\t\tfree(data);\n+\t\t\t\tdata = strbuf_detach(&worktree, &sz);\n+\t\t\t}\n+\t\t\tif (!compare_with_fd(data, sz, fd))\n+\t\t\t\tmatch = 0;\n+\t\t}\n+\t\tfree(data);\n+\t\tclose(fd);\n+\t}\n+\treturn match;\n+}\n+\n int would_convert_to_git_filter_fd(const char *path)\n {\n \tstruct conv_attrs ca;\n@@ -898,22 +957,21 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n \tident_to_git(path, dst->buf, dst->len, dst, ca.ident);\n }\n \n-static int convert_to_working_tree_internal(const char *path, const char *src,\n+static int convert_to_working_tree_internal(const char *path,\n+\t\t\t\t\t    struct conv_attrs *ca,\n+\t\t\t\t\t    const char *src,\n \t\t\t\t\t    size_t len, struct strbuf *dst,\n \t\t\t\t\t    int normalizing)\n {\n \tint ret = 0, ret_filter = 0;\n \tconst char *filter = NULL;\n \tint required = 0;\n-\tstruct conv_attrs ca;\n-\n-\tconvert_attrs(&ca, path);\n-\tif (ca.drv) {\n-\t\tfilter = ca.drv->smudge;\n-\t\trequired = ca.drv->required;\n+\tif (ca->drv) {\n+\t\tfilter = ca->drv->smudge;\n+\t\trequired = ca->drv->required;\n \t}\n \n-\tret |= ident_to_worktree(path, src, len, dst, ca.ident);\n+\tret |= ident_to_worktree(path, src, len, dst, ca->ident);\n \tif (ret) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n@@ -923,7 +981,7 @@ static int convert_to_working_tree_internal(const char *path, const char *src,\n \t * is a smudge filter.  The filter might expect CRLFs.\n \t */\n \tif (filter || !normalizing) {\n-\t\tret |= crlf_to_worktree(path, src, len, dst, ca.crlf_action);\n+\t\tret |= crlf_to_worktree(path, src, len, dst, ca->crlf_action);\n \t\tif (ret) {\n \t\t\tsrc = dst->buf;\n \t\t\tlen = dst->len;\n@@ -932,19 +990,24 @@ static int convert_to_working_tree_internal(const char *path, const char *src,\n \n \tret_filter = apply_filter(path, src, len, -1, dst, filter);\n \tif (!ret_filter && required)\n-\t\tdie(\"%s: smudge filter %s failed\", path, ca.drv->name);\n+\t\tdie(\"%s: smudge filter %s failed\", path, ca->drv->name);\n \n \treturn ret | ret_filter;\n }\n \n int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)\n {\n-\treturn convert_to_working_tree_internal(path, src, len, dst, 0);\n+\tstruct conv_attrs ca;\n+\tconvert_attrs(&ca, path);\n+\treturn convert_to_working_tree_internal(path, &ca, src, len, dst, 0);\n }\n \n int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst)\n {\n-\tint ret = convert_to_working_tree_internal(path, src, len, dst, 1);\n+\tstruct conv_attrs ca;\n+\tint ret;\n+\tconvert_attrs(&ca, path);\n+\tret = convert_to_working_tree_internal(path, &ca, src, len, dst, 1);\n \tif (ret) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\ndiff --git a/read-cache.c b/read-cache.c\nindex 2948b8f..35481b0 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -206,26 +206,7 @@ static int ce_compare_data(const struct cache_entry *ce, struct stat *st)\n \t * Would another \"git checkout -f\" out of the index change\n \t * what is in the working tree file?\n \t */\n-\tfd = open(ce->name, O_RDONLY);\n-\tif (fd >= 0) {\n-\t\tenum object_type type;\n-\t\tunsigned long size;\n-\t\tvoid *data = read_sha1_file(ce->sha1, &type, &size);\n-\n-\t\tif (type == OBJ_BLOB) {\n-\t\t\tstruct strbuf worktree = STRBUF_INIT;\n-\t\t\tif (convert_to_working_tree(ce->name, data, size,\n-\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t&worktree)) {\n-\t\t\t\tfree(data);\n-\t\t\t\tdata = strbuf_detach(&worktree, &size);\n-\t\t\t}\n-\t\t\tif (!compare_with_fd(data, size, fd))\n-\t\t\t\tmatch = 0;\n-\t\t}\n-\t\tfree(data);\n-\t\tclose(fd);\n-\t}\n-\treturn match;\n+\treturn convert_cmp_checkout(ce->name);\n }\n \n static int ce_compare_link(const struct cache_entry *ce, size_t expected_size)\n-- \n2.7.0.303.g2c4f448.dirty\n"},{"id":"277946","messageId":"1455207373-24970-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"Message-Id=xmqqio26nqk8.fsf@gitster.mtv.corp.google.com","subject":"[PATCH 3/3] convert.c: Optimize convert_cmp_checkout() for changed file len","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-02-11T16:16:13Z","receivedAt":"2016-02-11T16:16:13Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhenever the size of data from convert_to_working_tree() is different\nfrom the length of the file in the working tree, the must be different\nand compare_with_fd() can be skipped.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c | 34 +++++++++++++++++-----------------\n 1 file changed, 17 insertions(+), 17 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex 9cbc62c..2593367 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -838,30 +838,30 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n int convert_cmp_checkout(const char *path)\n {\n \tstruct conv_attrs ca;\n-\tint match = -1; /* no match */\n-\tint fd;\n+\tsize_t sz;\n+\tvoid *data;\n+\tint match = -1; /* no match, or unknown */\n \tconvert_attrs(&ca, path);\n \tif (ca.crlf_action == CRLF_BINARY && !ca.drv && !ca.ident)\n \t  return -1; /* No eol conversion, no ident, no filter */\n \n-\tfd = open(path, O_RDONLY);\n-\tif (fd >= 0) {\n-\t\tunsigned long sz;\n-\t\tvoid *data;\n-\t\tdata = read_blob_data_from_cache(path, &sz);\n-\t\tif (!data)\n-\t\t\tmatch = -1;\n-\t\telse {\n-\t\t\tstruct strbuf worktree = STRBUF_INIT;\n-\t\t\tif (convert_to_working_tree(path, data, sz, &worktree)) {\n-\t\t\t\tfree(data);\n-\t\t\t\tdata = strbuf_detach(&worktree, &sz);\n+\tdata = read_blob_data_from_cache(path, &sz);\n+\tif (data) {\n+\t\tstruct strbuf worktree = STRBUF_INIT;\n+\t\tstruct stat st;\n+\t\tif (convert_to_working_tree(path, data, sz, &worktree)) {\n+\t\t\tfree(data);\n+\t\t\tdata = strbuf_detach(&worktree, &sz);\n+\t\t}\n+\t\tif (!lstat(path, &st) && sz == xsize_t(st.st_size)) {\n+\t\t\tint fd = open(path, O_RDONLY);\n+\t\t\tif (fd >= 0) {\n+\t\t\t\tif (!compare_with_fd(data, sz, fd))\n+\t\t\t\t\tmatch = 0;\n+\t\t\t\tclose(fd);\n \t\t\t}\n-\t\t\tif (!compare_with_fd(data, sz, fd))\n-\t\t\t\tmatch = 0;\n \t\t}\n \t\tfree(data);\n-\t\tclose(fd);\n \t}\n \treturn match;\n }\n-- \n2.7.0.303.g2c4f448.dirty\n"},{"id":"277949","messageId":"xmqqy4arw089.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1455207366-24892-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH 1/3] git reset --hard gives clean working tree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-02-11T18:49:58Z","receivedAt":"2016-02-11T18:49:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> We define the working tree file is clean if either:\n>\n>   * the result of running convert_to_git() on the working tree\n>     contents matches what is in the index (because that would mean\n>     doing another \"git add\" on the path is a no-op); OR\n>\n>   * the result of running convert_to_working_tree() on the content\n>     in the index matches what is in the working tree (because that\n>     would mean doing another \"git checkout -f\" on the path is a\n>     no-op).\n>\n> Add an extra check in ce_compare_data() in read_cache.c, and adjust\n> the test cases in t0025:\n> When a file has CRLF in the index, and is checked out into the working tree,\n> but left unchabged, it is not normalized at the next commit.\n> Whenever the file is changed in the working tree, a line is added/deleted\n> or dos2unix is run, it may be normalized at the next commit,\n> depending on .gitattributes.\n>\n> This patch is a result of a longer discussion on the mailing list,\n> how to fix the flaky t0025.\n\nCurrently, the codepaths that want to stop if it would lose\ninformation from the index and/or the working tree for the path run\nan equivalent of \"diff-files path\" to see there is any difference.\nThis indeed is overly strict for a path that has contents in the\nindex that wouldn't have been created by \"clean\" conversion (I am\nusing this word to mean anything convert_to_git() does, not limited\nto the \"clean\" filter).\n\nAnd it is sensible to allow them to proceed if the contents in the\nworking tree file for the path match what would be created by\n\"smudge\" conversion of the contents in the index.\n\nBut breaking \"diff-files\" is not the right way to do so.  Teaching\n\"Am I safe to proceed\" callers that paths that do not pass\n\"diff-files\" test may still be safe to work on is.\n\nI did not continue the approach I illustrated because I realized and\nfinally convinced myself that touching ce_compare_data() is a wrong\nsolution--it breaks \"diff-files\".\n\nImagine if you have contents in the index that wouldn't have been\nleft by a \"clean\" conversion of what is in the working tree.  You\nthen run \"git checkout -f\".  Now the contents in the working tree\nwill still not convert back to what is in the index with another\n\"clean\" conversion, but it should pass the \"Am I safe to proceed\"\ncheck, namely, it matches what convert_to_worktree() would give.\n\nBut imagine further what would happen when you add an extra blank\nline at the end of the file in the working tree (i.e. \"echo >>file\")\nand then run \"diff-files -p\".\n\nThe illustration patch I gave broke \"diff-files\" in such a way that\nbefore such an addition of an extra blank line, it would have said\n\"No changes\".  And if you run \"diff-files\" after adding that extra\nblank line, you will see whole bunch of changes, not just the extra\nblank line at the end.\n\nThis is sufficient to convince me that the approach is broken.\n\nThe stolen code from me to do the reverse conversion and comparison\nmay still be reusable, but it should not go to ce_compare_data().\nSuch a path that has contents in the index that does not match what\n\"clean\"-ing the working tree contents would give us _must_ remain\ndirty and return DATA_CHANGED to ie_modified().\n\nI think the right approach to solve this (assuming that this is\nworth solving, which I am yet not sure) would go like this:\n\n * Allocate an extra bit in options passed to ie_match_stat().  When\n   this bit is set, allow it to perform the \"Smudge the contents in\n   the index and compare it with the working tree contents\" check\n   and declare \"You can proceed, nothing will be lost by touching\n   the working tree\", but never mark the cache entry up-to-date\n   while doing so.\n\n * Pass the flag from callers that want this semantics,\n   e.g. verify_uptodate() in unpack-trees.c, but not from\n   \"diff-files\".\n\nIt probably is necessary to enable the new behaviour _only_ when a\nnew command line option explicitly asks for it, because\n\n - this is rather expensive;\n\n - this will have to be done for pretty-much all dirty paths, not\n   just the ones that the additional reverse test would declare\n   clean;\n\n - most normal people would not have such a broken data in the\n   index;\n\n - those who has such a broken data would want to \"fix\" the data in\n   the index as a tree-wide flag day correction event, after which\n   they do not want to pay the penalty of doing this reverse\n   comparison check all the time; and\n\n - requiring an explicit command line option is not a burden when\n   the user _does_ want to do such a one-time \"fix\".\n"},{"id":"280234","messageId":"56DA896A.3050201@web.de","threadId":"41391","inReplyTo":"xmqqy4arw089.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 1/3] git reset --hard gives clean working tree","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-03-05T07:23:22Z","receivedAt":"2016-03-05T07:23:22Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"\n\nOn 11.02.16 19:49, Junio C Hamano wrote:\n> tboegi@web.de writes:\n>\n>> From: Torsten Bögershausen <tboegi@web.de>\n>>\n>> We define the working tree file is clean if either:\n>>\n>>   * the result of running convert_to_git() on the working tree\n>>     contents matches what is in the index (because that would mean\n>>     doing another \"git add\" on the path is a no-op); OR\n>>\n>>   * the result of running convert_to_working_tree() on the content\n>>     in the index matches what is in the working tree (because that\n>>     would mean doing another \"git checkout -f\" on the path is a\n>>     no-op).\n>>\n>> Add an extra check in ce_compare_data() in read_cache.c, and adjust\n>> the test cases in t0025:\n>> When a file has CRLF in the index, and is checked out into the working tree,\n>> but left unchabged, it is not normalized at the next commit.\n>> Whenever the file is changed in the working tree, a line is added/deleted\n>> or dos2unix is run, it may be normalized at the next commit,\n>> depending on .gitattributes.\n>>\n>> This patch is a result of a longer discussion on the mailing list,\n>> how to fix the flaky t0025.\n> Currently, the codepaths that want to stop if it would lose\n> information from the index and/or the working tree for the path run\n> an equivalent of \"diff-files path\" to see there is any difference.\n> This indeed is overly strict for a path that has contents in the\n> index that wouldn't have been created by \"clean\" conversion (I am\n> using this word to mean anything convert_to_git() does, not limited\n> to the \"clean\" filter).\n>\n> And it is sensible to allow them to proceed if the contents in the\n> working tree file for the path match what would be created by\n> \"smudge\" conversion of the contents in the index.\n>\n> But breaking \"diff-files\" is not the right way to do so.  Teaching\n> \"Am I safe to proceed\" callers that paths that do not pass\n> \"diff-files\" test may still be safe to work on is.\n>\n> I did not continue the approach I illustrated because I realized and\n> finally convinced myself that touching ce_compare_data() is a wrong\n> solution--it breaks \"diff-files\".\n>\n> Imagine if you have contents in the index that wouldn't have been\n> left by a \"clean\" conversion of what is in the working tree.  You\n> then run \"git checkout -f\".  Now the contents in the working tree\n> will still not convert back to what is in the index with another\n> \"clean\" conversion, but it should pass the \"Am I safe to proceed\"\n> check, namely, it matches what convert_to_worktree() would give.\n>\n> But imagine further what would happen when you add an extra blank\n> line at the end of the file in the working tree (i.e. \"echo >>file\")\n> and then run \"diff-files -p\".\n>\n> The illustration patch I gave broke \"diff-files\" in such a way that\n> before such an addition of an extra blank line, it would have said\n> \"No changes\".  And if you run \"diff-files\" after adding that extra\n> blank line, you will see whole bunch of changes, not just the extra\n> blank line at the end.\n>\n> This is sufficient to convince me that the approach is broken.\n[]\nWould something like this make sense?\n(The main part is in diff.c, the rest needs some polishing)\n\ncommit e494c31fd2f0f8a638ff14d1b8ae3f3a6d56a107\nAuthor: Torsten Bögershausen <tboegi@web.de>\nDate:   Sat Mar 5 07:51:08 2016 +0100\n\n    Text files needs to be normalized before diffing\n   \n    Whenever a text file is stored with CRLF in the index, Git changes\n    CRLF into LF at the next commit.\n    (text file means the attribute \"text\" or \"crlf\" of \"eol\" is set).\n   \n    \"git diff\" reports that all lines with CRLF in the index as changed to LF.\n    After cloning a repo, the work tree is not considered clean by Git, even if\n    the user didn't change a single line.\n   \n    Avoid to report lines as changed by converting the content from the index into\n    LF before running diff.\n\ndiff --git a/convert.c b/convert.c\nindex f524b8d..af8248d 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -231,9 +231,9 @@ static int has_cr_in_index(const char *path)\n     return has_cr;\n }\n \n-static int crlf_to_git(const char *path, const char *src, size_t len,\n-               struct strbuf *buf,\n-               enum crlf_action crlf_action, enum safe_crlf checksafe)\n+static int crlf_to_git_internal(const char *path, const char *src, size_t len,\n+                struct strbuf *buf,\n+                enum crlf_action crlf_action, enum safe_crlf checksafe)\n {\n     struct text_stat stats;\n     char *dst;\n@@ -852,7 +852,17 @@ const char *get_convert_attr_ascii(const char *path)\n     return \"\";\n }\n \n-int convert_to_git(const char *path, const char *src, size_t len,\n+int convert_crlf_to_git(const char *path, const char *src, size_t len,\n+            struct strbuf *buf,\n+            enum safe_crlf checksafe)\n+{\n+    struct conv_attrs ca;\n+    convert_attrs(&ca, path);\n+    return crlf_to_git_internal(path, src, len, buf,\n+                    ca.crlf_action, checksafe);\n+\n+}\n+    int convert_to_git(const char *path, const char *src, size_t len,\n                    struct strbuf *dst, enum safe_crlf checksafe)\n {\n     int ret = 0;\n@@ -874,7 +884,7 @@ int convert_to_git(const char *path, const char *src, size_t len,\n         src = dst->buf;\n         len = dst->len;\n     }\n-    ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe);\n+    ret |= crlf_to_git_internal(path, src, len, dst, ca.crlf_action, checksafe);\n     if (ret && dst) {\n         src = dst->buf;\n         len = dst->len;\n@@ -894,7 +904,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n     if (!apply_filter(path, NULL, 0, fd, dst, ca.drv->clean))\n         die(\"%s: clean filter '%s' failed\", path, ca.drv->name);\n \n-    crlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n+    crlf_to_git_internal(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n     ident_to_git(path, dst->buf, dst->len, dst, ca.ident);\n }\n \ndiff --git a/convert.h b/convert.h\nindex ccf436b..11eff02 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -52,6 +52,9 @@ extern void convert_to_git_filter_fd(const char *path, int fd,\n                      struct strbuf *dst,\n                      enum safe_crlf checksafe);\n extern int would_convert_to_git_filter_fd(const char *path);\n+extern int convert_crlf_to_git(const char *path, const char *src, size_t len,\n+                   struct strbuf *buf,\n+                   enum safe_crlf checksafe);\n \n /*****************************************************************\n  *\ndiff --git a/diff.c b/diff.c\nindex 059123c..8710a36 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2730,6 +2730,7 @@ static int diff_populate_gitlink(struct diff_filespec *s, int size_only)\n  */\n int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)\n {\n+    struct strbuf buf = STRBUF_INIT;\n     int size_only = flags & CHECK_SIZE_ONLY;\n     int err = 0;\n     /*\n@@ -2756,7 +2757,6 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)\n \n     if (!s->sha1_valid ||\n         reuse_worktree_file(s->path, s->sha1, 0)) {\n-        struct strbuf buf = STRBUF_INIT;\n         struct stat st;\n         int fd;\n \n@@ -2826,6 +2826,12 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)\n         if (!s->data)\n             die(\"unable to read %s\", sha1_to_hex(s->sha1));\n         s->should_free = 1;\n+        if (convert_crlf_to_git(s->path, s->data, s->size,\n+                    &buf, SAFE_CRLF_FALSE)) {\n+            size_t size = 0;\n+            s->data = strbuf_detach(&buf, &size);\n+            s->size = size;\n+        }\n     }\n     return 0;\n }\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex c164b46..dd1645b 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' '\n     test -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n+test_expect_success 'crlf=true on a CRLF file git diff is empty' '\n \n     # Backwards compatibility check\n     rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n@@ -49,19 +49,18 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n     # Note, \"normalized\" means that git will normalize it if added\n     has_cr CRLFonly &&\n     CRLFonlydiff=$(git diff CRLFonly) &&\n-    test -n \"$CRLFonlydiff\"\n+    test -z \"$CRLFonlydiff\"\n '\n \n-test_expect_success 'text=true causes a CRLF file to be normalized' '\n+test_expect_success 'eol=crlf gives CRLF with no diff' '\n \n     rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n-    echo \"CRLFonly text\" > .gitattributes &&\n+    echo \"CRLFonly text eol=crlf\" > .gitattributes &&\n     git read-tree --reset -u HEAD &&\n-\n-    # Note, \"normalized\" means that git will normalize it if added\n-    has_cr CRLFonly &&\n-    CRLFonlydiff=$(git diff CRLFonly) &&\n-    test -n \"$CRLFonlydiff\"\n+    >expect &&\n+    git diff CRLFonly | tr \"\\015\" Q >actual &&\n+    test_cmp expect actual &&\n+    has_cr CRLFonly\n '\n \n test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' '\n@@ -114,7 +113,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' '\n     test -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n+test_expect_success 'text=auto, autocrlf=true git diff is empty' '\n \n     rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n     git config core.autocrlf true &&\n@@ -126,7 +125,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n     LFonlydiff=$(git diff LFonly) &&\n     CRLFonlydiff=$(git diff CRLFonly) &&\n     LFwithNULdiff=$(git diff LFwithNUL) &&\n-    test -z \"$LFonlydiff\" -a -n \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n+    test -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '\n"},{"id":"280237","messageId":"xmqqtwklwdrh.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"56DA896A.3050201@web.de","subject":"Re: [PATCH 1/3] git reset --hard gives clean working tree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-05T08:05:38Z","receivedAt":"2016-03-05T08:05:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n> On 11.02.16 19:49, Junio C Hamano wrote:\n>\n>> I did not continue the approach I illustrated because I realized and\n>> finally convinced myself that touching ce_compare_data() is a wrong\n>> solution--it breaks \"diff-files\".\n>>\n>> Imagine if you have contents in the index that wouldn't have been\n>> left by a \"clean\" conversion of what is in the working tree.  You\n>> then run \"git checkout -f\".  Now the contents in the working tree\n>> will still not convert back to what is in the index with another\n>> \"clean\" conversion, but it should pass the \"Am I safe to proceed\"\n>> check, namely, it matches what convert_to_worktree() would give.\n>>\n>> But imagine further what would happen when you add an extra blank\n>> line at the end of the file in the working tree (i.e. \"echo >>file\")\n>> and then run \"diff-files -p\".\n>>\n>> The illustration patch I gave broke \"diff-files\" in such a way that\n>> before such an addition of an extra blank line, it would have said\n>> \"No changes\".  And if you run \"diff-files\" after adding that extra\n>> blank line, you will see whole bunch of changes, not just the extra\n>> blank line at the end.\n>>\n>> This is sufficient to convince me that the approach is broken.\n> []\n> Would something like this make sense?\n> (The main part is in diff.c, the rest needs some polishing)\n>\n> commit e494c31fd2f0f8a638ff14d1b8ae3f3a6d56a107\n> Author: Torsten Bögershausen <tboegi@web.de>\n> Date:   Sat Mar 5 07:51:08 2016 +0100\n>\n>     Text files needs to be normalized before diffing\n>    \n>     Whenever a text file is stored with CRLF in the index, Git changes\n>     CRLF into LF at the next commit.\n>     (text file means the attribute \"text\" or \"crlf\" of \"eol\" is set).\n\nI do not think I can endorse this approach, as I cannot explain why\nit could possibly make sense to treat as if CRLF conversion is\nsomehow special among all the convert_to_git()/convert_to_worktree()\nconversions, which your patch does to the diff code.\n\nComparisons between contents from two tree objects and comparisons\nbetween contents from a tree object and the index must happen\nwithout conversion, and comparisons between contents from the tree\nin the HEAD commit and contents from the working tree must be done\nin line with the HEAD vs index comparison to serve as a preview of\nwhat would happen after adding the contents taken from the working\ntree to the index, which means we should compare what is in the\nindex (without conversion) and the result of running the whole\nconvert_to_git() conversion on what is in the working tree.  It\nfeels fundamentally wrong to apply only CRLF conversion without any\nother conversion, whether the direction of the conversion is from\nworktree to git or the other way around, when comparing two things.\n\nWhen the user has CRLF data in the index and the user tell the\nattribute system so that the next \"add\" would result in \"fixing\" the\nindexed lines to be terminated with LF, \"diff-files\" _should_ show\nthat correction as a change, I think.\n"},{"id":"280239","messageId":"56DA986B.6040003@web.de","threadId":"41391","inReplyTo":"xmqqtwklwdrh.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 1/3] git reset --hard gives clean working tree","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-03-05T08:27:23Z","receivedAt":"2016-03-05T08:27:23Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"\n> I do not think I can endorse this approach, as I cannot explain why\n> it could possibly make sense to treat as if CRLF conversion is\n> somehow special among all the convert_to_git()/convert_to_worktree()\n> conversions, which your patch does to the diff code.\n>\n> Comparisons between contents from two tree objects and comparisons\n> between contents from a tree object and the index must happen\n> without conversion, and comparisons between contents from the tree\n> in the HEAD commit and contents from the working tree must be done\n> in line with the HEAD vs index comparison to serve as a preview of\n> what would happen after adding the contents taken from the working\n> tree to the index, which means we should compare what is in the\n> index (without conversion) and the result of running the whole\n> convert_to_git() conversion on what is in the working tree.  It\n> feels fundamentally wrong to apply only CRLF conversion without any\n> other conversion, whether the direction of the conversion is from\n> worktree to git or the other way around, when comparing two things.\n>\n> When the user has CRLF data in the index and the user tell the\n> attribute system so that the next \"add\" would result in \"fixing\" the\n> indexed lines to be terminated with LF, \"diff-files\" _should_ show\n> that correction as a change, I think.\nFair enough.\nThere are 2 users here:\nUser 1 commits files with CRLF into the index, and later decides\nto set the \"text eol=crlf\" attribute on it, without normalizing the repo.\n\nUser 2 does a simple \"git clone\", which includes checkout.\nRunning \"git diff\" tells user 2, that his work tree is dirty.\n\nMy conclusion is, that we could suppress the normalization for text files,\n(as we do it for core.autocrlf with the new safer CRLF handling)\nmeaning that \"git diff\" and \"git status\" is clean and that files stay with CRLF\nin the index.\nDoes this make sense ?\n"},{"id":"280262","messageId":"xmqqr3fotyhu.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"56DA986B.6040003@web.de","subject":"Re: [PATCH 1/3] git reset --hard gives clean working tree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-05T21:18:21Z","receivedAt":"2016-03-05T21:18:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n>> When the user has CRLF data in the index and the user tell the\n>> attribute system so that the next \"add\" would result in \"fixing\" the\n>> indexed lines to be terminated with LF, \"diff-files\" _should_ show\n>> that correction as a change, I think.\n> Fair enough.\n> There are 2 users here:\n> User 1 commits files with CRLF into the index, and later decides\n> to set the \"text eol=crlf\" attribute on it, without normalizing the repo.\n>\n> User 2 does a simple \"git clone\", which includes checkout.\n> Running \"git diff\" tells user 2, that his work tree is dirty.\n>\n> My conclusion is, that we could suppress the normalization for text files,\n> (as we do it for core.autocrlf with the new safer CRLF handling)\n> meaning that \"git diff\" and \"git status\" is clean and that files stay with CRLF\n> in the index.\n> Does this make sense ?\n\nYour example is for these two users to have conflicting settings on\nthe line ending, but if user 1 commits files in latin-1 to a project\nwhere in-project data is expected to be UTF-8 and working tree files\ncan be in latin-1, with necessary conversion done via clean/smudge\nfilter, the user 2 would see a very similar symptom, wouldn't s/he?\n\nSo I am not sure how your example supports a hack that treats CRLF\nconversion as something special among other conversions, without\ndoing anything about clean/smudge filter.\n\nBesides, it is OK if your status and diff says your worktree is\ndirty immediately after cloning in such a broken situation, I would\nthink.  In fact, it may even be preferable to do so, in order to\nindicate that there is something unusual going on.\n"},{"id":"280317","messageId":"xmqqpov6puv7.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"xmqqr3fotyhu.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 1/3] git reset --hard gives clean working tree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-07T08:14:52Z","receivedAt":"2016-03-07T08:14:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Besides, it is OK if your status and diff says your worktree is\n> dirty immediately after cloning in such a broken situation, I would\n> think.  In fact, it may even be preferable to do so, in order to\n> indicate that there is something unusual going on.\n\nThe above needs a bit of clarifying follow-up.\n\nSome operations (e.g. \"apply --index\" and \"checkout another-branch\")\nwant to make sure that the path in the working tree \"matches\" what\nis in the index before proceeding.  The reason why they require a\nmatch is because they are going to update what is in the index and\nthen update what is in the working tree to match the result by\nchecking the updated index entry out to the working tree--if the\nworking tree and the index are different before they start their\noperation, that means you have some changes you made in the working\ntree since you checked it out of the index, and their operation will\nlose such changes.\n\nNormally, this verification is done by ce_match_stat() and friends,\nwhose correct operation relies on an earlier refresh_index(), which\nin turn makes sure that the result of running the contents in the\nworking tree through convert_to_git() matches what is in the index.\n\nWhen your convert_to_working_tree() and convert_to_git() do not\nround-trip, however, the result of convert_to_git() on the working\ntree contents would not match what is in the index.  That is\ninconvenient, and it is something you may want to relax to help such\na broken situation.  Immediately after you \"git checkout\" (or \"git\nreset --hard\"), you haven't made any changes, and you should be able\nto \"git checkout another\" to go to another branch.\n\nFor this reason, I am perfectly OK with an approach to teach the\ncallers that currently use ce_uptodate() as the only way to make\nsure that there is no modification to a given path (and refuse to\nwork on it if ce_uptodate() says the path is modified) that it is\nalso OK to clobber a path that does not pass the ce_uptodate() check\nas long as the result of running convert_to_working_tree() on the\nindexed contents matches what is in the working tree.  These callers\nare currently overly strict and you will be relaxing their overly\nstrict check to help this broken situation.\n\nPerhaps we can introduce a new function can_clobber() that has the\nsame function signature as ce_uptodate() and update the callers in\napply and unpack-trees (there may be others) to call it instead when\nthey want to see if they can clobber the working tree file that\ncorresponds to the cache entry.\n\nFor implementing the can_clobber() function, you can use something\nalong the lines of compare_with_fd() helper function I introduced in\n[1] and do something like this, perhaps.\n\nWhen I send an illustration patch and say \"totally untested\", I\nusually start from the real source file and send \"git diff\" output\nafter making changes to the source file, and I may even have at\nleast compiled the modified result.  The following however is typed\ndirectly into my mail program without touching any existing source\nfile, so it is truly untested--caveat emptor.\n\n/*\n * We are about to do some operation to the index entry, and\n * write the result out to the working tree.  Would we lose\n * some local change that exist only in the working tree by\n * doing so?  Return 1 if we can safely clobber the working\n * tree file (i.e. no changes) and return 0 if we can't (i.e.\n * there are some changes).\n */\nint can_clobber(struct cache_entry *ce)\n{\n        int fd, match = 0;\n        enum object_type type;\n\tunsigned long size;\n        void *data;\n\n        /*\n         * Does another \"git add -f\" of the path result in the\n         * identical blob in the index?  If so, the working tree\n         * file is expendable.\n         */\n\tif (ce_uptodate(ce))\n        \treturn 1;\n\tfd = open(ce->name, O_RDONLY);\n        if (fd < 0)\n\t\treturn 0;\n\n\tdata = read_sha1_file(ce->sha1, &type, &size);\n\tif (type == OBJ_BLOB) {\n\t\tstruct strbuf worktree = STRBUF_INIT;\n\t\t/*\n                 * Does another \"git checkout -- path\"\n\t\t * recreate what we see in the working tree?\n                 * If so, the working tree file is expendable.\n                 */\n\t\tif (convert_to_working_tree(ce->name, data, size,\n\t\t\t\t\t    &worktree)) {\n\t\t\tfree(data);\n\t\t\tdata = strbuf_detach(&worktree, &size);\n\t\t}\n\t\tif (!compare_with_fd(data, size, fd))\n\t\t\tmatch = 1;\n\t}\n\tfree(data);\n\tclose(fd);\n\n        return match;\n}\n\n\n[Reference]\n\n*1* http://thread.gmane.org/gmane.comp.version-control.git/284352/focus=285341\n"},{"id":"280319","messageId":"xmqqlh5upt6q.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"xmqqpov6puv7.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 1/3] git reset --hard gives clean working tree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-07T08:51:09Z","receivedAt":"2016-03-07T08:51:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Perhaps we can introduce a new function can_clobber() that has the\n> same function signature as ce_uptodate() and update the callers in\n> apply and unpack-trees (there may be others) to call it instead when\n> they want to see if they can clobber the working tree file that\n> corresponds to the cache entry.\n\nBy the way, I do not want see ie_match_stat() modified to work like\nthe can_clobber() I outlined in the previous message, which in turn\nmeans that immediately after \"git reset --hard\" or \"git checkout\" \nwhen your convert_to_git() and convert_to_working_tree() do not\nroundtrip, you _must_ see differences in \"git diff\".\n\nThis is for (at least) two reasons.\n\n * \"git diff\" (compare between the index and the working tree) is\n   meant as a preview of how the indexed contents will be modified\n   if you did \"git add\" with what you currently have in your working\n   tree at the path.  In a \"conversions do not roundtrip\" situation,\n   your \"git add\" will be modifying the contents in the index, so we\n   should actively be showing what modification we will be making.\n\n   One way of \"fixing\" the situation without changing either the\n   working tree contents or the indexed contents is to fix your\n   convert-to-git settings to make the conversions round-trip, and\n   then you would stop seeing the changes you would make when you do\n   \"git add\".  Not showing any diff when can_clobber() is true but\n   ce_uptodate() is false would make \"git diff\" less useful when the\n   user makes this correction.\n\n * \"git add\" of a path can legitimately optimize itself by not\n   adding a path that is ce_uptodate().  Mixing ie_match_stat()\n   with can_clobber() logic would mark such a \"conversions do not\n   roundtrip\" path as ce_uptodate(), and prevent the user from\n   \"fixing\" the incorrect index entry by running \"git add\".\n"},{"id":"280321","messageId":"56DD42AE.2010200@web.de","threadId":"41391","inReplyTo":"xmqqlh5upt6q.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 1/3] git reset --hard gives clean working tree","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-03-07T08:58:22Z","receivedAt":"2016-03-07T08:58:22Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 03/07/2016 09:51 AM, Junio C Hamano wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> Perhaps we can introduce a new function can_clobber() that has the\n>> same function signature as ce_uptodate() and update the callers in\n>> apply and unpack-trees (there may be others) to call it instead when\n>> they want to see if they can clobber the working tree file that\n>> corresponds to the cache entry.\n> By the way, I do not want see ie_match_stat() modified to work like\n> the can_clobber() I outlined in the previous message, which in turn\n> means that immediately after \"git reset --hard\" or \"git checkout\"\n> when your convert_to_git() and convert_to_working_tree() do not\n> roundtrip, you _must_ see differences in \"git diff\".\n>\n> This is for (at least) two reasons.\n>\n>   * \"git diff\" (compare between the index and the working tree) is\n>     meant as a preview of how the indexed contents will be modified\n>     if you did \"git add\" with what you currently have in your working\n>     tree at the path.  In a \"conversions do not roundtrip\" situation,\n>     your \"git add\" will be modifying the contents in the index, so we\n>     should actively be showing what modification we will be making.\n>\n>     One way of \"fixing\" the situation without changing either the\n>     working tree contents or the indexed contents is to fix your\n>     convert-to-git settings to make the conversions round-trip, and\n>     then you would stop seeing the changes you would make when you do\n>     \"git add\".  Not showing any diff when can_clobber() is true but\n>     ce_uptodate() is false would make \"git diff\" less useful when the\n>     user makes this correction.\n>\n>   * \"git add\" of a path can legitimately optimize itself by not\n>     adding a path that is ce_uptodate().  Mixing ie_match_stat()\n>     with can_clobber() logic would mark such a \"conversions do not\n>     roundtrip\" path as ce_uptodate(), and prevent the user from\n>     \"fixing\" the incorrect index entry by running \"git add\".\n>\nThanks.\nOK about \"git add\" and \"git diff\".\nThe major question, at least on my side, is where to hook in \n\"can_clobber()\" ?\n"},{"id":"280338","messageId":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"56DD42AE.2010200@web.de","subject":"Re: [PATCH 1/3] git reset --hard gives clean working tree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-07T22:34:26Z","receivedAt":"2016-03-07T22:34:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n> The major question, at least on my side, is where to hook in\n> \"can_clobber()\" ?\n\nThere are different ways the existing commands ensure that they do\nnot lose local modifications.\n\n * Some (like unpack-trees code that is used by \"merge\") do\n   refresh_cache() upfront and then ask ce_uptodate() if the\n   contents in the working tree match the indexed contents.\n   unpack-trees.c::verify_uptodate_1() has a call to ce_uptodate()\n   and returns early when true (i.e. if \"git add\" would result in\n   the same index entry), but then does a double-check with\n   ie_match_stat(), which essentially asks the \"does an add result\n   in the same index entry?\" again.\n\n * Others (like apply) do not do the tree-wide refresh_cache(), but\n   asks \"does an add result in the same index entry\" by calling\n   ce_match_stat(), which is a thin wrapper to ie_match_stat(), in\n   builtin/apply.c::verify_index_match().\n\nThese places need to learn that there is a case where\nie_match_stat() says \"'git add' would change the index, i.e. working\ntree file is different\" but the working tree file can still be\nclobbered because 'checkout' would produce the same contents in the\nworking tree.\n\nBut stepping back a bit, I no longer am sure if such a loosening is\ndesirable.  Imagine that you implemented such loosening and allowed\na patch to be applied to the index (and the result checked out to\nthe working tree).  What would the result of \"diff --cached\" be\nafter doing so?  Would it contain only the change described in the\npatch you just accepted?  If that is the case, it would be OK, but\nif the change from the patch gets mixed with the \"fix incorrectly\nrecorded data in the index\" change that you would have recorded if\nyou did \"git add\" from the working tree without applying the patch,\nthen that would not be a desirable outcome, I would suspect.  You\nwould rather want to first commit the \"fix incorrectly recorded data\nin the index\" as a separate preparatory step and then want to apply\nthe patch.  So...\n"},{"id":"282049","messageId":"1459257930-17193-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v1 1/7] Make it possible to get sha1 for a path from the index","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-03-29T13:25:30Z","receivedAt":"2016-03-29T13:25:30Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nFactor out the retrival of the sha1 for a given path in\nread_blob_data_from_index() into the function get_sha1_from_index().\n\nThis will be used in the next commit, when convert.c can do the analyze\nfor \"text=auto\" without slurping the whole blob into memory at once.\n\nAdd a wrapper definition get_sha1_from_cache().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n cache.h      |  3 +++\n read-cache.c | 29 ++++++++++++++++++-----------\n 2 files changed, 21 insertions(+), 11 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex b829410..bd1210a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -379,6 +379,7 @@ extern void free_name_hash(struct index_state *istate);\n #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)\n #define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)\n #define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))\n+#define get_sha1_from_cache(path)  get_sha1_from_index (&the_index, (path))\n #endif\n \n enum object_type {\n@@ -1008,6 +1009,8 @@ static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *\n \treturn read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);\n }\n \n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path);\n+\n /*\n  * This internal function is only declared here for the benefit of\n  * lookup_replace_object().  Please do not call it directly.\ndiff --git a/read-cache.c b/read-cache.c\nindex d9fb78b..a3ef967 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -2263,13 +2263,27 @@ int index_name_is_other(const struct index_state *istate, const char *name,\n \n void *read_blob_data_from_index(struct index_state *istate, const char *path, unsigned long *size)\n {\n-\tint pos, len;\n+\tconst unsigned char *sha1;\n \tunsigned long sz;\n \tenum object_type type;\n \tvoid *data;\n \n-\tlen = strlen(path);\n-\tpos = index_name_pos(istate, path, len);\n+\tsha1 = get_sha1_from_index(istate, path);\n+\tif (!sha1)\n+\t\treturn NULL;\n+\tdata = read_sha1_file(sha1, &type, &sz);\n+\tif (!data || type != OBJ_BLOB) {\n+\t\tfree(data);\n+\t\treturn NULL;\n+\t}\n+\tif (size)\n+\t\t*size = sz;\n+\treturn data;\n+}\n+\n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path)\n+{\n+\tint pos = index_name_pos(istate, path, strlen(path));\n \tif (pos < 0) {\n \t\t/*\n \t\t * We might be in the middle of a merge, in which\n@@ -2285,14 +2299,7 @@ void *read_blob_data_from_index(struct index_state *istate, const char *path, un\n \t}\n \tif (pos < 0)\n \t\treturn NULL;\n-\tdata = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);\n-\tif (!data || type != OBJ_BLOB) {\n-\t\tfree(data);\n-\t\treturn NULL;\n-\t}\n-\tif (size)\n-\t\t*size = sz;\n-\treturn data;\n+\treturn (istate->cache[pos]->sha1);\n }\n \n void stat_validity_clear(struct stat_validity *sv)\n-- \n2.8.0.rc2.6.g3847ccb\n"},{"id":"282050","messageId":"1459257932-17233-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v1 2/7] convert.c: stream and early out","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-03-29T13:25:32Z","receivedAt":"2016-03-29T13:25:32Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen statistics are done for the autocrlf handling, the search in\nthe content can be stopped, if e.g\n- a search for binary is done, and a NUL character is found\n- a search for CRLF is done, and the first CRLF is found.\n\nSimilar when statistics for binary vs non-binary are gathered:\nWhenever a lone CR or NUL is found, the search can be aborted.\n\nWhen checking out files in \"auto\" mode, any file that has a \"lone CR\"\nor a CRLF will not be converted, so the search can be aborted early.\n\nAdd the new bit, CONVERT_STAT_BITS_ANY_CR,\nwhich is set for either lone CR or CRLF.\n\nMany binary files have a NUL very early (within the first few bytes,\nlatest within the first 1..2K).\nIt is often not necessary to load the whole content of a file or blob\ninto memory.\n\nUse a streaming handling for blobs and files in the worktree.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c | 162 ++++++++++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 106 insertions(+), 56 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex f524b8d..b6da114 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -3,6 +3,7 @@\n #include \"run-command.h\"\n #include \"quote.h\"\n #include \"sigchain.h\"\n+#include \"streaming.h\"\n \n /*\n  * convert.c - convert a file when checking it out and checking it in.\n@@ -13,10 +14,10 @@\n  * translation when the \"text\" attribute or \"auto_crlf\" option is set.\n  */\n \n-/* Stat bits: When BIN is set, the txt bits are unset */\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n+#define CONVERT_STAT_BITS_ANY_CR    0x8\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -31,30 +32,36 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned nul, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonecr, lonelf, crlf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n };\n \n-static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)\n+static void do_gather_stats(const char *buf, unsigned long size,\n+\t\t\t    struct text_stat *stats, unsigned earlyout)\n {\n \tunsigned long i;\n \n-\tmemset(stats, 0, sizeof(*stats));\n-\n+\tif (!buf || !size)\n+\t\treturn;\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n \t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n-\t\t\t} else\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\t} else {\n \t\t\t\tstats->lonecr++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+\t\t\t}\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == '\\n') {\n \t\t\tstats->lonelf++;\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_LF;\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == 127)\n@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t\t\tstats->printable++;\n \t\t\t\tbreak;\n \t\t\tcase 0:\n-\t\t\t\tstats->nul++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t\t/* fall through */\n \t\t\tdefault:\n \t\t\t\tstats->nonprintable++;\n@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t}\n \t\telse\n \t\t\tstats->printable++;\n+\t\tif (stats->stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n \t}\n \n \t/* If file ends with EOF then don't count this EOF as non-printable. */\n@@ -86,41 +95,63 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n  * The same heuristics as diff.c::mmfile_is_binary()\n  * We treat files with bare CR as binary\n  */\n-static int convert_is_binary(unsigned long size, const struct text_stat *stats)\n+static void convert_nonprintable(struct text_stat *stats)\n {\n-\tif (stats->lonecr)\n-\t\treturn 1;\n-\tif (stats->nul)\n-\t\treturn 1;\n \tif ((stats->printable >> 7) < stats->nonprintable)\n-\t\treturn 1;\n-\treturn 0;\n+\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+}\n+\n+static void gather_stats(const char *buf, unsigned long size,\n+\t\t\t struct text_stat *stats, unsigned earlyout)\n+{\n+\tmemset(stats, 0, sizeof(*stats));\n+\tdo_gather_stats(buf, size, stats, earlyout);\n+\tconvert_nonprintable(stats);\n }\n \n-static unsigned int gather_convert_stats(const char *data, unsigned long size)\n+\n+static unsigned get_convert_stats_sha1(const char *path,\n+\t\t\t\t       unsigned const char *sha1,\n+\t\t\t\t       unsigned earlyout)\n {\n+\tstruct git_istream *st;\n \tstruct text_stat stats;\n-\tint ret = 0;\n-\tif (!data || !size)\n-\t\treturn 0;\n-\tgather_stats(data, size, &stats);\n-\tif (convert_is_binary(size, &stats))\n-\t\tret |= CONVERT_STAT_BITS_BIN;\n-\tif (stats.crlf)\n-\t\tret |= CONVERT_STAT_BITS_TXT_CRLF;\n-\tif (stats.lonelf)\n-\t\tret |=  CONVERT_STAT_BITS_TXT_LF;\n+\tenum object_type type;\n+\tunsigned long sz;\n \n-\treturn ret;\n+\tif (!sha1)\n+\t\treturn 0;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tst = open_istream(sha1, &type, &sz, NULL);\n+\tif (!st) {\n+\t\treturn 0;\n+\t}\n+\tif (type != OBJ_BLOB)\n+\t\tgoto close_and_exit_i;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read_istream(st, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+close_and_exit_i:\n+\tclose_istream(st);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n }\n \n-static const char *gather_convert_stats_ascii(const char *data, unsigned long size)\n+static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned int convert_stats = gather_convert_stats(data, size);\n-\n+\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n+\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats) {\n+\tswitch (convert_stats & mask) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -132,24 +163,46 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si\n \t}\n }\n \n+static unsigned get_convert_stats_wt(const char *path)\n+{\n+\tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tint fd;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tfd = open(path, O_RDONLY);\n+\tif (fd < 0)\n+\t\treturn 0;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read(fd, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+\tclose(fd);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n+}\n+\n const char *get_cached_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret;\n-\tunsigned long sz;\n-\tvoid *data = read_blob_data_from_cache(path, &sz);\n-\tret = gather_convert_stats_ascii(data, sz);\n-\tfree(data);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(path,\n+\t\t\t\t\t       get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n const char *get_wt_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret = \"\";\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (strbuf_read_file(&sb, path, 0) >= 0)\n-\t\tret = gather_convert_stats_ascii(sb.buf, sb.len);\n-\tstrbuf_release(&sb);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_wt(path);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n static int text_eol_is_crlf(void)\n@@ -219,16 +272,11 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \n static int has_cr_in_index(const char *path)\n {\n-\tunsigned long sz;\n-\tvoid *data;\n-\tint has_cr;\n-\n-\tdata = read_blob_data_from_cache(path, &sz);\n-\tif (!data)\n-\t\treturn 0;\n-\thas_cr = memchr(data, '\\r', sz) != NULL;\n-\tfree(data);\n-\treturn has_cr;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_sha1(path,\n+\t\t\t\t\t       get_sha1_from_cache(path),\n+\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n+\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -249,10 +297,10 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \n \t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n@@ -309,11 +357,13 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n+\n \n \tif (!len || output_eol(crlf_action) != EOL_CRLF)\n \t\treturn 0;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, earlyout);\n \n \t/* No \"naked\" LF? Nothing to convert, regardless. */\n \tif (!stats.lonelf)\n@@ -327,7 +377,7 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\t\t\treturn 0;\n \t\t}\n \n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \t}\n \n-- \n2.8.0.rc2.6.g3847ccb\n"},{"id":"282051","messageId":"1459257934-17272-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v1 3/7] Allow core.autocrlf=input and core.eol=crlf","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-03-29T13:25:34Z","receivedAt":"2016-03-29T13:25:34Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nCommit  942e77 \"Add \"core.eol\" config variable\" adds a condition to\nthe config parser: core.autocrlf=input is not allowed together with\ncore.eol=crlf.\n\nThis may lead to unnecessary problems, when config files are parsed:\nA global config file sets core.autocrlf=input,\nthe repo local config file sets is own configuration: core.eol=crlf\n\nThere is no need to prevent combinations in config.c, in any case\ncore.autocrlf overrides core.eol.\nAllow all combinations of core.crlf and core.eol and document\nthat core.autocrlf overrides core.eol.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt | 6 +++---\n config.c                 | 4 ----\n 2 files changed, 3 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2cd6bdd..4a27ad4 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -337,9 +337,9 @@ core.quotePath::\n \n core.eol::\n \tSets the line ending type to use in the working directory for\n-\tfiles that have the `text` property set.  Alternatives are\n-\t'lf', 'crlf' and 'native', which uses the platform's native\n-\tline ending.  The default value is `native`.  See\n+\tfiles that have the `text` property set when core.autocrlf is false.\n+\tAlternatives are 'lf', 'crlf' and 'native', which uses the platform's\n+\tnative line ending.  The default value is `native`.  See\n \tlinkgit:gitattributes[5] for more information on end-of-line\n \tconversion.\n \ndiff --git a/config.c b/config.c\nindex 9ba40bc..a6adc8b 100644\n--- a/config.c\n+++ b/config.c\n@@ -803,8 +803,6 @@ static int git_default_core_config(const char *var, const char *value)\n \n \tif (!strcmp(var, \"core.autocrlf\")) {\n \t\tif (value && !strcasecmp(value, \"input\")) {\n-\t\t\tif (core_eol == EOL_CRLF)\n-\t\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\t\tauto_crlf = AUTO_CRLF_INPUT;\n \t\t\treturn 0;\n \t\t}\n@@ -830,8 +828,6 @@ static int git_default_core_config(const char *var, const char *value)\n \t\t\tcore_eol = EOL_NATIVE;\n \t\telse\n \t\t\tcore_eol = EOL_UNSET;\n-\t\tif (core_eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)\n-\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\treturn 0;\n \t}\n \n-- \n2.8.0.rc2.6.g3847ccb\n"},{"id":"282052","messageId":"1459257935-17311-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v1 4/7] t0027: TC for combined attributes","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-03-29T13:25:35Z","receivedAt":"2016-03-29T13:25:35Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nAdd more test cases for the not normalized files (\"NNO\").\nThe  \"text\" attribute is most important, use it as the first parameter.\n\"ident\", if set, is the second paramater followed by the eol attribute.\nThe eol attribute overrides core.autocrlf, which overrides core.eol.\n\nUse loops to test more combinations of attributes, like\n\"* text eol=crlf\" or especially \"*text=auto eol=crlf\".\n\nCurrently \"* text=auto eol=lf\" does the same as \"* text eol=lf\", as the\neol attribute overrides \"text=auto\", this will change in future.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n t/t0027-auto-crlf.sh | 321 +++++++++++++++++++++++++--------------------------\n 1 file changed, 158 insertions(+), 163 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex f33962b..55f45d3 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -52,14 +52,17 @@ create_gitattributes () {\n create_NNO_files () {\n \tfor crlf in false true input\n \tdo\n-\t\tfor attr in \"\" auto text -text lf crlf\n+\t\tfor attr in \"\" auto text -text\n \t\tdo\n-\t\t\tpfx=NNO_${crlf}_attr_${attr} &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tfor aeol in \"\" lf crlf\n+\t\t\tdo\n+\t\t\t\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tdone\n \t\tdone\n \tdone\n }\n@@ -100,16 +103,17 @@ commit_check_warn () {\n }\n \n commit_chk_wrnNNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfwarn=$3\n-\tcrlfwarn=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfwarn=$1 ; shift\n+\tcrlfwarn=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n \t#Commit files on top of existing file\n-\tcreate_gitattributes \"$attr\" &&\n+\tcreate_gitattributes \"$attr\" $aeol &&\n \tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n@@ -121,19 +125,19 @@ commit_chk_wrnNNO () {\n \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n \t'\n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF\" '\n \t\tcheck_warning \"$crlfwarn\" ${pfx}_CRLF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_mix_LF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_mix_LF\" '\n \t\tcheck_warning \"$lfmixcrlf\" ${pfx}_CRLF_mix_LF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF_mix_cr\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf LF_mix_cr\" '\n \t\tcheck_warning \"$lfmixcr\" ${pfx}_LF_mix_CR.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_nul\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_nul\" '\n \t\tcheck_warning \"$crlfnul\" ${pfx}_CRLF_nul.err\n \t'\n }\n@@ -162,6 +166,7 @@ stats_ascii () {\n \n # contruct the attr/ returned by git ls-files --eol\n # Take none (=empty), one or two args\n+# convert.c: eol=XX overrides text=auto\n attr_ascii () {\n \tcase $1,$2 in\n \t-text,*)   echo \"-text\" ;;\n@@ -169,8 +174,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text=auto eol=lf\" ;;\n-\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n+\tauto,lf)   echo \"text eol=lf\" ;;\n+\tauto,crlf) echo \"text eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -195,28 +200,29 @@ check_files_in_repo () {\n }\n \n check_in_repo_NNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfname=$3\n-\tcrlfname=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}_\n-\ttest_expect_success \"compare_files $lfname ${pfx}LF.txt\" '\n-\t\tcompare_files $lfname ${pfx}LF.txt\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfname=$1 ; shift\n+\tcrlfname=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\ttest_expect_success \"compare_files $lfname ${pfx}_LF.txt\" '\n+\t\tcompare_files $lfname ${pfx}_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfname ${pfx}CRLF.txt\" '\n-\t\tcompare_files $crlfname ${pfx}CRLF.txt\n+\ttest_expect_success \"compare_files $crlfname ${pfx}_CRLF.txt\" '\n+\t\tcompare_files $crlfname ${pfx}_CRLF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\" '\n-\t\tcompare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\n+\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\" '\n+\t\tcompare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcr ${pfx}LF_mix_CR.txt\" '\n-\t\tcompare_files $lfmixcr ${pfx}LF_mix_CR.txt\n+\ttest_expect_success \"compare_files $lfmixcr ${pfx}_LF_mix_CR.txt\" '\n+\t\tcompare_files $lfmixcr ${pfx}_LF_mix_CR.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfnul ${pfx}CRLF_nul.txt\" '\n-\t\tcompare_files $crlfnul ${pfx}CRLF_nul.txt\n+\ttest_expect_success \"compare_files $crlfnul ${pfx}_CRLF_nul.txt\" '\n+\t\tcompare_files $crlfnul ${pfx}_CRLF_nul.txt\n \t'\n }\n \n@@ -231,7 +237,7 @@ checkout_files () {\n \tlfmixcrlf=$1 ; shift\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n-\tcreate_gitattributes \"$attr\" \"$ident\" &&\n+\tcreate_gitattributes \"$attr\" $ident $aeol &&\n \tgit config core.autocrlf $crlf &&\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n@@ -244,7 +250,7 @@ checkout_files () {\n \t\tfi\n \tdone\n \n-\ttest_expect_success \"ls-files --eol attr=$attr $ident $aeol core.autocrlf=$crlf core.eol=$ceol\" '\n+\ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n \t\ttest_when_finished \"rm expect actual\" &&\n \t\tsort <<-EOF >expect &&\n \t\ti/crlf w/$(stats_ascii $crlfname) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF.txt\n@@ -385,31 +391,31 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                       attr   LF        CRLF      CRLFmixLF \t LF_mix_CR   CRLFNUL\n-commit_chk_wrnNNO false \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"\"     \"LF_CRLF\" \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-\n+#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO false \"auto\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"auto\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"auto\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n \n-commit_chk_wrnNNO false \"text\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"$WILC\"   \t \"$WICL\"\n-commit_chk_wrnNNO true  \"text\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"text\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"CRLF_LF\"\n-\n-commit_chk_wrnNNO false \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-\n-commit_chk_wrnNNO false \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO true  \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO input \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n+for crlf in true false input;\n+do\n+\tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+done\n \n-commit_chk_wrnNNO false \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO true  \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n \n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n@@ -440,24 +446,20 @@ test_expect_success 'commit -text' '\n \tcheck_files_in_repo input \"-text\" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n '\n \n-#                       attr    LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLFNUL\n-check_in_repo_NNO false \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO true  \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO input \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-\n-check_in_repo_NNO false \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-\n+for crlf in true false input;\n+do\n+\t#                 attr  aeol           LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLFNUL\n+\tcheck_in_repo_NNO \"\"    \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n # How to read the table below:\n@@ -489,89 +491,82 @@ LFNUL=LF_nul\n fi\n export CRLF_MIX_LF_CR MIX NL\n \n-checkout_files \"\"      \"\" \t \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   native   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   native   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\n+# Same handling with and without ident\n for id in \"\" ident;\n do\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t# -text overrides core.autocrlf and core.eol\n+\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n+\tfor crlf in true false input;\n+\tdo\n+\t\tfor ceol in \"\" lf crlf native;\n+\t\tdo\n+\t\t\tcheckout_files \"-text\" \"$id\" \"\"     \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"text\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"text\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tdone\n+\tdone\n+\t# text: core.autocrlf=false uses core.eol\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files \"auto\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files \"auto\"  \"$id\"  \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\n+\tfor ceol in \"\" lf crlf native;\n+\tdo\n+\t\t# text: core.autocrlf = true overrides core.eol\n+\t\tcheckout_files \"text\"  \"$id\"  \"\"    true   \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t# text: core.autocrlf = input overrides core.eol\n+\t\tcheckout_files \"text\"  \"$id\"  \"\"    input  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\"  \"\"    input  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tdone\n+\t# No text attr\n+\tfor ceol in \"\" lf crlf native;\n+\tdo\n+\t\t# core.autocrlf!=true gives LF (or mixed) at checkout\n+\t\tfor crlf in false input;\n+\t\tdo\n+\t\t\tcheckout_files \"\"    \"$id\" \"\"    \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tdone\n+\tdone\n+done\n+\n+#Handling without ident\n+for id in \"\";\n+do\n+\tfor ceol in \"\" lf crlf native;\n+\tdo\n+\t\t# core.autocrlf=true\n+\t\tcheckout_files \"\"      \"$id\" \"\"    true   \"$ceol\"   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\" \"\"    true   \"$ceol\"   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\t# text=auto + eol=XXX\n+\t\t# currently the same as text, eol=XXX\n+\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\tdone\n+done\n+\n+#Handling with ident\n+for id in ident;\n+do\n+\tfor crlf in \"\" true false input;\n+\tdo\n+\t\tfor ceol in \"\" lf crlf native;\n+\t\tdo\n+\t\t\t# ident does not react on core.autocrlf=true\n+\t\t\tcheckout_files \"\"      \"$id\" \"\"   \"$crlf\" \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\t# ident does not react on text=auto\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"\"    true   \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\t# text=auto + eol=XXX\n+\t\t\t# currently the same as text, eol=XXX\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tdone\n+\tdone\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.8.0.rc2.6.g3847ccb\n"},{"id":"282055","messageId":"1459257937-17350-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v1 5/7] CRLF: unify the \"auto\" handling","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-03-29T13:25:37Z","receivedAt":"2016-03-29T13:25:37Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nMake .gitattributes \"* text=auto eol=crlf\" to do the same as\nsetting core.autocrlf=true and \"* text=auto eol=crlf\" the same\nas core.autocrlf=input\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt        | 11 +++++-----\n Documentation/gitattributes.txt |  7 ++++---\n convert.c                       | 37 ++++++++++++++++-----------------\n t/t0025-crlf-auto.sh            |  4 ++--\n t/t0027-auto-crlf.sh            | 45 +++++++++++++++++++----------------------\n 5 files changed, 52 insertions(+), 52 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 4a27ad4..3191a42 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -389,14 +389,15 @@ file with mixed line endings would be reported by the `core.safecrlf`\n mechanism.\n \n core.autocrlf::\n-\tSetting this variable to \"true\" is almost the same as setting\n-\tthe `text` attribute to \"auto\" on all files except that text\n-\tfiles are not guaranteed to be normalized: files that contain\n+\tSetting this variable to \"true\" is the same as setting\n+\tthe attributes to \"auto eol=crlf\" on all files.\n+\tFiles are not guaranteed to be normalized: files that contain\n \t`CRLF` in the repository will not be touched.  Use this\n \tsetting if you want to have `CRLF` line endings in your\n-\tworking directory even though the repository does not have\n-\tnormalized line endings.  This variable can be set to 'input',\n+\tworking directory and he repository has\tnormalized line endings.\n+\tThis variable can be set to 'input',\n \tin which case no output conversion is performed.\n+\tNote: older versions of Git behave different.\n \n core.symlinks::\n \tIf false, symbolic links are checked out as small plain files that\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex e3b1de8..43b70b5 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n `core.eol` configuration variable for all text files.\n+Note that `core.autocrlf` overrides `core.eol`\n \n Set::\n \n@@ -187,8 +188,8 @@ regardless of their content.\n \n ------------------------\n *.txt\t\ttext\n-*.vcproj\teol=crlf\n-*.sh\t\teol=lf\n+*.vcproj\ttext eol=crlf\n+*.sh\t\ttext eol=lf\n *.jpg\t\t-text\n ------------------------\n \n@@ -198,7 +199,7 @@ normalization in Git.\n \n If you simply want to have CRLF line endings in your working directory\n regardless of the repository you are working with, you can set the\n-config variable \"core.autocrlf\" without changing any attributes.\n+config variable \"core.autocrlf\" without using any attributes.\n \n ------------------------\n [core]\ndiff --git a/convert.c b/convert.c\nindex b6da114..4ed5d89 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -229,7 +229,9 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \t\treturn EOL_LF;\n \tcase CRLF_UNDEFINED:\n \tcase CRLF_AUTO_CRLF:\n+\t\treturn EOL_CRLF;\n \tcase CRLF_AUTO_INPUT:\n+\t\treturn EOL_LF;\n \tcase CRLF_TEXT:\n \tcase CRLF_AUTO:\n \t\t/* fall through */\n@@ -302,15 +304,12 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/*\n-\t\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t\t * This is the new safer autocrlf handling.\n-\t\t\t */\n-\t\t\tif (has_cr_in_index(path))\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/*\n+\t\t * If the file in the index has any CR in it, do not convert.\n+\t\t * This is the new safer autocrlf handling.\n+\t\t */\n+\t\tif (has_cr_in_index(path))\n+\t\t\treturn 0;\n \t}\n \n \tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n@@ -370,12 +369,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\treturn 0;\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t\t/* This is the new safer autocrlf-handling */\n-\t\t\tif (stats.lonecr || stats.crlf )\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n+\t\t/* This is the new safer autocrlf-handling */\n+\t\tif (stats.lonecr || stats.crlf )\n+\t\t\treturn 0;\n \n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n@@ -836,7 +833,11 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tca->drv = git_path_check_convert(ccheck + 2);\n \t\tif (ca->crlf_action != CRLF_BINARY) {\n \t\t\tenum eol eol_attr = git_path_check_eol(ccheck + 3);\n-\t\t\tif (eol_attr == EOL_LF)\n+\t\t\tif (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_INPUT;\n+\t\t\telse if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_CRLF;\n+\t\t\telse if (eol_attr == EOL_LF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_INPUT;\n \t\t\telse if (eol_attr == EOL_CRLF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_CRLF;\n@@ -895,9 +896,9 @@ const char *get_convert_attr_ascii(const char *path)\n \tcase CRLF_AUTO:\n \t\treturn \"text=auto\";\n \tcase CRLF_AUTO_CRLF:\n-\t\treturn \"text=auto eol=crlf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=crlf\";\n \tcase CRLF_AUTO_INPUT:\n-\t\treturn \"text=auto eol=lf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=lf\";\n \t}\n \treturn \"\";\n }\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex c164b46..d0bee08 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -114,7 +114,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n+test_expect_success 'text=auto, autocrlf=true does not normalize CRLF files' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \tgit config core.autocrlf true &&\n@@ -126,7 +126,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n \tLFonlydiff=$(git diff LFonly) &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n \tLFwithNULdiff=$(git diff LFwithNUL) &&\n-\ttest -z \"$LFonlydiff\" -a -n \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n+\ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 55f45d3..86175cf 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -174,8 +174,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text eol=lf\" ;;\n-\tauto,crlf) echo \"text eol=crlf\" ;;\n+\tauto,lf)   echo \"text=auto eol=lf\" ;;\n+\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -396,10 +396,9 @@ commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n-\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input;\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n@@ -407,8 +406,8 @@ do\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n \tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n \tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n done\n@@ -453,9 +452,9 @@ do\n \tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n@@ -513,8 +512,6 @@ do\n \t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n \tcheckout_files \"text\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \tcheckout_files \"text\"  \"$id\"  \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"auto\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"auto\"  \"$id\"  \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \n \tfor ceol in \"\" lf crlf native;\n \tdo\n@@ -541,30 +538,30 @@ do\n \tfor ceol in \"\" lf crlf native;\n \tdo\n \t\t# core.autocrlf=true\n-\t\tcheckout_files \"\"      \"$id\" \"\"    true   \"$ceol\"   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files \"auto\"  \"$id\" \"\"    true   \"$ceol\"   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files \"\"      \"$id\" \"\"     true   \"$ceol\"   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\" \"\"     true   \"$ceol\"   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\"  \"\"    false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\"  \"\"    false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text=auto + eol=XXX\n-\t\t# currently the same as text, eol=XXX\n-\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \tdone\n done\n \n #Handling with ident\n for id in ident;\n do\n-\tfor crlf in \"\" true false input;\n+\tfor crlf in true false input;\n \tdo\n \t\tfor ceol in \"\" lf crlf native;\n \t\tdo\n \t\t\t# ident does not react on core.autocrlf=true\n-\t\t\tcheckout_files \"\"      \"$id\" \"\"   \"$crlf\" \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"\"      \"$id\" \"\"     \"$crlf\" \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\t# ident does not react on text=auto\n-\t\t\tcheckout_files \"auto\"  \"$id\" \"\"    true   \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"\"      true   \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\t# text=auto + eol=XXX\n-\t\t\t# currently the same as text, eol=XXX\n-\t\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \tdone\n done\n-- \n2.8.0.rc2.6.g3847ccb\n"},{"id":"282054","messageId":"1459257938-17389-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v1 6/7] correct blame for files commited with CRLF","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-03-29T13:25:38Z","receivedAt":"2016-03-29T13:25:38Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\ngit blame reports lines as not \"Not Committed Yet\" when they have\nCRLF in the index, CRLF in the worktree and e.g. core.autocrlf is true.\n\nSince commit c48053 \"new safer autocrlf handling\", files that have CRLF\nin the index are not normalized at commit when e.g. core.autocrl is set.\n\nWhenever a CLRF conversion is needed (or any filter us set), load the\nindex temporally, before calling convert_to_git()\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n builtin/blame.c               |  6 +++++-\n convert.c                     | 10 ++++++++++\n convert.h                     |  1 +\n t/t8003-blame-corner-cases.sh | 14 ++++++++++++++\n 4 files changed, 30 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex e982fb8..a219068 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2376,7 +2376,11 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,\n \t\tif (strbuf_read(&buf, 0, 0) < 0)\n \t\t\tdie_errno(\"failed to read from stdin\");\n \t}\n-\tconvert_to_git(path, buf.buf, buf.len, &buf, 0);\n+\tif (convert_needs_conversion(path)) {\n+\t\tread_cache();\n+\t\tconvert_to_git(path, buf.buf, buf.len, &buf, 0);\n+\t\tdiscard_cache();\n+\t}\n \torigin->file.ptr = buf.buf;\n \torigin->file.size = buf.len;\n \tpretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);\ndiff --git a/convert.c b/convert.c\nindex 4ed5d89..02c50da 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -903,6 +903,16 @@ const char *get_convert_attr_ascii(const char *path)\n \treturn \"\";\n }\n \n+int convert_needs_conversion(const char *path)\n+{\n+\tstruct conv_attrs ca;\n+\n+\tconvert_attrs(&ca, path);\n+\tif (ca.drv || ca.ident || ca.crlf_action != CRLF_BINARY)\n+\t\treturn 1;\n+\treturn 0;\n+}\n+\n int convert_to_git(const char *path, const char *src, size_t len,\n                    struct strbuf *dst, enum safe_crlf checksafe)\n {\ndiff --git a/convert.h b/convert.h\nindex ccf436b..ffd9c32 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -35,6 +35,7 @@ extern enum eol core_eol;\n extern const char *get_cached_convert_stats_ascii(const char *path);\n extern const char *get_wt_convert_stats_ascii(const char *path);\n extern const char *get_convert_attr_ascii(const char *path);\n+int convert_needs_conversion(const char *path);\n \n /* returns 1 if *dst was used */\n extern int convert_to_git(const char *path, const char *src, size_t len,\ndiff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh\nindex 6568429..a9b266f 100755\n--- a/t/t8003-blame-corner-cases.sh\n+++ b/t/t8003-blame-corner-cases.sh\n@@ -212,4 +212,18 @@ test_expect_success 'blame file with CRLF attributes text' '\n \tgrep \"A U Thor\" actual\n '\n \n+test_expect_success 'blame file with CRLF core.autocrlf=true' '\n+\tgit config core.autocrlf false &&\n+\tprintf \"testcase\\r\\n\" >crlfinrepo &&\n+\t>.gitattributes &&\n+\tgit add crlfinrepo &&\n+\tgit commit -m \"add crlfinrepo\" &&\n+\tgit config core.autocrlf true &&\n+\tmv crlfinrepo tmp &&\n+\tgit checkout crlfinrepo &&\n+\trm tmp &&\n+\tgit blame crlfinrepo >actual &&\n+\tgrep \"A U Thor\" actual\n+'\n+\n test_done\n-- \n2.8.0.rc2.6.g3847ccb\n"},{"id":"282053","messageId":"1459257940-17428-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v1 7/7] convert.c: more safer crlf handling with text attribute","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-03-29T13:25:40Z","receivedAt":"2016-03-29T13:25:40Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nA follow-up after a discussion how to fix the flaky execution\nof t0025, gmane/$284352.\n\nThis patch extends the work done in commit c480539:\n\"Make it work also for un-normalized repositories\". Make sure that CRLF\ncan be converted round trip, or don't convert them at all.\n\nThe old handling would treat a file as unchanged after checkout,\nas long as it is not touched in the work tree and mtime matches the value\nrecorded in the index.\nWhen the mtime is changed in the working tree, or the inode is changed,\nthe file is reported as modified.\n\nThe following sequence is now handled reproducable:\n$ git init\n$ printf \"line1\\r\\n\" >file.bat\n$ git add file.bat\n$ git commit -m \"Add file with CRLF\" file.bat\n$ echo \"*.bat text eol=crlf\" >.gitattributes\n$ git commit -m \"bat files should have CRLF\"\n$ git status\n # nothing to commit, working directory clean\n$ git push <upstream>\n$ printf \"newline\\r\\n\" >>file.bat\n$ mv file.bat file.sav\n$ git checkout file.bat\n$ git status\n #modified:   file.bat\n\nThe new handling makes sure that after running \"git reset --hard\".\n\"git status\" reports the working tree as clean regarding CRLF conversion.\nIt makes sure that the Git-internal eol conversion is\ndoing roundtrip. A user can still write an external smudge/clean filter\noutside Git, which doesn't do a roundtrip and the working directory is\nnot clean.\n\nThe functionality of has_cr_in_index() is turned into has_crlf_in_index(),\nand the function is integrated into would_convert_crlf_at_commit().\n\nCheck for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR\nis no longer used and removed, as well as \"lonecr\" in struct text_stat.\n\nRewrite check_safe_crlf() in convert.c to simulate checkin-checkout,\nto detect whether any line endings are converted.\n\nModify the lf_to_crlf_filter:\nFiles with LF are converted into CRLF, file with CRLF are not changed.\nFiles with mixed line endings are not converted, the filter fails, and Git\nfalls back to the non-streaming handling, see write_entry().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/gitattributes.txt |  10 +-\n convert.c                       | 215 ++++++++++++++++++++++++----------------\n t/t0025-crlf-auto.sh            |   8 +-\n t/t0027-auto-crlf.sh            |  38 +++----\n 4 files changed, 158 insertions(+), 113 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex 43b70b5..7929880 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'.\n `text`\n ^^^^^^\n \n-This attribute enables and controls end-of-line normalization.  When a\n+This attribute enables and controls end-of-line conversion.  When a\n text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol`\n Set::\n \n \tSetting the `text` attribute on a path enables end-of-line\n-\tnormalization and marks the path as a text file.  End-of-line\n+\tconversion and marks the path as a text file.  End-of-line\n \tconversion takes place without guessing the content type.\n+\tFiles that have been commited with CRLF before the text attribute\n+\tis set and commited are not normalized. No end-of-line conversion\n+\tis done at checkout or checkin.\n \n Unset::\n \n@@ -132,7 +135,8 @@ Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n \tend-of-line normalization.  If Git decides that the content is\n-\ttext, its line endings are normalized to LF on checkin.\n+\ttext, and the path has no CRLF in the index,\n+\tits line endings are converted to LF on checkin.\n \n Unspecified::\n \ndiff --git a/convert.c b/convert.c\nindex 02c50da..8266d87 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -17,7 +17,6 @@\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n-#define CONVERT_STAT_BITS_ANY_CR    0x8\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -32,7 +31,7 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned stat_bits, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonelf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n@@ -48,13 +47,10 @@ static void do_gather_stats(const char *buf, unsigned long size,\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n-\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n-\t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n \t\t\t} else {\n-\t\t\t\tstats->lonecr++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t}\n \t\t\tcontinue;\n@@ -136,7 +132,7 @@ static unsigned get_convert_stats_sha1(const char *path,\n \t\tif (!readlen)\n \t\t\tbreak;\n \t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n-\t\tif (stats.stat_bits & earlyout)\n+\t\tif ((stats.stat_bits & earlyout) == earlyout)\n \t\t\tbreak; /* We found what we have been searching for */\n \t}\n close_and_exit_i:\n@@ -147,11 +143,9 @@ close_and_exit_i:\n \n static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n-\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats & mask) {\n+\tswitch (convert_stats) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -163,7 +157,17 @@ static const char *convert_stats_ascii(unsigned convert_stats)\n \t}\n }\n \n-static unsigned get_convert_stats_wt(const char *path)\n+const char *get_cached_convert_stats_ascii(const char *path)\n+{\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(path,\n+\t\t\t\t\t       get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n+}\n+\n+const char *get_wt_convert_stats_ascii(const char *path)\n {\n \tstruct text_stat stats;\n \tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n@@ -185,24 +189,7 @@ static unsigned get_convert_stats_wt(const char *path)\n \t}\n \tclose(fd);\n \tconvert_nonprintable(&stats);\n-\treturn stats.stat_bits;\n-}\n-\n-const char *get_cached_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n-\tconvert_stats = get_convert_stats_sha1(path,\n-\t\t\t\t\t       get_sha1_from_cache(path),\n-\t\t\t\t\t       earlyout);\n-\treturn convert_stats_ascii(convert_stats);\n-}\n-\n-const char *get_wt_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_wt(path);\n-\treturn convert_stats_ascii(convert_stats);\n+\treturn convert_stats_ascii(stats.stat_bits);\n }\n \n static int text_eol_is_crlf(void)\n@@ -241,53 +228,90 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \treturn core_eol;\n }\n \n+static int would_convert_lf_at_checkout(unsigned convert_stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tif (output_eol(crlf_action) != EOL_CRLF)\n+\t\treturn 0;\n+\n+\t/* No \"naked\" LF? Nothing to convert, regardless. */\n+\tif (!convert_stats & CONVERT_STAT_BITS_TXT_LF)\n+\t\treturn 0;\n+\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\t/* auto: binary files are not converted */\n+\t\tif (convert_stats & CONVERT_STAT_BITS_BIN)\n+\t\t\treturn 0;\n+\t}\n+\t/* If we have any CRLF line endings, we do not touch it */\n+\t/* This is the new safer autocrlf-handling */\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+\n+}\n+\n+static int would_convert_crlf_at_commit(const char * path,\n+\t\t\t\t\tconst struct text_stat *stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tunsigned stat_bits_index;\n+\t/* No CRLF? Nothing to convert, regardless. */\n+\tif (!(stats->stat_bits & CONVERT_STAT_BITS_TXT_CRLF))\n+\t\treturn 0;\n+\t/*\n+\t * If the file in the index has any CRLF in it, do not convert.\n+\t * This is the new safer autocrlf handling.\n+\t */\n+\tstat_bits_index = get_convert_stats_sha1(path,\n+\t\t\t\t\t\t get_sha1_from_cache(path),\n+\t\t\t\t\t\t CONVERT_STAT_BITS_TXT_CRLF);\n+\tif (stat_bits_index & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+}\n+\n static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n-                            struct text_stat *stats, enum safe_crlf checksafe)\n+\t\t\t    enum safe_crlf checksafe,\n+\t\t\t    unsigned convert_stats, unsigned new_convert_stats)\n {\n \tif (!checksafe)\n \t\treturn;\n-\n-\tif (output_eol(crlf_action) == EOL_LF) {\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n \t\t/*\n \t\t * CRLFs would not be restored by checkout:\n \t\t * check if we'd remove CRLFs\n \t\t */\n-\t\tif (stats->crlf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n-\t\t}\n-\t} else if (output_eol(crlf_action) == EOL_CRLF) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n+\t}\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_LF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_LF)) {\n \t\t/*\n \t\t * CRLFs would be added by checkout:\n \t\t * check if we have \"naked\" LFs\n \t\t */\n-\t\tif (stats->lonelf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n-\t\t}\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n \t}\n }\n \n-static int has_cr_in_index(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_sha1(path,\n-\t\t\t\t\t       get_sha1_from_cache(path),\n-\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n-\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n-}\n-\n static int crlf_to_git(const char *path, const char *src, size_t len,\n \t\t       struct strbuf *buf,\n \t\t       enum crlf_action crlf_action, enum safe_crlf checksafe)\n {\n \tstruct text_stat stats;\n \tchar *dst;\n-\n+\tint convert_crlf;\n \tif (crlf_action == CRLF_BINARY ||\n \t    (src && !len))\n \t\treturn 0;\n@@ -299,23 +323,36 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n-\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\t\t/*\n-\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t * This is the new safer autocrlf handling.\n-\t\t */\n-\t\tif (has_cr_in_index(path))\n-\t\t\treturn 0;\n+\t} else {\n+\t\tgather_stats(src, len, &stats, 0);\n \t}\n-\n-\tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n-\n-\t/* Optimization: No CRLF? Nothing to convert, regardless. */\n-\tif (!stats.crlf)\n+\tconvert_crlf = would_convert_crlf_at_commit(path, &stats, len,\n+\t\t\t\t\t\t    crlf_action);\n+\tif (checksafe) {\n+\t\tunsigned convert_stats = stats.stat_bits;\n+\t\tunsigned new_convert_stats = convert_stats;\n+\t\t/* Simulate commit */\n+\t\tif (convert_crlf &&\n+\t\t    (new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_LF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t}\n+\t\t/* Simulate checkout */\n+\t\tif (would_convert_lf_at_checkout(new_convert_stats,\n+\t\t\t\t\t\t len, crlf_action)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_LF;\n+\t\t}\n+\t\tcheck_safe_crlf(path, crlf_action, checksafe,\n+\t\t\t\tconvert_stats, new_convert_stats);\n+\t}\n+\tif (!convert_crlf)\n \t\treturn 0;\n \n \t/*\n@@ -329,7 +366,9 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (strbuf_avail(buf) + buf->len < len)\n \t\tstrbuf_grow(buf, len - buf->len);\n \tdst = buf->buf;\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n \t\t/*\n \t\t * If we guessed, we already know we rejected a file with\n \t\t * lone CR, and we can strip a CR without looking at what\n@@ -356,28 +395,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n-\n-\n-\tif (!len || output_eol(crlf_action) != EOL_CRLF)\n+\tunsigned earlyout = 0; /* Need to count lonelf */\n+\tif (!len)\n \t\treturn 0;\n \n \tgather_stats(src, len, &stats, earlyout);\n-\n-\t/* No \"naked\" LF? Nothing to convert, regardless. */\n-\tif (!stats.lonelf)\n+\tif (!would_convert_lf_at_checkout(stats.stat_bits,\n+\t\t\t\t\t  len, crlf_action))\n \t\treturn 0;\n \n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t/* This is the new safer autocrlf-handling */\n-\t\tif (stats.lonecr || stats.crlf )\n-\t\t\treturn 0;\n-\n-\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n-\t\t\treturn 0;\n-\t}\n-\n \t/* are we \"faking\" in place editing ? */\n \tif (src == buf->buf)\n \t\tto_free = strbuf_detach(buf, NULL);\n@@ -1079,6 +1105,8 @@ int is_null_stream_filter(struct stream_filter *filter)\n struct lf_to_crlf_filter {\n \tstruct stream_filter filter;\n \tunsigned has_held:1;\n+\tunsigned expanded_loneLF:1;\n+\tunsigned had_CRLF:1;\n \tchar held;\n };\n \n@@ -1119,7 +1147,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \t\t\tchar ch = input[i];\n \n \t\t\tif (ch == '\\n') {\n-\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\tif (!lf_to_crlf->had_CRLF) {\n+\t\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\t\tlf_to_crlf->expanded_loneLF = 1;\n+\t\t\t\t}\n+\t\t\t\tif (was_cr)\n+\t\t\t\t\tlf_to_crlf->had_CRLF = 1;\n \t\t\t} else if (was_cr) {\n \t\t\t\t/*\n \t\t\t\t * Previous round saw CR and it is not followed\n@@ -1148,6 +1181,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \n \t\t\twas_cr = 0;\n \t\t\toutput[o++] = ch;\n+\t\t\tif (lf_to_crlf->expanded_loneLF &&\n+\t\t\t    lf_to_crlf->had_CRLF) {\n+\t\t\t\t/*\n+\t\t\t\t * Mixed EOL, round trip not possible.\n+\t\t\t\t */\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n \t\t}\n \n \t\t*osize_p -= o;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex d0bee08..b5f93e2 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n+test_expect_success 'crlf=true causes a CRLF file not to be normalized' '\n \n \t# Backwards compatibility check\n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n-test_expect_success 'text=true causes a CRLF file to be normalized' '\n+test_expect_success 'text=true causes a CRLF file not to be normalized' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \techo \"CRLFonly text\" > .gitattributes &&\n@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 86175cf..3fa9be4 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -354,7 +354,7 @@ else\n \tWAMIX=CRLF_LF\n fi\n \n-#                         attr   LF        CRLF      CRLFmixLF LFmixCR   CRLFNUL\n+#                               attr   LF        CRLF      CRLFmixLF LFmixCR   CRLFNUL\n test_expect_success 'commit files empty attr' '\n \tcommit_check_warn false \"\"     \"\"        \"\"        \"\"        \"\"        \"\" &&\n \tcommit_check_warn true  \"\"     \"LF_CRLF\" \"\"        \"LF_CRLF\" \"\"        \"\" &&\n@@ -391,7 +391,7 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+#                 attr    aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n@@ -401,20 +401,22 @@ commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"\n commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input;\n do\n+#                          attr aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n-\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        \"\"          LF_CRLF     \"\"\n \tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          LF_CRLF     \"\"\n done\n \n-commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n-commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n+#                  attr   aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"$WILC\"     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        \"\"          LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n@@ -455,9 +457,9 @@ do\n \tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n@@ -478,12 +480,10 @@ done\n \n if test_have_prereq NATIVE_CRLF\n then\n-MIX_CRLF_LF=CRLF\n MIX_LF_CR=CRLF_mix_CR\n NL=CRLF\n LFNUL=CRLF_nul\n else\n-MIX_CRLF_LF=CRLF_mix_LF\n MIX_LF_CR=LF_mix_CR\n NL=LF\n LFNUL=LF_nul\n@@ -503,20 +503,20 @@ do\n \t\t\tcheckout_files \"-text\" \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\tcheckout_files \"-text\" \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\tcheckout_files \"text\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files \"text\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files \"text\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\tdone\n \tdone\n \t# text: core.autocrlf=false uses core.eol\n-\tcheckout_files \"text\"  \"$id\"  \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  crlf     CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \tcheckout_files \"text\"  \"$id\"  \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files \"text\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\"  \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  CRLF_mix_LF  $MIX_LF_CR   $LFNUL\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  native   $NL   CRLF  CRLF_mix_LF  $MIX_LF_CR   $LFNUL\n \n \tfor ceol in \"\" lf crlf native;\n \tdo\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files \"text\"  \"$id\"  \"\"    true   \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tcheckout_files \"text\"  \"$id\"  \"\"    true   \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n \t\tcheckout_files \"text\"  \"$id\"  \"\"    input  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tcheckout_files \"auto\"  \"$id\"  \"\"    input  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-- \n2.8.0.rc2.6.g3847ccb\n"},{"id":"282056","messageId":"CACsJy8A-nwv2B=6B4TqAz+i=DxC6Wu5yO924uaXWd5zLuXFRTQ@mail.gmail.com","threadId":"41391","inReplyTo":"1459257930-17193-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v1 1/7] Make it possible to get sha1 for a path from the index","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-29T13:28:29Z","receivedAt":"2016-03-29T13:28:29Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Mar 29, 2016 at 8:25 PM,  <tboegi@web.de> wrote:\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> Factor out the retrival of the sha1 for a given path in\n> read_blob_data_from_index() into the function get_sha1_from_index().\n\nGetting _sha1_ from index is one function call and a memory\ndereference or two. I think you mean get sha1 _file_ (or data) from\nindex. Maybe put either word in the function name.\n\n> This will be used in the next commit, when convert.c can do the analyze\n> for \"text=auto\" without slurping the whole blob into memory at once.\n-- \nDuy\n"},{"id":"282060","messageId":"CACsJy8DqN+s2inEeO++hcen1MH+9Op_DFG2x6n8D4xuVfgAu8w@mail.gmail.com","threadId":"41391","inReplyTo":"CACsJy8A-nwv2B=6B4TqAz+i=DxC6Wu5yO924uaXWd5zLuXFRTQ@mail.gmail.com","subject":"Re: [PATCH v1 1/7] Make it possible to get sha1 for a path from the index","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-29T13:31:00Z","receivedAt":"2016-03-29T13:31:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Mar 29, 2016 at 8:28 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Tue, Mar 29, 2016 at 8:25 PM,  <tboegi@web.de> wrote:\n>> From: Torsten Bögershausen <tboegi@web.de>\n>>\n>> Factor out the retrival of the sha1 for a given path in\n>> read_blob_data_from_index() into the function get_sha1_from_index().\n>\n> Getting _sha1_ from index is one function call and a memory\n> dereference or two. I think you mean get sha1 _file_ (or data) from\n> index. Maybe put either word in the function name.\n\nOops, shouldn't have trusted that function name in the @@ line. No\nwhat you write in the commit message matches the patch. Sorry for the\nnoise.\n-- \nDuy\n"},{"id":"282064","messageId":"56FA99AF.1040006@web.de","threadId":"41391","inReplyTo":"CACsJy8DqN+s2inEeO++hcen1MH+9Op_DFG2x6n8D4xuVfgAu8w@mail.gmail.com","subject":"Re: [PATCH v1 1/7] Make it possible to get sha1 for a path from the index","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-03-29T15:05:19Z","receivedAt":"2016-03-29T15:05:19Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 2016-03-29 15.31, Duy Nguyen wrote:\n> On Tue, Mar 29, 2016 at 8:28 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n>> On Tue, Mar 29, 2016 at 8:25 PM,  <tboegi@web.de> wrote:\n>>> From: Torsten Bögershausen <tboegi@web.de>\n>>>\n>>> Factor out the retrival of the sha1 for a given path in\n>>> read_blob_data_from_index() into the function get_sha1_from_index().\n>>\n>> Getting _sha1_ from index is one function call and a memory\n>> dereference or two. I think you mean get sha1 _file_ (or data) from\n>> index. Maybe put either word in the function name.\n> \n> Oops, shouldn't have trusted that function name in the @@ line. No\n> what you write in the commit message matches the patch. Sorry for the\n> noise.\n> \nThanks for the review.\nIt feels that the naming isn't ideal, let's see if we can find a better\nfunction name.\n"},{"id":"282071","messageId":"xmqqa8lhyzbq.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1459257938-17389-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v1 6/7] correct blame for files commited with CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-29T17:21:45Z","receivedAt":"2016-03-29T17:21:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> git blame reports lines as not \"Not Committed Yet\" when they have\n> CRLF in the index, CRLF in the worktree and e.g. core.autocrlf is true.\n>\n> Since commit c48053 \"new safer autocrlf handling\", files that have CRLF\n> in the index are not normalized at commit when e.g. core.autocrl is set.\n>\n> Whenever a CLRF conversion is needed (or any filter us set), load the\n> index temporally, before calling convert_to_git()\n\nSorry, but I do not understand what problem you are trying to\naddress here.\n\nUnder the same condition described in the first paragraph, what\nwould \"git diff\" and \"git diff HEAD\" say?  They should show that you\nwould be making a commit that corrects the line ending of the blob\nrecorded in the history.\n\nThe \"Not Committed Yet\" output from \"git blame\" is the same thing.\nIt is telling you that the commit you would be making by adding\nthat path from the working tree in its current state will become\nthe one that is responsible for the final state of the line.\n\nSo it is absolutely the right thing that these lines are shown as\n\"Not Commited Yet\".  You will be making the line-ending correction\nfor the entire blob, and you should be made aware of it.\n\nNow, it would be a very good idea for such a correction change to\nhave no other change, and it would be a very good idea to give users\na tool to see if there is any change other than the eol correction.\nThere is \"git blame -w\" to ignore whitespace changes, and I think\nthat would hide the CRLF/LF correction, but that hides all other kinds\nof whitespace changes, so it is too broad for the purpose.\n\nI do not think I'd be opposed to a new option to allow the command\nto ignore _only_ eol changes (this applies not just to \"blame\" but\nalso to \"diff\", too).  That way:\n\n * The users can more easily make sure that the set of changes being\n   prepared does not do anything other than correcting eol;\n\n * \"git blame\" can be told to relieve a commit of the responsibility\n   for lines if the only change it did to them is to correct eol\n   when digging the history (i.e. this will not just help \"Not\n   Committed Yet\" changes in the working tree, but for digging\n   through historical events).\n"},{"id":"282080","messageId":"xmqqr3etxh9i.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1459257940-17428-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v1 7/7] convert.c: more safer crlf handling with text attribute","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-29T18:37:13Z","receivedAt":"2016-03-29T18:37:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> A follow-up after a discussion how to fix the flaky execution\n> of t0025, gmane/$284352.\n> ...\n> The new handling makes sure that after running \"git reset --hard\".\n> \"git status\" reports the working tree as clean regarding CRLF\n> conversion.  It makes sure that the Git-internal eol conversion is\n> doing roundtrip. A user can still write an external smudge/clean\n> filter outside Git, which doesn't do a roundtrip and the working\n> directory is not clean.\n\nIf the project (not Git itself, but I am talking about any project\nused by real people) declares that the blobs in the history must be\nusing LF endings (perhaps it wants to be protable across two worlds)\nby telling the users to set configurations so that \"git add\" would\ndo the crlf-to-lf conversion, why is it a good idea to bend over\nbackwards to _hide_ the fact that the index records something that\ncontradicts with the project policy expressed by the end-user\nconfiguration?  If the project wants to standardize on CRLF endings\nin the recorded history and some users use configurations and filters\nto use LF ending in their working tree, the same argument applies.\nIf they by mistake or whatever adds blobs with LF line ending, that\nalso should be shown as a change.\n\nI would understand if the \"fix\" were to make sure that the working\ntree files are dirty after \"git reset --hard\".  If you \"git add\" the\nfiles from the working tree and make a commit from such a state, you\nwill be changing the path in the commited history, so by definition\nthe working tree should be reported as dirty, shouldn't it?\n\nI started to suspect that the flaky test in t0025 is not worth\naddressing for some time ago (iow, it is testing and expecting some\nfixed result where we should just declare \"the behaviour is\nundefined if you did so\"), and especially if the best we can do is\nto treat line-ending conversion something so special, it does not\nsound like we are going in the right direction.\n"},{"id":"282095","messageId":"CAPig+cQ7GrANpqPxpRAZLyYzO5pNj8ZjF0HX99VkSoJ98TzH8Q@mail.gmail.com","threadId":"41391","inReplyTo":"1459257930-17193-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v1 1/7] Make it possible to get sha1 for a path from the index","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-03-29T19:32:32Z","receivedAt":"2016-03-29T19:32:32Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Mar 29, 2016 at 9:25 AM,  <tboegi@web.de> wrote:\n> Factor out the retrival of the sha1 for a given path in\n\ns/retrival/retrieval/\n\n> read_blob_data_from_index() into the function get_sha1_from_index().\n>\n> This will be used in the next commit, when convert.c can do the analyze\n> for \"text=auto\" without slurping the whole blob into memory at once.\n>\n> Add a wrapper definition get_sha1_from_cache().\n>\n> Signed-off-by: Torsten Bögershausen <tboegi@web.de>\n"},{"id":"282097","messageId":"CAPig+cQiSaz-NdaenrR8H840S9-BVTqs-HARBvQVgcKpKSvw6A@mail.gmail.com","threadId":"41391","inReplyTo":"1459257937-17350-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v1 5/7] CRLF: unify the \"auto\" handling","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-03-29T19:42:53Z","receivedAt":"2016-03-29T19:42:53Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Mar 29, 2016 at 9:25 AM,  <tboegi@web.de> wrote:\n> Make .gitattributes \"* text=auto eol=crlf\" to do the same as\n> setting core.autocrlf=true and \"* text=auto eol=crlf\" the same\n> as core.autocrlf=input\n>\n> Signed-off-by: Torsten Bögershausen <tboegi@web.de>\n> ---\n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> @@ -389,14 +389,15 @@ file with mixed line endings would be reported by the `core.safecrlf`\n>  core.autocrlf::\n> -       Setting this variable to \"true\" is almost the same as setting\n> -       the `text` attribute to \"auto\" on all files except that text\n> -       files are not guaranteed to be normalized: files that contain\n> +       Setting this variable to \"true\" is the same as setting\n> +       the attributes to \"auto eol=crlf\" on all files.\n> +       Files are not guaranteed to be normalized: files that contain\n>         `CRLF` in the repository will not be touched.  Use this\n>         setting if you want to have `CRLF` line endings in your\n> -       working directory even though the repository does not have\n> -       normalized line endings.  This variable can be set to 'input',\n> +       working directory and he repository has normalized line endings.\n\ns/he/the/\n\n> +       This variable can be set to 'input',\n>         in which case no output conversion is performed.\n> +       Note: older versions of Git behave different.\n\nWould it make sense to spell out what \"different\" means since new\nreaders won't know what the old behavior was?\n\n> diff --git a/convert.c b/convert.c\n> @@ -370,12 +369,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n>         if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n> -               if (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n> -                       /* If we have any CR or CRLF line endings, we do not touch it */\n> -                       /* This is the new safer autocrlf-handling */\n> -                       if (stats.lonecr || stats.crlf )\n> -                               return 0;\n> -               }\n> +               /* If we have any CR or CRLF line endings, we do not touch it */\n> +               /* This is the new safer autocrlf-handling */\n\nThe comment style violation could have been fixed while outdenting,\nbut perhaps it's not worth the churn.\n\n> +               if (stats.lonecr || stats.crlf )\n> +                       return 0;\n"},{"id":"282100","messageId":"56FADCAB.1010201@web.de","threadId":"41391","inReplyTo":"xmqqa8lhyzbq.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v1 6/7] correct blame for files commited with CRLF","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-03-29T19:51:07Z","receivedAt":"2016-03-29T19:51:07Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 29.03.16 19:21, Junio C Hamano wrote:\n> tboegi@web.de writes:\n> \n>> From: Torsten Bögershausen <tboegi@web.de>\n>>\n>> git blame reports lines as not \"Not Committed Yet\" when they have\n>> CRLF in the index, CRLF in the worktree and e.g. core.autocrlf is true.\n>>\n>> Since commit c48053 \"new safer autocrlf handling\", files that have CRLF\n>> in the index are not normalized at commit when e.g. core.autocrl is set.\n>>\n>> Whenever a CLRF conversion is needed (or any filter us set), load the\n>> index temporally, before calling convert_to_git()\n> \n> Sorry, but I do not understand what problem you are trying to\n> address here.\n> \n> Under the same condition described in the first paragraph, what\n> would \"git diff\" and \"git diff HEAD\" say?  They should show that you\n> would be making a commit that corrects the line ending of the blob\n> recorded in the history.\n> \nLet's make an experiment, Git v2.8.0\n\n\n$ printf \"Line1\\r\\nLine2\\r\\n\" >test_CRLF.txt\n$ git add test_CRLF.txt \n$ git commit -m \"add test_CRLF.txt\"\n [detached HEAD 719c166] add test_CRLF.txt\n 1 file changed, 2 insertions(+)\n create mode 100644 test_CRLF.txt\n\n$ git ls-files --eol test_CRLF.txt \ni/crlf  w/crlf  attr/                   test_CRLF.txt\n# So far, so good.\n\ngit config core.autocrlf true\n\n# Now lets patch Git to debug the safer CRLF handling\ndiff --git a/convert.c b/convert.c\nindex f524b8d..fcf7653 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -260,8 +260,11 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n                         * If the file in the index has any CR in it, do not convert.\n                         * This is the new safer autocrlf handling.\n                         */\n-                       if (has_cr_in_index(path))\n+                       if (has_cr_in_index(path)) {\n+                               fprintf(stderr, \"%s/%s:%d has_cr_in_index(%s)\\n\",\n+                                       __FILE__, __FUNCTION__, __LINE__, path);\n                                return 0;\n+                       }\n\n# Of course, run make\n$ make\n#\nprintf \"Line3\\r\\n\" >>test_CRLF.txt\n\n# Lets see what diff says:\n./git diff test_CRLF.txt | od -c\nconvert.c/crlf_to_git:265 has_cr_in_index(test_CRLF.txt)\nconvert.c/crlf_to_git:265 has_cr_in_index(test_CRLF.txt)\n0000000    d   i   f   f       -   -   g   i   t       a   /   t   e   s\n0000020    t   _   C   R   L   F   .   t   x   t       b   /   t   e   s\n0000040    t   _   C   R   L   F   .   t   x   t  \\n   i   n   d   e   x\n0000060        4   a   a   5   5   1   d   .   .   d   0   f   a   f   1\n0000100    d       1   0   0   6   4   4  \\n   -   -   -       a   /   t\n0000120    e   s   t   _   C   R   L   F   .   t   x   t  \\n   +   +   +\n0000140        b   /   t   e   s   t   _   C   R   L   F   .   t   x   t\n0000160   \\n   @   @       -   1   ,   2       +   1   ,   3       @   @\n0000200   \\n       L   i   n   e   1  \\r  \\n       L   i   n   e   2  \\r\n0000220   \\n   +   l   i   n   e   3  \\r  \\n                            \n0000231\n# Here the lines are not going to be normalized at the next commit.\n# They stay CRLF.\n# But git blame doesn't know that, because has_cr_in_index doesn't work\n# without an index.\n\n$ ./git blame test_CRLF.txt \n00000000 (Not Committed Yet 2016-03-29 21:44:48 +0200 1) Line1\n00000000 (Not Committed Yet 2016-03-29 21:44:48 +0200 2) Line2\n00000000 (Not Committed Yet 2016-03-29 21:44:48 +0200 3) line3\n\n\n\n$ git commit -m \"Add line3\" test_CRLF.txt\n\n> The \"Not Committed Yet\" output from \"git blame\" is the same thing.\n> It is telling you that the commit you would be making by adding\n> that path from the working tree in its current state will become\n> the one that is responsible for the final state of the line.\n> \n> So it is absolutely the right thing that these lines are shown as\n> \"Not Commited Yet\".  You will be making the line-ending correction\n> for the entire blob, and you should be made aware of it.\nIf we had made the CRLF -> LF conversion, yes. But we don't do that.\ncrlf_to_git() returns without touching the line endings.\n"},{"id":"282102","messageId":"xmqq1t6txdic.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"56FADCAB.1010201@web.de","subject":"Re: [PATCH v1 6/7] correct blame for files commited with CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-29T19:58:19Z","receivedAt":"2016-03-29T19:58:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n> # Here the lines are not going to be normalized at the next commit.\n> # They stay CRLF.\n\nIsn't that the real source of the problem?  Why don't we fix that\nthen?\n"},{"id":"282110","messageId":"xmqqio05vxo9.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"56FADCAB.1010201@web.de","subject":"Re: [PATCH v1 6/7] correct blame for files commited with CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-29T20:25:42Z","receivedAt":"2016-03-29T20:25:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n> If we had made the CRLF -> LF conversion, yes. But we don't do that.\n> crlf_to_git() returns without touching the line endings.\n\nThat sounds quite broken.  How would a user ever fix broken data in\nthe index then?  I know the commit that often appears in these\ndiscussions claims to give us \"safer CRLF\" handling, but I have a\nsuspicion that perhaps we should rethink if that claim is really\ntrue.  Isn't it giving us more problems than it is worth?\n"},{"id":"282114","messageId":"xmqqa8lhvxd4.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"xmqqio05vxo9.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v1 6/7] correct blame for files commited with CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-29T20:32:23Z","receivedAt":"2016-03-29T20:32:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Torsten Bögershausen <tboegi@web.de> writes:\n>\n>> If we had made the CRLF -> LF conversion, yes. But we don't do that.\n>> crlf_to_git() returns without touching the line endings.\n>\n> That sounds quite broken.  How would a user ever fix broken data in\n> the index then?  I know the commit that often appears in these\n> discussions claims to give us \"safer CRLF\" handling, but I have a\n> suspicion that perhaps we should rethink if that claim is really\n> true.  Isn't it giving us more problems than it is worth?\n\nHaving said all that, within the context of the current codebase\nwhere autocrlf refuses to do the conversion, I agree that teaching\nblame to follow the same logic makes sense.  Let me review the\nseries up to 6/7 with fresh eyes.\n\nThanks.\n"},{"id":"282116","messageId":"xmqq60w5vwj9.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"xmqqa8lhvxd4.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v1 6/7] correct blame for files commited with CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-29T20:50:18Z","receivedAt":"2016-03-29T20:50:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> Torsten Bögershausen <tboegi@web.de> writes:\n>>\n>>> If we had made the CRLF -> LF conversion, yes. But we don't do that.\n>>> crlf_to_git() returns without touching the line endings.\n>>\n>> That sounds quite broken.  How would a user ever fix broken data in\n>> the index then?  I know the commit that often appears in these\n>> discussions claims to give us \"safer CRLF\" handling, but I have a\n>> suspicion that perhaps we should rethink if that claim is really\n>> true.  Isn't it giving us more problems than it is worth?\n>\n> Having said all that, within the context of the current codebase\n> where autocrlf refuses to do the conversion, I agree that teaching\n> blame to follow the same logic makes sense.  Let me review the\n> series up to 6/7 with fresh eyes.\n\nAnd for the same reason 7/7 may make sense (I didn't check the\nimplementation, but I think I understand your motivation well enough\nto comment)--if crlf-to-git returns without actually converting upon\nnext \"git add $path\", in order to serve a preview of what change you\nwould be checking in and/or committing when you do \"git add $path\"\nand/or \"git commit $path\", the _to_git() conversion \"git diff\" and\n\"git diff HEAD\" do on the contents taken from the working tree\nshould follow the same logic.\n\n\"git diff $tree-ish\" (of which \"git diff HEAD\" is a special case) is\na bit tricky to reason about, but I think using the \"does index have\nCR to cause us refuse conversion?\" logic is a sensible thing to do\neven in that case.  It is asking what difference you would have if\nyou committed the state in the working tree right now, and the \"does\nindex have CR?\" logic to kick in, even though the contents of the\nindex may not be something that was derived from the unrelated\n$tree-ish, would kick in when you make the hypothetical commit to be\ncompared against $tree-ish.\n\nAgain, let me review 7/7 as well with fresh eyes.\n\nThanks.\n"},{"id":"282255","messageId":"56FC1184.7010802@web.de","threadId":"41391","inReplyTo":"xmqq60w5vwj9.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v1 6/7] correct blame for files commited with CRLF","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-03-30T17:48:52Z","receivedAt":"2016-03-30T17:48:52Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"7/7 needs to be amended with something like this,\nand the documentation needs an update.\n\nIn any case, the user can normalize the repo like this:\n$ echo \"* text=auto\" >>.gitattributes\n$ rm .git/index     # Remove the index to force Git to\n$ git reset         # re-scan the working directory\n$ git status        # Show files that will be normalized\n$ git add -u\n$ git add .gitattributes\n$ git commit -m \"Introduce end-of-line normalization\"\n\n(or run \"dos2unix\" filename)\n\n----------------\n\n\ncommit a604db36bb946000776514c220964f32979c8756\nAuthor: Torsten Bögershausen <tboegi@web.de>\nDate:   Wed Mar 30 15:53:52 2016 +0200\n\n    convert.c: add warning when eol are wrong after checkout\n    \n    When line endings are not normalized, they may be different after the\n    next checkout to what is configured.\n    Add a warning, similar to the CRLF-LF replacement, when a file is commited,\n    and the line endings are not converted at commit or checkout.\n\ndiff --git a/convert.c b/convert.c\nindex 8266d87..1fddbe8 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -18,6 +18,8 @@\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n \n+#define CONVERT_STAT_BITS_MIXED (CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF)\n+\n enum crlf_action {\n \tCRLF_UNDEFINED,\n \tCRLF_BINARY,\n@@ -279,6 +281,8 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \t\t\t    enum safe_crlf checksafe,\n \t\t\t    unsigned convert_stats, unsigned new_convert_stats)\n {\n+\tenum eol new_eol = output_eol(crlf_action);\n+\tconst char *err_warn_msg = NULL;\n \tif (!checksafe)\n \t\treturn;\n \tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF &&\n@@ -303,6 +307,19 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \t\telse /* i.e. SAFE_CRLF_FAIL */\n \t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n \t}\n+\tif ((new_convert_stats & CONVERT_STAT_BITS_MIXED) == CONVERT_STAT_BITS_MIXED)\n+\t\terr_warn_msg = \"mixed eol\";\n+\telse if (new_eol == EOL_LF && new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\terr_warn_msg = \"CRLF\";\n+\n+\tif (err_warn_msg) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"%s will be present after commit and checkout in %s.\",\n+\t\t\t\terr_warn_msg, path);\n+\t\telse\n+\t\t\tdie(\"%s will be present after commit and checkout in %s\",\n+\t\t\t    err_warn_msg, path);\n+\t}\n }\n \n[snip changes in t0027] \n"},{"id":"282471","messageId":"1459526902-19790-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v2 1/7] Make it possible to get sha1 for a path from the index","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-01T16:08:22Z","receivedAt":"2016-04-01T16:08:22Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nFactor out the retrieval of the sha1 for a given path in\nread_blob_data_from_index() into the function get_sha1_from_index().\n\nThis will be used in the next commit, when convert.c can do the analyze\nfor \"text=auto\" without slurping the whole blob into memory at once.\n\nAdd a wrapper definition get_sha1_from_cache().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n- Changes against v1:\n  Fixed typos, thanks Eric\n  Corrected gitattributes.txt, \"auto\" will no longer normalize\n  Rework of 7/7: Show the eol mismatch to the user when committing\n---\n cache.h      |  3 +++\n read-cache.c | 29 ++++++++++++++++++-----------\n 2 files changed, 21 insertions(+), 11 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex b829410..bd1210a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -379,6 +379,7 @@ extern void free_name_hash(struct index_state *istate);\n #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)\n #define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)\n #define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))\n+#define get_sha1_from_cache(path)  get_sha1_from_index (&the_index, (path))\n #endif\n \n enum object_type {\n@@ -1008,6 +1009,8 @@ static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *\n \treturn read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);\n }\n \n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path);\n+\n /*\n  * This internal function is only declared here for the benefit of\n  * lookup_replace_object().  Please do not call it directly.\ndiff --git a/read-cache.c b/read-cache.c\nindex d9fb78b..a3ef967 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -2263,13 +2263,27 @@ int index_name_is_other(const struct index_state *istate, const char *name,\n \n void *read_blob_data_from_index(struct index_state *istate, const char *path, unsigned long *size)\n {\n-\tint pos, len;\n+\tconst unsigned char *sha1;\n \tunsigned long sz;\n \tenum object_type type;\n \tvoid *data;\n \n-\tlen = strlen(path);\n-\tpos = index_name_pos(istate, path, len);\n+\tsha1 = get_sha1_from_index(istate, path);\n+\tif (!sha1)\n+\t\treturn NULL;\n+\tdata = read_sha1_file(sha1, &type, &sz);\n+\tif (!data || type != OBJ_BLOB) {\n+\t\tfree(data);\n+\t\treturn NULL;\n+\t}\n+\tif (size)\n+\t\t*size = sz;\n+\treturn data;\n+}\n+\n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path)\n+{\n+\tint pos = index_name_pos(istate, path, strlen(path));\n \tif (pos < 0) {\n \t\t/*\n \t\t * We might be in the middle of a merge, in which\n@@ -2285,14 +2299,7 @@ void *read_blob_data_from_index(struct index_state *istate, const char *path, un\n \t}\n \tif (pos < 0)\n \t\treturn NULL;\n-\tdata = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);\n-\tif (!data || type != OBJ_BLOB) {\n-\t\tfree(data);\n-\t\treturn NULL;\n-\t}\n-\tif (size)\n-\t\t*size = sz;\n-\treturn data;\n+\treturn (istate->cache[pos]->sha1);\n }\n \n void stat_validity_clear(struct stat_validity *sv)\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"282472","messageId":"1459526904-19829-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v2 2/7] convert.c: stream and early out","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-01T16:08:24Z","receivedAt":"2016-04-01T16:08:24Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen statistics are done for the autocrlf handling, the search in\nthe content can be stopped, if e.g\n- a search for binary is done, and a NUL character is found\n- a search for CRLF is done, and the first CRLF is found.\n\nSimilar when statistics for binary vs non-binary are gathered:\nWhenever a lone CR or NUL is found, the search can be aborted.\n\nWhen checking out files in \"auto\" mode, any file that has a \"lone CR\"\nor a CRLF will not be converted, so the search can be aborted early.\n\nAdd the new bit, CONVERT_STAT_BITS_ANY_CR,\nwhich is set for either lone CR or CRLF.\n\nMany binary files have a NUL very early (within the first few bytes,\nlatest within the first 1..2K).\nIt is often not necessary to load the whole content of a file or blob\ninto memory.\n\nUse a streaming handling for blobs and files in the worktree.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c | 162 ++++++++++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 106 insertions(+), 56 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex f524b8d..b6da114 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -3,6 +3,7 @@\n #include \"run-command.h\"\n #include \"quote.h\"\n #include \"sigchain.h\"\n+#include \"streaming.h\"\n \n /*\n  * convert.c - convert a file when checking it out and checking it in.\n@@ -13,10 +14,10 @@\n  * translation when the \"text\" attribute or \"auto_crlf\" option is set.\n  */\n \n-/* Stat bits: When BIN is set, the txt bits are unset */\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n+#define CONVERT_STAT_BITS_ANY_CR    0x8\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -31,30 +32,36 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned nul, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonecr, lonelf, crlf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n };\n \n-static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)\n+static void do_gather_stats(const char *buf, unsigned long size,\n+\t\t\t    struct text_stat *stats, unsigned earlyout)\n {\n \tunsigned long i;\n \n-\tmemset(stats, 0, sizeof(*stats));\n-\n+\tif (!buf || !size)\n+\t\treturn;\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n \t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n-\t\t\t} else\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\t} else {\n \t\t\t\tstats->lonecr++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+\t\t\t}\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == '\\n') {\n \t\t\tstats->lonelf++;\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_LF;\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == 127)\n@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t\t\tstats->printable++;\n \t\t\t\tbreak;\n \t\t\tcase 0:\n-\t\t\t\tstats->nul++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t\t/* fall through */\n \t\t\tdefault:\n \t\t\t\tstats->nonprintable++;\n@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t}\n \t\telse\n \t\t\tstats->printable++;\n+\t\tif (stats->stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n \t}\n \n \t/* If file ends with EOF then don't count this EOF as non-printable. */\n@@ -86,41 +95,63 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n  * The same heuristics as diff.c::mmfile_is_binary()\n  * We treat files with bare CR as binary\n  */\n-static int convert_is_binary(unsigned long size, const struct text_stat *stats)\n+static void convert_nonprintable(struct text_stat *stats)\n {\n-\tif (stats->lonecr)\n-\t\treturn 1;\n-\tif (stats->nul)\n-\t\treturn 1;\n \tif ((stats->printable >> 7) < stats->nonprintable)\n-\t\treturn 1;\n-\treturn 0;\n+\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+}\n+\n+static void gather_stats(const char *buf, unsigned long size,\n+\t\t\t struct text_stat *stats, unsigned earlyout)\n+{\n+\tmemset(stats, 0, sizeof(*stats));\n+\tdo_gather_stats(buf, size, stats, earlyout);\n+\tconvert_nonprintable(stats);\n }\n \n-static unsigned int gather_convert_stats(const char *data, unsigned long size)\n+\n+static unsigned get_convert_stats_sha1(const char *path,\n+\t\t\t\t       unsigned const char *sha1,\n+\t\t\t\t       unsigned earlyout)\n {\n+\tstruct git_istream *st;\n \tstruct text_stat stats;\n-\tint ret = 0;\n-\tif (!data || !size)\n-\t\treturn 0;\n-\tgather_stats(data, size, &stats);\n-\tif (convert_is_binary(size, &stats))\n-\t\tret |= CONVERT_STAT_BITS_BIN;\n-\tif (stats.crlf)\n-\t\tret |= CONVERT_STAT_BITS_TXT_CRLF;\n-\tif (stats.lonelf)\n-\t\tret |=  CONVERT_STAT_BITS_TXT_LF;\n+\tenum object_type type;\n+\tunsigned long sz;\n \n-\treturn ret;\n+\tif (!sha1)\n+\t\treturn 0;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tst = open_istream(sha1, &type, &sz, NULL);\n+\tif (!st) {\n+\t\treturn 0;\n+\t}\n+\tif (type != OBJ_BLOB)\n+\t\tgoto close_and_exit_i;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read_istream(st, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+close_and_exit_i:\n+\tclose_istream(st);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n }\n \n-static const char *gather_convert_stats_ascii(const char *data, unsigned long size)\n+static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned int convert_stats = gather_convert_stats(data, size);\n-\n+\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n+\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats) {\n+\tswitch (convert_stats & mask) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -132,24 +163,46 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si\n \t}\n }\n \n+static unsigned get_convert_stats_wt(const char *path)\n+{\n+\tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tint fd;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tfd = open(path, O_RDONLY);\n+\tif (fd < 0)\n+\t\treturn 0;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read(fd, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+\tclose(fd);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n+}\n+\n const char *get_cached_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret;\n-\tunsigned long sz;\n-\tvoid *data = read_blob_data_from_cache(path, &sz);\n-\tret = gather_convert_stats_ascii(data, sz);\n-\tfree(data);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(path,\n+\t\t\t\t\t       get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n const char *get_wt_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret = \"\";\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (strbuf_read_file(&sb, path, 0) >= 0)\n-\t\tret = gather_convert_stats_ascii(sb.buf, sb.len);\n-\tstrbuf_release(&sb);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_wt(path);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n static int text_eol_is_crlf(void)\n@@ -219,16 +272,11 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \n static int has_cr_in_index(const char *path)\n {\n-\tunsigned long sz;\n-\tvoid *data;\n-\tint has_cr;\n-\n-\tdata = read_blob_data_from_cache(path, &sz);\n-\tif (!data)\n-\t\treturn 0;\n-\thas_cr = memchr(data, '\\r', sz) != NULL;\n-\tfree(data);\n-\treturn has_cr;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_sha1(path,\n+\t\t\t\t\t       get_sha1_from_cache(path),\n+\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n+\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -249,10 +297,10 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \n \t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n@@ -309,11 +357,13 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n+\n \n \tif (!len || output_eol(crlf_action) != EOL_CRLF)\n \t\treturn 0;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, earlyout);\n \n \t/* No \"naked\" LF? Nothing to convert, regardless. */\n \tif (!stats.lonelf)\n@@ -327,7 +377,7 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\t\t\treturn 0;\n \t\t}\n \n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \t}\n \n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"282473","messageId":"1459526906-19868-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v2 3/7] Allow core.autocrlf=input and core.eol=crlf","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-01T16:08:26Z","receivedAt":"2016-04-01T16:08:26Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nCommit  942e77 \"Add \"core.eol\" config variable\" adds a condition to\nthe config parser: core.autocrlf=input is not allowed together with\ncore.eol=crlf.\n\nThis may lead to unnecessary problems, when config files are parsed:\nA global config file sets core.autocrlf=input,\nthe repo local config file sets is own configuration: core.eol=crlf\n\nThere is no need to prevent combinations in config.c, in any case\ncore.autocrlf overrides core.eol.\nAllow all combinations of core.crlf and core.eol and document\nthat core.autocrlf overrides core.eol.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt | 6 +++---\n config.c                 | 4 ----\n 2 files changed, 3 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2cd6bdd..4a27ad4 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -337,9 +337,9 @@ core.quotePath::\n \n core.eol::\n \tSets the line ending type to use in the working directory for\n-\tfiles that have the `text` property set.  Alternatives are\n-\t'lf', 'crlf' and 'native', which uses the platform's native\n-\tline ending.  The default value is `native`.  See\n+\tfiles that have the `text` property set when core.autocrlf is false.\n+\tAlternatives are 'lf', 'crlf' and 'native', which uses the platform's\n+\tnative line ending.  The default value is `native`.  See\n \tlinkgit:gitattributes[5] for more information on end-of-line\n \tconversion.\n \ndiff --git a/config.c b/config.c\nindex 9ba40bc..a6adc8b 100644\n--- a/config.c\n+++ b/config.c\n@@ -803,8 +803,6 @@ static int git_default_core_config(const char *var, const char *value)\n \n \tif (!strcmp(var, \"core.autocrlf\")) {\n \t\tif (value && !strcasecmp(value, \"input\")) {\n-\t\t\tif (core_eol == EOL_CRLF)\n-\t\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\t\tauto_crlf = AUTO_CRLF_INPUT;\n \t\t\treturn 0;\n \t\t}\n@@ -830,8 +828,6 @@ static int git_default_core_config(const char *var, const char *value)\n \t\t\tcore_eol = EOL_NATIVE;\n \t\telse\n \t\t\tcore_eol = EOL_UNSET;\n-\t\tif (core_eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)\n-\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\treturn 0;\n \t}\n \n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"282475","messageId":"1459526908-19907-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v2 4/7] t0027: TC for combined attributes","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-01T16:08:28Z","receivedAt":"2016-04-01T16:08:28Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nAdd more test cases for the not normalized files (\"NNO\").\nThe  \"text\" attribute is most important, use it as the first parameter.\n\"ident\", if set, is the second paramater followed by the eol attribute.\nThe eol attribute overrides core.autocrlf, which overrides core.eol.\n\nUse loops to test more combinations of attributes, like\n\"* text eol=crlf\" or especially \"*text=auto eol=crlf\".\n\nCurrently \"* text=auto eol=lf\" does the same as \"* text eol=lf\", as the\neol attribute overrides \"text=auto\", this will change in future.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n t/t0027-auto-crlf.sh | 321 +++++++++++++++++++++++++--------------------------\n 1 file changed, 158 insertions(+), 163 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex f33962b..55f45d3 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -52,14 +52,17 @@ create_gitattributes () {\n create_NNO_files () {\n \tfor crlf in false true input\n \tdo\n-\t\tfor attr in \"\" auto text -text lf crlf\n+\t\tfor attr in \"\" auto text -text\n \t\tdo\n-\t\t\tpfx=NNO_${crlf}_attr_${attr} &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tfor aeol in \"\" lf crlf\n+\t\t\tdo\n+\t\t\t\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tdone\n \t\tdone\n \tdone\n }\n@@ -100,16 +103,17 @@ commit_check_warn () {\n }\n \n commit_chk_wrnNNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfwarn=$3\n-\tcrlfwarn=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfwarn=$1 ; shift\n+\tcrlfwarn=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n \t#Commit files on top of existing file\n-\tcreate_gitattributes \"$attr\" &&\n+\tcreate_gitattributes \"$attr\" $aeol &&\n \tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n@@ -121,19 +125,19 @@ commit_chk_wrnNNO () {\n \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n \t'\n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF\" '\n \t\tcheck_warning \"$crlfwarn\" ${pfx}_CRLF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_mix_LF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_mix_LF\" '\n \t\tcheck_warning \"$lfmixcrlf\" ${pfx}_CRLF_mix_LF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF_mix_cr\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf LF_mix_cr\" '\n \t\tcheck_warning \"$lfmixcr\" ${pfx}_LF_mix_CR.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_nul\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_nul\" '\n \t\tcheck_warning \"$crlfnul\" ${pfx}_CRLF_nul.err\n \t'\n }\n@@ -162,6 +166,7 @@ stats_ascii () {\n \n # contruct the attr/ returned by git ls-files --eol\n # Take none (=empty), one or two args\n+# convert.c: eol=XX overrides text=auto\n attr_ascii () {\n \tcase $1,$2 in\n \t-text,*)   echo \"-text\" ;;\n@@ -169,8 +174,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text=auto eol=lf\" ;;\n-\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n+\tauto,lf)   echo \"text eol=lf\" ;;\n+\tauto,crlf) echo \"text eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -195,28 +200,29 @@ check_files_in_repo () {\n }\n \n check_in_repo_NNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfname=$3\n-\tcrlfname=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}_\n-\ttest_expect_success \"compare_files $lfname ${pfx}LF.txt\" '\n-\t\tcompare_files $lfname ${pfx}LF.txt\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfname=$1 ; shift\n+\tcrlfname=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\ttest_expect_success \"compare_files $lfname ${pfx}_LF.txt\" '\n+\t\tcompare_files $lfname ${pfx}_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfname ${pfx}CRLF.txt\" '\n-\t\tcompare_files $crlfname ${pfx}CRLF.txt\n+\ttest_expect_success \"compare_files $crlfname ${pfx}_CRLF.txt\" '\n+\t\tcompare_files $crlfname ${pfx}_CRLF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\" '\n-\t\tcompare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\n+\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\" '\n+\t\tcompare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcr ${pfx}LF_mix_CR.txt\" '\n-\t\tcompare_files $lfmixcr ${pfx}LF_mix_CR.txt\n+\ttest_expect_success \"compare_files $lfmixcr ${pfx}_LF_mix_CR.txt\" '\n+\t\tcompare_files $lfmixcr ${pfx}_LF_mix_CR.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfnul ${pfx}CRLF_nul.txt\" '\n-\t\tcompare_files $crlfnul ${pfx}CRLF_nul.txt\n+\ttest_expect_success \"compare_files $crlfnul ${pfx}_CRLF_nul.txt\" '\n+\t\tcompare_files $crlfnul ${pfx}_CRLF_nul.txt\n \t'\n }\n \n@@ -231,7 +237,7 @@ checkout_files () {\n \tlfmixcrlf=$1 ; shift\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n-\tcreate_gitattributes \"$attr\" \"$ident\" &&\n+\tcreate_gitattributes \"$attr\" $ident $aeol &&\n \tgit config core.autocrlf $crlf &&\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n@@ -244,7 +250,7 @@ checkout_files () {\n \t\tfi\n \tdone\n \n-\ttest_expect_success \"ls-files --eol attr=$attr $ident $aeol core.autocrlf=$crlf core.eol=$ceol\" '\n+\ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n \t\ttest_when_finished \"rm expect actual\" &&\n \t\tsort <<-EOF >expect &&\n \t\ti/crlf w/$(stats_ascii $crlfname) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF.txt\n@@ -385,31 +391,31 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                       attr   LF        CRLF      CRLFmixLF \t LF_mix_CR   CRLFNUL\n-commit_chk_wrnNNO false \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"\"     \"LF_CRLF\" \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-\n+#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO false \"auto\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"auto\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"auto\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n \n-commit_chk_wrnNNO false \"text\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"$WILC\"   \t \"$WICL\"\n-commit_chk_wrnNNO true  \"text\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"text\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"CRLF_LF\"\n-\n-commit_chk_wrnNNO false \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-\n-commit_chk_wrnNNO false \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO true  \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO input \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n+for crlf in true false input;\n+do\n+\tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+done\n \n-commit_chk_wrnNNO false \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO true  \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n \n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n@@ -440,24 +446,20 @@ test_expect_success 'commit -text' '\n \tcheck_files_in_repo input \"-text\" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n '\n \n-#                       attr    LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLFNUL\n-check_in_repo_NNO false \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO true  \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO input \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-\n-check_in_repo_NNO false \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-\n+for crlf in true false input;\n+do\n+\t#                 attr  aeol           LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLFNUL\n+\tcheck_in_repo_NNO \"\"    \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n # How to read the table below:\n@@ -489,89 +491,82 @@ LFNUL=LF_nul\n fi\n export CRLF_MIX_LF_CR MIX NL\n \n-checkout_files \"\"      \"\" \t \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   native   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   native   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\n+# Same handling with and without ident\n for id in \"\" ident;\n do\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t# -text overrides core.autocrlf and core.eol\n+\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n+\tfor crlf in true false input;\n+\tdo\n+\t\tfor ceol in \"\" lf crlf native;\n+\t\tdo\n+\t\t\tcheckout_files \"-text\" \"$id\" \"\"     \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"text\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"text\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tdone\n+\tdone\n+\t# text: core.autocrlf=false uses core.eol\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files \"auto\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files \"auto\"  \"$id\"  \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\n+\tfor ceol in \"\" lf crlf native;\n+\tdo\n+\t\t# text: core.autocrlf = true overrides core.eol\n+\t\tcheckout_files \"text\"  \"$id\"  \"\"    true   \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t# text: core.autocrlf = input overrides core.eol\n+\t\tcheckout_files \"text\"  \"$id\"  \"\"    input  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\"  \"\"    input  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tdone\n+\t# No text attr\n+\tfor ceol in \"\" lf crlf native;\n+\tdo\n+\t\t# core.autocrlf!=true gives LF (or mixed) at checkout\n+\t\tfor crlf in false input;\n+\t\tdo\n+\t\t\tcheckout_files \"\"    \"$id\" \"\"    \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tdone\n+\tdone\n+done\n+\n+#Handling without ident\n+for id in \"\";\n+do\n+\tfor ceol in \"\" lf crlf native;\n+\tdo\n+\t\t# core.autocrlf=true\n+\t\tcheckout_files \"\"      \"$id\" \"\"    true   \"$ceol\"   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\" \"\"    true   \"$ceol\"   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\t# text=auto + eol=XXX\n+\t\t# currently the same as text, eol=XXX\n+\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\tdone\n+done\n+\n+#Handling with ident\n+for id in ident;\n+do\n+\tfor crlf in \"\" true false input;\n+\tdo\n+\t\tfor ceol in \"\" lf crlf native;\n+\t\tdo\n+\t\t\t# ident does not react on core.autocrlf=true\n+\t\t\tcheckout_files \"\"      \"$id\" \"\"   \"$crlf\" \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\t# ident does not react on text=auto\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"\"    true   \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\t# text=auto + eol=XXX\n+\t\t\t# currently the same as text, eol=XXX\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tdone\n+\tdone\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"282474","messageId":"1459526909-19946-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v2 5/7] CRLF: unify the \"auto\" handling","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-01T16:08:29Z","receivedAt":"2016-04-01T16:08:29Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nMake .gitattributes \"* text=auto eol=crlf\" to do the same as\nsetting core.autocrlf=true and \"* text=auto eol=crlf\" the same\nas core.autocrlf=input\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt        | 10 ++++-----\n Documentation/gitattributes.txt | 11 +++++-----\n convert.c                       | 37 ++++++++++++++++-----------------\n t/t0025-crlf-auto.sh            |  4 ++--\n t/t0027-auto-crlf.sh            | 45 +++++++++++++++++++----------------------\n 5 files changed, 53 insertions(+), 54 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 4a27ad4..dfaf39c 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf`\n mechanism.\n \n core.autocrlf::\n-\tSetting this variable to \"true\" is almost the same as setting\n-\tthe `text` attribute to \"auto\" on all files except that text\n-\tfiles are not guaranteed to be normalized: files that contain\n+\tSetting this variable to \"true\" is the same as setting\n+\tthe attributes to \"auto eol=crlf\" on all files.\n+\tFiles are not guaranteed to be normalized: files that contain\n \t`CRLF` in the repository will not be touched.  Use this\n \tsetting if you want to have `CRLF` line endings in your\n-\tworking directory even though the repository does not have\n-\tnormalized line endings.  This variable can be set to 'input',\n+\tworking directory and the repository has normalized line endings.\n+\tThis variable can be set to 'input',\n \tin which case no output conversion is performed.\n \n core.symlinks::\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex e3b1de8..c2663c7 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n `core.eol` configuration variable for all text files.\n+Note that `core.autocrlf` overrides `core.eol`\n \n Set::\n \n@@ -146,8 +147,8 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It enables end-of-line normalization without any\n-content checks, effectively setting the `text` attribute.\n+working directory.  It sets the `text` attribute,\n+unless `text=auto` is specified.\n \n Set to string value \"crlf\"::\n \n@@ -187,8 +188,8 @@ regardless of their content.\n \n ------------------------\n *.txt\t\ttext\n-*.vcproj\teol=crlf\n-*.sh\t\teol=lf\n+*.vcproj\ttext eol=crlf\n+*.sh\t\ttext eol=lf\n *.jpg\t\t-text\n ------------------------\n \n@@ -198,7 +199,7 @@ normalization in Git.\n \n If you simply want to have CRLF line endings in your working directory\n regardless of the repository you are working with, you can set the\n-config variable \"core.autocrlf\" without changing any attributes.\n+config variable \"core.autocrlf\" without using any attributes.\n \n ------------------------\n [core]\ndiff --git a/convert.c b/convert.c\nindex b6da114..4ed5d89 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -229,7 +229,9 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \t\treturn EOL_LF;\n \tcase CRLF_UNDEFINED:\n \tcase CRLF_AUTO_CRLF:\n+\t\treturn EOL_CRLF;\n \tcase CRLF_AUTO_INPUT:\n+\t\treturn EOL_LF;\n \tcase CRLF_TEXT:\n \tcase CRLF_AUTO:\n \t\t/* fall through */\n@@ -302,15 +304,12 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/*\n-\t\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t\t * This is the new safer autocrlf handling.\n-\t\t\t */\n-\t\t\tif (has_cr_in_index(path))\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/*\n+\t\t * If the file in the index has any CR in it, do not convert.\n+\t\t * This is the new safer autocrlf handling.\n+\t\t */\n+\t\tif (has_cr_in_index(path))\n+\t\t\treturn 0;\n \t}\n \n \tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n@@ -370,12 +369,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\treturn 0;\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t\t/* This is the new safer autocrlf-handling */\n-\t\t\tif (stats.lonecr || stats.crlf )\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n+\t\t/* This is the new safer autocrlf-handling */\n+\t\tif (stats.lonecr || stats.crlf )\n+\t\t\treturn 0;\n \n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n@@ -836,7 +833,11 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tca->drv = git_path_check_convert(ccheck + 2);\n \t\tif (ca->crlf_action != CRLF_BINARY) {\n \t\t\tenum eol eol_attr = git_path_check_eol(ccheck + 3);\n-\t\t\tif (eol_attr == EOL_LF)\n+\t\t\tif (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_INPUT;\n+\t\t\telse if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_CRLF;\n+\t\t\telse if (eol_attr == EOL_LF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_INPUT;\n \t\t\telse if (eol_attr == EOL_CRLF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_CRLF;\n@@ -895,9 +896,9 @@ const char *get_convert_attr_ascii(const char *path)\n \tcase CRLF_AUTO:\n \t\treturn \"text=auto\";\n \tcase CRLF_AUTO_CRLF:\n-\t\treturn \"text=auto eol=crlf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=crlf\";\n \tcase CRLF_AUTO_INPUT:\n-\t\treturn \"text=auto eol=lf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=lf\";\n \t}\n \treturn \"\";\n }\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex c164b46..d0bee08 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -114,7 +114,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n+test_expect_success 'text=auto, autocrlf=true does not normalize CRLF files' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \tgit config core.autocrlf true &&\n@@ -126,7 +126,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n \tLFonlydiff=$(git diff LFonly) &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n \tLFwithNULdiff=$(git diff LFwithNUL) &&\n-\ttest -z \"$LFonlydiff\" -a -n \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n+\ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 55f45d3..86175cf 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -174,8 +174,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text eol=lf\" ;;\n-\tauto,crlf) echo \"text eol=crlf\" ;;\n+\tauto,lf)   echo \"text=auto eol=lf\" ;;\n+\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -396,10 +396,9 @@ commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n-\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input;\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n@@ -407,8 +406,8 @@ do\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n \tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n \tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n done\n@@ -453,9 +452,9 @@ do\n \tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n@@ -513,8 +512,6 @@ do\n \t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n \tcheckout_files \"text\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \tcheckout_files \"text\"  \"$id\"  \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"auto\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"auto\"  \"$id\"  \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \n \tfor ceol in \"\" lf crlf native;\n \tdo\n@@ -541,30 +538,30 @@ do\n \tfor ceol in \"\" lf crlf native;\n \tdo\n \t\t# core.autocrlf=true\n-\t\tcheckout_files \"\"      \"$id\" \"\"    true   \"$ceol\"   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files \"auto\"  \"$id\" \"\"    true   \"$ceol\"   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files \"\"      \"$id\" \"\"     true   \"$ceol\"   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\" \"\"     true   \"$ceol\"   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\"  \"\"    false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\"  \"\"    false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text=auto + eol=XXX\n-\t\t# currently the same as text, eol=XXX\n-\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \tdone\n done\n \n #Handling with ident\n for id in ident;\n do\n-\tfor crlf in \"\" true false input;\n+\tfor crlf in true false input;\n \tdo\n \t\tfor ceol in \"\" lf crlf native;\n \t\tdo\n \t\t\t# ident does not react on core.autocrlf=true\n-\t\t\tcheckout_files \"\"      \"$id\" \"\"   \"$crlf\" \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"\"      \"$id\" \"\"     \"$crlf\" \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\t# ident does not react on text=auto\n-\t\t\tcheckout_files \"auto\"  \"$id\" \"\"    true   \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"\"      true   \"$ceol\"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\t# text=auto + eol=XXX\n-\t\t\t# currently the same as text, eol=XXX\n-\t\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"auto\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \tdone\n done\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"282476","messageId":"1459526911-19985-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v2 6/7] correct blame for files commited with CRLF","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-01T16:08:31Z","receivedAt":"2016-04-01T16:08:31Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\ngit blame reports lines as not \"Not Committed Yet\" when they have\nCRLF in the index, CRLF in the worktree and e.g. core.autocrlf is true.\n\nSince commit c48053 \"new safer autocrlf handling\", files that have CRLF\nin the index are not normalized at commit when e.g. core.autocrl is set.\n\nWhenever a CLRF conversion is needed (or any filter us set), load the\nindex temporally, before calling convert_to_git()\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n builtin/blame.c               |  6 +++++-\n convert.c                     | 10 ++++++++++\n convert.h                     |  1 +\n t/t8003-blame-corner-cases.sh | 14 ++++++++++++++\n 4 files changed, 30 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex e982fb8..a219068 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2376,7 +2376,11 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,\n \t\tif (strbuf_read(&buf, 0, 0) < 0)\n \t\t\tdie_errno(\"failed to read from stdin\");\n \t}\n-\tconvert_to_git(path, buf.buf, buf.len, &buf, 0);\n+\tif (convert_needs_conversion(path)) {\n+\t\tread_cache();\n+\t\tconvert_to_git(path, buf.buf, buf.len, &buf, 0);\n+\t\tdiscard_cache();\n+\t}\n \torigin->file.ptr = buf.buf;\n \torigin->file.size = buf.len;\n \tpretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);\ndiff --git a/convert.c b/convert.c\nindex 4ed5d89..02c50da 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -903,6 +903,16 @@ const char *get_convert_attr_ascii(const char *path)\n \treturn \"\";\n }\n \n+int convert_needs_conversion(const char *path)\n+{\n+\tstruct conv_attrs ca;\n+\n+\tconvert_attrs(&ca, path);\n+\tif (ca.drv || ca.ident || ca.crlf_action != CRLF_BINARY)\n+\t\treturn 1;\n+\treturn 0;\n+}\n+\n int convert_to_git(const char *path, const char *src, size_t len,\n                    struct strbuf *dst, enum safe_crlf checksafe)\n {\ndiff --git a/convert.h b/convert.h\nindex ccf436b..ffd9c32 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -35,6 +35,7 @@ extern enum eol core_eol;\n extern const char *get_cached_convert_stats_ascii(const char *path);\n extern const char *get_wt_convert_stats_ascii(const char *path);\n extern const char *get_convert_attr_ascii(const char *path);\n+int convert_needs_conversion(const char *path);\n \n /* returns 1 if *dst was used */\n extern int convert_to_git(const char *path, const char *src, size_t len,\ndiff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh\nindex 6568429..a9b266f 100755\n--- a/t/t8003-blame-corner-cases.sh\n+++ b/t/t8003-blame-corner-cases.sh\n@@ -212,4 +212,18 @@ test_expect_success 'blame file with CRLF attributes text' '\n \tgrep \"A U Thor\" actual\n '\n \n+test_expect_success 'blame file with CRLF core.autocrlf=true' '\n+\tgit config core.autocrlf false &&\n+\tprintf \"testcase\\r\\n\" >crlfinrepo &&\n+\t>.gitattributes &&\n+\tgit add crlfinrepo &&\n+\tgit commit -m \"add crlfinrepo\" &&\n+\tgit config core.autocrlf true &&\n+\tmv crlfinrepo tmp &&\n+\tgit checkout crlfinrepo &&\n+\trm tmp &&\n+\tgit blame crlfinrepo >actual &&\n+\tgrep \"A U Thor\" actual\n+'\n+\n test_done\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"282477","messageId":"1459526913-20024-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v2 7/7] convert.c: more safer crlf handling with text attribute","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-01T16:08:33Z","receivedAt":"2016-04-01T16:08:33Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nA follow-up after a discussion how to fix the flaky execution\nof t0025, gmane/$284352.\n\nThis patch extends the work done in commit c480539:\n\"Make it work also for un-normalized repositories\". Make sure that CRLF\ncan be converted round trip, or don't convert them at all.\n\nThe old handling would treat a file as unchanged after checkout,\nas long as it is not touched in the work tree and mtime matches the value\nrecorded in the index.\nWhen the mtime is changed in the working tree, or the inode is changed,\nthe file is reported as modified.\n\nThe following sequence is now handled reproducable:\n$ git init\n$ printf \"line1\\r\\n\" >file.bat\n$ git add file.bat\n$ git commit -m \"Add file with CRLF\" file.bat\n$ echo \"*.bat text eol=crlf\" >.gitattributes\n$ git commit -m \"bat files should have CRLF\"\n$ git status\n # nothing to commit, working directory clean\n$ git push <upstream>\n$ printf \"newline\\r\\n\" >>file.bat\n$ mv file.bat file.sav\n$ git checkout file.bat\n$ git status\n #modified:   file.bat\n\nThe new handling makes sure that after running \"git reset --hard\".\n\"git status\" reports the working tree as clean regarding CRLF conversion.\nIt makes sure that the Git-internal eol conversion is\ndoing roundtrip. A user can still write an external smudge/clean filter\noutside Git, which doesn't do a roundtrip and the working directory is\nnot clean.\n\nThe functionality of has_cr_in_index() is turned into has_crlf_in_index(),\nand the function is integrated into would_convert_crlf_at_commit().\n\nCheck for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR\nis no longer used and removed, as well as \"lonecr\" in struct text_stat.\n\nRewrite check_safe_crlf() in convert.c to simulate checkin-checkout,\nto detect whether any line endings are converted.\n\nAdd a warning, similar to the CRLF-LF replacement, when a file is commited,\nand after the next checkout the line endings are not they should be.\n\nModify the lf_to_crlf_filter:\nFiles with LF are converted into CRLF, file with CRLF are not changed.\nFiles with mixed line endings are not converted, the filter fails, and Git\nfalls back to the non-streaming handling, see write_entry().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/gitattributes.txt |  16 ++-\n convert.c                       | 232 +++++++++++++++++++++++++---------------\n t/t0025-crlf-auto.sh            |   8 +-\n t/t0027-auto-crlf.sh            |  58 +++++-----\n 4 files changed, 191 insertions(+), 123 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex c2663c7..3caeb52 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'.\n `text`\n ^^^^^^\n \n-This attribute enables and controls end-of-line normalization.  When a\n+This attribute enables and controls end-of-line conversion.  When a\n text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol`\n Set::\n \n \tSetting the `text` attribute on a path enables end-of-line\n-\tnormalization and marks the path as a text file.  End-of-line\n+\tconversion and marks the path as a text file.  End-of-line\n \tconversion takes place without guessing the content type.\n+\tFiles that have been commited with CRLF before the text attribute\n+\tis set and commited are not normalized. No end-of-line conversion\n+\tis done at checkout or checkin.\n \n Unset::\n \n@@ -132,7 +135,8 @@ Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n \tend-of-line normalization.  If Git decides that the content is\n-\ttext, its line endings are normalized to LF on checkin.\n+\ttext, and the path has no CRLF in the index,\n+\tits line endings are converted to LF on checkin.\n \n Unspecified::\n \n@@ -147,8 +151,10 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It sets the `text` attribute,\n-unless `text=auto` is specified.\n+working directory.  It sets the `text` attribute, unless `text=auto`\n+is specified.\n+When the file had been commited with CRLF in the index, no conversion\n+is done at checkout or commit.\n \n Set to string value \"crlf\"::\n \ndiff --git a/convert.c b/convert.c\nindex 02c50da..1fddbe8 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -17,7 +17,8 @@\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n-#define CONVERT_STAT_BITS_ANY_CR    0x8\n+\n+#define CONVERT_STAT_BITS_MIXED (CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF)\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -32,7 +33,7 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned stat_bits, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonelf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n@@ -48,13 +49,10 @@ static void do_gather_stats(const char *buf, unsigned long size,\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n-\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n-\t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n \t\t\t} else {\n-\t\t\t\tstats->lonecr++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t}\n \t\t\tcontinue;\n@@ -136,7 +134,7 @@ static unsigned get_convert_stats_sha1(const char *path,\n \t\tif (!readlen)\n \t\t\tbreak;\n \t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n-\t\tif (stats.stat_bits & earlyout)\n+\t\tif ((stats.stat_bits & earlyout) == earlyout)\n \t\t\tbreak; /* We found what we have been searching for */\n \t}\n close_and_exit_i:\n@@ -147,11 +145,9 @@ close_and_exit_i:\n \n static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n-\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats & mask) {\n+\tswitch (convert_stats) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -163,7 +159,17 @@ static const char *convert_stats_ascii(unsigned convert_stats)\n \t}\n }\n \n-static unsigned get_convert_stats_wt(const char *path)\n+const char *get_cached_convert_stats_ascii(const char *path)\n+{\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(path,\n+\t\t\t\t\t       get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n+}\n+\n+const char *get_wt_convert_stats_ascii(const char *path)\n {\n \tstruct text_stat stats;\n \tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n@@ -185,24 +191,7 @@ static unsigned get_convert_stats_wt(const char *path)\n \t}\n \tclose(fd);\n \tconvert_nonprintable(&stats);\n-\treturn stats.stat_bits;\n-}\n-\n-const char *get_cached_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n-\tconvert_stats = get_convert_stats_sha1(path,\n-\t\t\t\t\t       get_sha1_from_cache(path),\n-\t\t\t\t\t       earlyout);\n-\treturn convert_stats_ascii(convert_stats);\n-}\n-\n-const char *get_wt_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_wt(path);\n-\treturn convert_stats_ascii(convert_stats);\n+\treturn convert_stats_ascii(stats.stat_bits);\n }\n \n static int text_eol_is_crlf(void)\n@@ -241,44 +230,96 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \treturn core_eol;\n }\n \n+static int would_convert_lf_at_checkout(unsigned convert_stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tif (output_eol(crlf_action) != EOL_CRLF)\n+\t\treturn 0;\n+\n+\t/* No \"naked\" LF? Nothing to convert, regardless. */\n+\tif (!convert_stats & CONVERT_STAT_BITS_TXT_LF)\n+\t\treturn 0;\n+\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\t/* auto: binary files are not converted */\n+\t\tif (convert_stats & CONVERT_STAT_BITS_BIN)\n+\t\t\treturn 0;\n+\t}\n+\t/* If we have any CRLF line endings, we do not touch it */\n+\t/* This is the new safer autocrlf-handling */\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+\n+}\n+\n+static int would_convert_crlf_at_commit(const char * path,\n+\t\t\t\t\tconst struct text_stat *stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tunsigned stat_bits_index;\n+\t/* No CRLF? Nothing to convert, regardless. */\n+\tif (!(stats->stat_bits & CONVERT_STAT_BITS_TXT_CRLF))\n+\t\treturn 0;\n+\t/*\n+\t * If the file in the index has any CRLF in it, do not convert.\n+\t * This is the new safer autocrlf handling.\n+\t */\n+\tstat_bits_index = get_convert_stats_sha1(path,\n+\t\t\t\t\t\t get_sha1_from_cache(path),\n+\t\t\t\t\t\t CONVERT_STAT_BITS_TXT_CRLF);\n+\tif (stat_bits_index & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+}\n+\n static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n-                            struct text_stat *stats, enum safe_crlf checksafe)\n+\t\t\t    enum safe_crlf checksafe,\n+\t\t\t    unsigned convert_stats, unsigned new_convert_stats)\n {\n+\tenum eol new_eol = output_eol(crlf_action);\n+\tconst char *err_warn_msg = NULL;\n \tif (!checksafe)\n \t\treturn;\n-\n-\tif (output_eol(crlf_action) == EOL_LF) {\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n \t\t/*\n \t\t * CRLFs would not be restored by checkout:\n \t\t * check if we'd remove CRLFs\n \t\t */\n-\t\tif (stats->crlf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n-\t\t}\n-\t} else if (output_eol(crlf_action) == EOL_CRLF) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n+\t}\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_LF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_LF)) {\n \t\t/*\n \t\t * CRLFs would be added by checkout:\n \t\t * check if we have \"naked\" LFs\n \t\t */\n-\t\tif (stats->lonelf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n-\t\t}\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n+\t}\n+\tif ((new_convert_stats & CONVERT_STAT_BITS_MIXED) == CONVERT_STAT_BITS_MIXED)\n+\t\terr_warn_msg = \"mixed eol\";\n+\telse if (new_eol == EOL_LF && new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\terr_warn_msg = \"CRLF\";\n+\n+\tif (err_warn_msg) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"%s will be present after commit and checkout in %s.\",\n+\t\t\t\terr_warn_msg, path);\n+\t\telse\n+\t\t\tdie(\"%s will be present after commit and checkout in %s\",\n+\t\t\t    err_warn_msg, path);\n \t}\n-}\n-\n-static int has_cr_in_index(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_sha1(path,\n-\t\t\t\t\t       get_sha1_from_cache(path),\n-\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n-\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -287,7 +328,7 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n {\n \tstruct text_stat stats;\n \tchar *dst;\n-\n+\tint convert_crlf;\n \tif (crlf_action == CRLF_BINARY ||\n \t    (src && !len))\n \t\treturn 0;\n@@ -299,23 +340,36 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n-\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\t\t/*\n-\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t * This is the new safer autocrlf handling.\n-\t\t */\n-\t\tif (has_cr_in_index(path))\n-\t\t\treturn 0;\n+\t} else {\n+\t\tgather_stats(src, len, &stats, 0);\n \t}\n-\n-\tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n-\n-\t/* Optimization: No CRLF? Nothing to convert, regardless. */\n-\tif (!stats.crlf)\n+\tconvert_crlf = would_convert_crlf_at_commit(path, &stats, len,\n+\t\t\t\t\t\t    crlf_action);\n+\tif (checksafe) {\n+\t\tunsigned convert_stats = stats.stat_bits;\n+\t\tunsigned new_convert_stats = convert_stats;\n+\t\t/* Simulate commit */\n+\t\tif (convert_crlf &&\n+\t\t    (new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_LF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t}\n+\t\t/* Simulate checkout */\n+\t\tif (would_convert_lf_at_checkout(new_convert_stats,\n+\t\t\t\t\t\t len, crlf_action)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_LF;\n+\t\t}\n+\t\tcheck_safe_crlf(path, crlf_action, checksafe,\n+\t\t\t\tconvert_stats, new_convert_stats);\n+\t}\n+\tif (!convert_crlf)\n \t\treturn 0;\n \n \t/*\n@@ -329,7 +383,9 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (strbuf_avail(buf) + buf->len < len)\n \t\tstrbuf_grow(buf, len - buf->len);\n \tdst = buf->buf;\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n \t\t/*\n \t\t * If we guessed, we already know we rejected a file with\n \t\t * lone CR, and we can strip a CR without looking at what\n@@ -356,28 +412,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n-\n-\n-\tif (!len || output_eol(crlf_action) != EOL_CRLF)\n+\tunsigned earlyout = 0; /* Need to count lonelf */\n+\tif (!len)\n \t\treturn 0;\n \n \tgather_stats(src, len, &stats, earlyout);\n-\n-\t/* No \"naked\" LF? Nothing to convert, regardless. */\n-\tif (!stats.lonelf)\n+\tif (!would_convert_lf_at_checkout(stats.stat_bits,\n+\t\t\t\t\t  len, crlf_action))\n \t\treturn 0;\n \n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t/* This is the new safer autocrlf-handling */\n-\t\tif (stats.lonecr || stats.crlf )\n-\t\t\treturn 0;\n-\n-\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n-\t\t\treturn 0;\n-\t}\n-\n \t/* are we \"faking\" in place editing ? */\n \tif (src == buf->buf)\n \t\tto_free = strbuf_detach(buf, NULL);\n@@ -1079,6 +1122,8 @@ int is_null_stream_filter(struct stream_filter *filter)\n struct lf_to_crlf_filter {\n \tstruct stream_filter filter;\n \tunsigned has_held:1;\n+\tunsigned expanded_loneLF:1;\n+\tunsigned had_CRLF:1;\n \tchar held;\n };\n \n@@ -1119,7 +1164,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \t\t\tchar ch = input[i];\n \n \t\t\tif (ch == '\\n') {\n-\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\tif (!lf_to_crlf->had_CRLF) {\n+\t\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\t\tlf_to_crlf->expanded_loneLF = 1;\n+\t\t\t\t}\n+\t\t\t\tif (was_cr)\n+\t\t\t\t\tlf_to_crlf->had_CRLF = 1;\n \t\t\t} else if (was_cr) {\n \t\t\t\t/*\n \t\t\t\t * Previous round saw CR and it is not followed\n@@ -1148,6 +1198,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \n \t\t\twas_cr = 0;\n \t\t\toutput[o++] = ch;\n+\t\t\tif (lf_to_crlf->expanded_loneLF &&\n+\t\t\t    lf_to_crlf->had_CRLF) {\n+\t\t\t\t/*\n+\t\t\t\t * Mixed EOL, round trip not possible.\n+\t\t\t\t */\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n \t\t}\n \n \t\t*osize_p -= o;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex d0bee08..b5f93e2 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n+test_expect_success 'crlf=true causes a CRLF file not to be normalized' '\n \n \t# Backwards compatibility check\n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n-test_expect_success 'text=true causes a CRLF file to be normalized' '\n+test_expect_success 'text=true causes a CRLF file not to be normalized' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \techo \"CRLFonly text\" > .gitattributes &&\n@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 86175cf..71ca1aa 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -71,10 +71,14 @@ check_warning () {\n \tcase \"$1\" in\n \tLF_CRLF) echo \"warning: LF will be replaced by CRLF\" >\"$2\".expect ;;\n \tCRLF_LF) echo \"warning: CRLF will be replaced by LF\" >\"$2\".expect ;;\n+\tCRLF)    echo \"warning: CRLF will be present after commit and checkout\" >\"$2\".expect ;;\n+\tmixed)   echo \"warning: mixed eol will be present after commit and checkout\" >\"$2\".expect ;;\n \t'')\t                                                 >\"$2\".expect ;;\n \t*) echo >&2 \"Illegal 1\": \"$1\" ; return false ;;\n \tesac\n-\tgrep \"will be replaced by\" \"$2\" | sed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" | uniq  >\"$2\".actual\n+\tegrep \"will be replaced by|will be present after commit\" \"$2\" |\n+\t\tsed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" |\n+\t\tuniq  >\"$2\".actual\n \ttest_cmp \"$2\".expect \"$2\".actual\n }\n \n@@ -354,7 +358,7 @@ else\n \tWAMIX=CRLF_LF\n fi\n \n-#                         attr   LF        CRLF      CRLFmixLF LFmixCR   CRLFNUL\n+#                               attr   LF        CRLF      CRLFmixLF LFmixCR   CRLFNUL\n test_expect_success 'commit files empty attr' '\n \tcommit_check_warn false \"\"     \"\"        \"\"        \"\"        \"\"        \"\" &&\n \tcommit_check_warn true  \"\"     \"LF_CRLF\" \"\"        \"LF_CRLF\" \"\"        \"\" &&\n@@ -391,30 +395,32 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+#                 attr    aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   CRLF      mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n for crlf in true false input;\n do\n+#                    attr aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n-\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf      $crlf   \"\"        CRLF      mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf    $crlf   LF_CRLF   \"\"        mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO text  lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO text  crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n done\n \n-commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n-commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n+#                  attr   aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   CRLF      mixed       \"$WILC\"     CRLF\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF      mixed       \"\"          CRLF\n \n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n@@ -455,9 +461,9 @@ do\n \tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n@@ -478,12 +484,10 @@ done\n \n if test_have_prereq NATIVE_CRLF\n then\n-MIX_CRLF_LF=CRLF\n MIX_LF_CR=CRLF_mix_CR\n NL=CRLF\n LFNUL=CRLF_nul\n else\n-MIX_CRLF_LF=CRLF_mix_LF\n MIX_LF_CR=LF_mix_CR\n NL=LF\n LFNUL=LF_nul\n@@ -503,20 +507,20 @@ do\n \t\t\tcheckout_files \"-text\" \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\tcheckout_files \"-text\" \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\tcheckout_files \"text\"  \"$id\" \"lf\"   \"$crlf\"  \"$ceol\"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files \"text\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files \"text\"  \"$id\" \"crlf\" \"$crlf\"  \"$ceol\"    CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\tdone\n \tdone\n \t# text: core.autocrlf=false uses core.eol\n-\tcheckout_files \"text\"  \"$id\"  \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  crlf     CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \tcheckout_files \"text\"  \"$id\"  \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files \"text\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\"  \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  \"\"       $NL   CRLF  CRLF_mix_LF  $MIX_LF_CR   $LFNUL\n+\tcheckout_files \"text\"  \"$id\"  \"\"    false  native   $NL   CRLF  CRLF_mix_LF  $MIX_LF_CR   $LFNUL\n \n \tfor ceol in \"\" lf crlf native;\n \tdo\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files \"text\"  \"$id\"  \"\"    true   \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tcheckout_files \"text\"  \"$id\"  \"\"    true   \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n \t\tcheckout_files \"text\"  \"$id\"  \"\"    input  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tcheckout_files \"auto\"  \"$id\"  \"\"    input  \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"282507","messageId":"xmqqio01gedt.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1459526906-19868-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v2 3/7] Allow core.autocrlf=input and core.eol=crlf","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-01T22:20:30Z","receivedAt":"2016-04-01T22:20:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> Commit  942e77 \"Add \"core.eol\" config variable\" adds a condition to\n> the config parser: core.autocrlf=input is not allowed together with\n> core.eol=crlf.\n>\n> This may lead to unnecessary problems, when config files are parsed:\n> A global config file sets core.autocrlf=input,\n> the repo local config file sets is own configuration: core.eol=crlf\n\nThis paragraph is unparsable.  Do you mean\n\n\tWhen the global configuration file sets core.autocrlf=input\n        and the repository local one sets core.eol=crlf, they violate\n        this condition and triggers an error when the configuration\n        is read.\n\nI think that is the designed behaviour, so it is not \"a problem\" at\nall, and an example that makes them come from two different sources\nof configuration is a red herring.  The parser faithfully implement\nthe policy that the combination is invalid.\n\nThe \"problem\" is in the policy itself, which you address below.\n\n> There is no need to prevent combinations in config.c, in any case\n> core.autocrlf overrides core.eol.\n\nSo\n\n        Even though the configuration parser errors out when\n        core.autocrlf is set to 'input' when core.eol is set to\n        'crlf', there is no need to do so, because the core.autocrlf\n        setting trumps core.eol.\n\nor something like that, perhaps?\n\n> Allow all combinations of core.crlf and core.eol and document\n> that core.autocrlf overrides core.eol.\n\nThat is a good change.\n\n> Signed-off-by: Torsten Bögershausen <tboegi@web.de>\n> ---\n>  Documentation/config.txt | 6 +++---\n>  config.c                 | 4 ----\n>  2 files changed, 3 insertions(+), 7 deletions(-)\n>\n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> index 2cd6bdd..4a27ad4 100644\n> --- a/Documentation/config.txt\n> +++ b/Documentation/config.txt\n> @@ -337,9 +337,9 @@ core.quotePath::\n>  \n>  core.eol::\n>  \tSets the line ending type to use in the working directory for\n> -\tfiles that have the `text` property set.  Alternatives are\n> -\t'lf', 'crlf' and 'native', which uses the platform's native\n> -\tline ending.  The default value is `native`.  See\n> +\tfiles that have the `text` property set when core.autocrlf is false.\n> +\tAlternatives are 'lf', 'crlf' and 'native', which uses the platform's\n> +\tnative line ending.  The default value is `native`.  See\n>  \tlinkgit:gitattributes[5] for more information on end-of-line\n>  \tconversion.\n>  \n> diff --git a/config.c b/config.c\n> index 9ba40bc..a6adc8b 100644\n> --- a/config.c\n> +++ b/config.c\n> @@ -803,8 +803,6 @@ static int git_default_core_config(const char *var, const char *value)\n>  \n>  \tif (!strcmp(var, \"core.autocrlf\")) {\n>  \t\tif (value && !strcasecmp(value, \"input\")) {\n> -\t\t\tif (core_eol == EOL_CRLF)\n> -\t\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n>  \t\t\tauto_crlf = AUTO_CRLF_INPUT;\n>  \t\t\treturn 0;\n>  \t\t}\n> @@ -830,8 +828,6 @@ static int git_default_core_config(const char *var, const char *value)\n>  \t\t\tcore_eol = EOL_NATIVE;\n>  \t\telse\n>  \t\t\tcore_eol = EOL_UNSET;\n> -\t\tif (core_eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)\n> -\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n>  \t\treturn 0;\n>  \t}\n"},{"id":"282508","messageId":"xmqqegapgea0.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1459526908-19907-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v2 4/7] t0027: TC for combined attributes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-01T22:22:47Z","receivedAt":"2016-04-01T22:22:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> +for crlf in true false input;\n\nStyle: lose the ';' at the end (there may be other instances of the\nsame).\n"},{"id":"282509","messageId":"xmqqa8ldge68.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1459526909-19946-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v2 5/7] CRLF: unify the \"auto\" handling","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-01T22:25:03Z","receivedAt":"2016-04-01T22:25:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> Make .gitattributes \"* text=auto eol=crlf\" to do the same as\n> setting core.autocrlf=true and \"* text=auto eol=crlf\" the same\n> as core.autocrlf=input\n\n\"Earlier we didn't do so and instead did X, which was not great\nbecause it caused symptom Y and Z\"\n\nwould be necessary for future readers to understand why the above\nchange is a good idea.\n"},{"id":"282510","messageId":"xmqq60w1gdyr.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1459526911-19985-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v2 6/7] correct blame for files commited with CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-01T22:29:32Z","receivedAt":"2016-04-01T22:29:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> Whenever a CLRF conversion is needed (or any filter us set), load the\n> index temporally, before calling convert_to_git()\n\nI am not sure if this is needed.  We should just do read_cache()\nunconditionally at the beginning of fake_working_tree_commit(),\nwithout even discarding it.  Most Git commands that work on the\nworking tree files follow that pattern, and I do not think the\n\"optimization\" this patch does over that simple pattern, while it\nmay be nice, is an unnecessary complication.\n\nBy the way, thanks for pushing back in the [v1 6/7] discussion\nthread to show me where convert_to_git() was failing.\n\n> Signed-off-by: Torsten Bögershausen <tboegi@web.de>\n> ---\n>  builtin/blame.c               |  6 +++++-\n>  convert.c                     | 10 ++++++++++\n>  convert.h                     |  1 +\n>  t/t8003-blame-corner-cases.sh | 14 ++++++++++++++\n>  4 files changed, 30 insertions(+), 1 deletion(-)\n>\n> diff --git a/builtin/blame.c b/builtin/blame.c\n> index e982fb8..a219068 100644\n> --- a/builtin/blame.c\n> +++ b/builtin/blame.c\n> @@ -2376,7 +2376,11 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,\n>  \t\tif (strbuf_read(&buf, 0, 0) < 0)\n>  \t\t\tdie_errno(\"failed to read from stdin\");\n>  \t}\n> -\tconvert_to_git(path, buf.buf, buf.len, &buf, 0);\n> +\tif (convert_needs_conversion(path)) {\n> +\t\tread_cache();\n> +\t\tconvert_to_git(path, buf.buf, buf.len, &buf, 0);\n> +\t\tdiscard_cache();\n> +\t}\n>  \torigin->file.ptr = buf.buf;\n>  \torigin->file.size = buf.len;\n>  \tpretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);\n> diff --git a/convert.c b/convert.c\n> index 4ed5d89..02c50da 100644\n> --- a/convert.c\n> +++ b/convert.c\n> @@ -903,6 +903,16 @@ const char *get_convert_attr_ascii(const char *path)\n>  \treturn \"\";\n>  }\n>  \n> +int convert_needs_conversion(const char *path)\n> +{\n> +\tstruct conv_attrs ca;\n> +\n> +\tconvert_attrs(&ca, path);\n> +\tif (ca.drv || ca.ident || ca.crlf_action != CRLF_BINARY)\n> +\t\treturn 1;\n> +\treturn 0;\n> +}\n> +\n>  int convert_to_git(const char *path, const char *src, size_t len,\n>                     struct strbuf *dst, enum safe_crlf checksafe)\n>  {\n> diff --git a/convert.h b/convert.h\n> index ccf436b..ffd9c32 100644\n> --- a/convert.h\n> +++ b/convert.h\n> @@ -35,6 +35,7 @@ extern enum eol core_eol;\n>  extern const char *get_cached_convert_stats_ascii(const char *path);\n>  extern const char *get_wt_convert_stats_ascii(const char *path);\n>  extern const char *get_convert_attr_ascii(const char *path);\n> +int convert_needs_conversion(const char *path);\n>  \n>  /* returns 1 if *dst was used */\n>  extern int convert_to_git(const char *path, const char *src, size_t len,\n> diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh\n> index 6568429..a9b266f 100755\n> --- a/t/t8003-blame-corner-cases.sh\n> +++ b/t/t8003-blame-corner-cases.sh\n> @@ -212,4 +212,18 @@ test_expect_success 'blame file with CRLF attributes text' '\n>  \tgrep \"A U Thor\" actual\n>  '\n>  \n> +test_expect_success 'blame file with CRLF core.autocrlf=true' '\n> +\tgit config core.autocrlf false &&\n> +\tprintf \"testcase\\r\\n\" >crlfinrepo &&\n> +\t>.gitattributes &&\n> +\tgit add crlfinrepo &&\n> +\tgit commit -m \"add crlfinrepo\" &&\n> +\tgit config core.autocrlf true &&\n> +\tmv crlfinrepo tmp &&\n> +\tgit checkout crlfinrepo &&\n> +\trm tmp &&\n> +\tgit blame crlfinrepo >actual &&\n> +\tgrep \"A U Thor\" actual\n> +'\n> +\n>  test_done\n"},{"id":"282560","messageId":"5700E26E.30409@web.de","threadId":"41391","inReplyTo":"xmqq60w1gdyr.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 6/7] correct blame for files commited with CRLF","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-04-03T09:29:18Z","receivedAt":"2016-04-03T09:29:18Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"Thanks for all the comments.\nI just reallized that t6038 is broken, which I didn't notice before :-(\n\n\nPlease feel free to kick out\ntb/safe-crlf-output-fix from pu,\n\nuntil I have looked into the breakage and found a fix.\n"},{"id":"282726","messageId":"1459884234-13026-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v1] correct blame for files commited with CRLF","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-05T19:23:54Z","receivedAt":"2016-04-05T19:23:54Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\ngit blame reports lines as not \"Not Committed Yet\" when they have\nCRLF in the index, CRLF in the worktree and core.autocrlf is true.\n\nSince commit c48053 \"new safer autocrlf handling\", files that have CRLF\nin the index are not normalized at commit when core.autocrl is set.\n\nAdd a call to read_cache() early in fake_working_tree_commit(),\nbefore calling convert_to_git().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n This fix is completely independent of the rest of the series,\n so break out 6/7 from tb/safe-crlf-output.\n The rest of the series will be send in a couple of days, some\n rework is needed.\nbuiltin/blame.c               |  1 +\n t/t8003-blame-corner-cases.sh | 14 ++++++++++++++\n 2 files changed, 15 insertions(+)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex e982fb8..21f42b0 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2307,6 +2307,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,\n \tunsigned mode;\n \tstruct strbuf msg = STRBUF_INIT;\n \n+\tread_cache();\n \ttime(&now);\n \tcommit = alloc_commit_node();\n \tcommit->object.parsed = 1;\ndiff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh\nindex 6568429..a9b266f 100755\n--- a/t/t8003-blame-corner-cases.sh\n+++ b/t/t8003-blame-corner-cases.sh\n@@ -212,4 +212,18 @@ test_expect_success 'blame file with CRLF attributes text' '\n \tgrep \"A U Thor\" actual\n '\n \n+test_expect_success 'blame file with CRLF core.autocrlf=true' '\n+\tgit config core.autocrlf false &&\n+\tprintf \"testcase\\r\\n\" >crlfinrepo &&\n+\t>.gitattributes &&\n+\tgit add crlfinrepo &&\n+\tgit commit -m \"add crlfinrepo\" &&\n+\tgit config core.autocrlf true &&\n+\tmv crlfinrepo tmp &&\n+\tgit checkout crlfinrepo &&\n+\trm tmp &&\n+\tgit blame crlfinrepo >actual &&\n+\tgrep \"A U Thor\" actual\n+'\n+\n test_done\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"282732","messageId":"xmqqoa9n22q1.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1459884234-13026-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v1] correct blame for files commited with CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-05T20:57:26Z","receivedAt":"2016-04-05T20:57:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n>  This fix is completely independent of the rest of the series,\n>  so break out 6/7 from tb/safe-crlf-output.\n\nSounds sensible.  It is somewhat sad and strange that we need to\nrely on what is in the index to show the current working tree state,\nbut this makes the things more consistent.\n\nWill queue.  Thanks.\n\n> builtin/blame.c               |  1 +\n>  t/t8003-blame-corner-cases.sh | 14 ++++++++++++++\n>  2 files changed, 15 insertions(+)\n>\n> diff --git a/builtin/blame.c b/builtin/blame.c\n> index e982fb8..21f42b0 100644\n> --- a/builtin/blame.c\n> +++ b/builtin/blame.c\n> @@ -2307,6 +2307,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,\n>  \tunsigned mode;\n>  \tstruct strbuf msg = STRBUF_INIT;\n>  \n> +\tread_cache();\n>  \ttime(&now);\n>  \tcommit = alloc_commit_node();\n>  \tcommit->object.parsed = 1;\n> diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh\n> index 6568429..a9b266f 100755\n> --- a/t/t8003-blame-corner-cases.sh\n> +++ b/t/t8003-blame-corner-cases.sh\n> @@ -212,4 +212,18 @@ test_expect_success 'blame file with CRLF attributes text' '\n>  \tgrep \"A U Thor\" actual\n>  '\n>  \n> +test_expect_success 'blame file with CRLF core.autocrlf=true' '\n> +\tgit config core.autocrlf false &&\n> +\tprintf \"testcase\\r\\n\" >crlfinrepo &&\n> +\t>.gitattributes &&\n> +\tgit add crlfinrepo &&\n> +\tgit commit -m \"add crlfinrepo\" &&\n> +\tgit config core.autocrlf true &&\n> +\tmv crlfinrepo tmp &&\n> +\tgit checkout crlfinrepo &&\n> +\trm tmp &&\n> +\tgit blame crlfinrepo >actual &&\n> +\tgrep \"A U Thor\" actual\n> +'\n> +\n>  test_done\n"},{"id":"282735","messageId":"xmqqegaj220t.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1459884234-13026-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v1] correct blame for files commited with CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-05T21:12:34Z","receivedAt":"2016-04-05T21:12:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> +\tgit config core.autocrlf true &&\n> +\tmv crlfinrepo tmp &&\n> +\tgit checkout crlfinrepo &&\n> +\trm tmp &&\n\nWhy not just \"rm -f crlfinrepo\" and \"git checkout crlfinrepo\"?\n\n> +\tgit blame crlfinrepo >actual &&\n> +\tgrep \"A U Thor\" actual\n> +'\n> +\n>  test_done\n"},{"id":"282742","messageId":"57048DED.9000904@web.de","threadId":"41391","inReplyTo":"xmqqegaj220t.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v1] correct blame for files commited with CRLF","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-04-06T04:17:49Z","receivedAt":"2016-04-06T04:17:49Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 05.04.16 23:12, Junio C Hamano wrote:\n> tboegi@web.de writes:\n> \n>> +\tgit config core.autocrlf true &&\n>> +\tmv crlfinrepo tmp &&\n>> +\tgit checkout crlfinrepo &&\n>> +\trm tmp &&\n> \n> Why not just \"rm -f crlfinrepo\" and \"git checkout crlfinrepo\"?\nThe intention was to get a new inode number, which marks the file\nin the working tree as modified, regardless of mtime.\n"},{"id":"283786","messageId":"1461072276-2755-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v5 1/4] t0027: Make more reliable","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-19T13:24:36Z","receivedAt":"2016-04-19T13:24:36Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nMake the commit_chk_wrnNNO test in t0027 more reliable:\nWhen the attributes of a commited file are changed and the file is otherwise\nunchanged, Git may not detect that the next commit may need to treat the\nfile as changed.\nThis happens when lstat() doesn't detect a change, since neither inode,\nmtime nor size are changed.\n\nAdd a singe \"Z\" character to change the file size.\nIgnore it when comparing the files later.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\nChanges against the last round:\n- Add this commit, since t0027 become shaky\n- Add bugfix in 4/4\n- Remove the non-normalizing changes, they will be part of a different\n  series. Mainly because t6038 needs improvements, and ce_compare_data()\n  in read_cache.c needs to learn to run convert_to_git()\n t/t0027-auto-crlf.sh | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex f33962b..9fe539b 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -12,7 +12,7 @@ fi\n \n compare_files () {\n \ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n-\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n+\ttr '\\015\\000' QN <\"$2\" | tr -d 'Z' >\"$2\".actual &&\n \ttest_cmp \"$1\".expect \"$2\".actual &&\n \trm \"$1\".expect \"$2\".actual\n }\n@@ -114,6 +114,7 @@ commit_chk_wrnNNO () {\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n \t\tcp $f $fname &&\n+\t\tprintf Z >>\"$fname\" &&\n \t\tgit -c core.autocrlf=$crlf add $fname 2>/dev/null &&\n \t\tgit -c core.autocrlf=$crlf commit -m \"commit_$fname\" $fname >\"${pfx}_$f.err\" 2>&1\n \tdone\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"283787","messageId":"1461072360-2796-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v5 2/4] convert: allow core.autocrlf=input and core.eol=crlf","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-19T13:26:00Z","receivedAt":"2016-04-19T13:26:00Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nEven though the configuration parser errors out when core.autocrlf\nis set to 'input' when core.eol is set to 'crlf', there is no need\nto do so, because the core.autocrlf setting trumps core.eol.\n\nAllow all combinations of core.crlf and core.eol and document\nthat core.autocrlf overrides core.eol.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt | 6 +++---\n config.c                 | 4 ----\n 2 files changed, 3 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 42d2b50..155f988 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -337,9 +337,9 @@ core.quotePath::\n \n core.eol::\n \tSets the line ending type to use in the working directory for\n-\tfiles that have the `text` property set.  Alternatives are\n-\t'lf', 'crlf' and 'native', which uses the platform's native\n-\tline ending.  The default value is `native`.  See\n+\tfiles that have the `text` property set when core.autocrlf is false.\n+\tAlternatives are 'lf', 'crlf' and 'native', which uses the platform's\n+\tnative line ending.  The default value is `native`.  See\n \tlinkgit:gitattributes[5] for more information on end-of-line\n \tconversion.\n \ndiff --git a/config.c b/config.c\nindex 4c92699..c8ac9c2 100644\n--- a/config.c\n+++ b/config.c\n@@ -803,8 +803,6 @@ static int git_default_core_config(const char *var, const char *value)\n \n \tif (!strcmp(var, \"core.autocrlf\")) {\n \t\tif (value && !strcasecmp(value, \"input\")) {\n-\t\t\tif (core_eol == EOL_CRLF)\n-\t\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\t\tauto_crlf = AUTO_CRLF_INPUT;\n \t\t\treturn 0;\n \t\t}\n@@ -830,8 +828,6 @@ static int git_default_core_config(const char *var, const char *value)\n \t\t\tcore_eol = EOL_NATIVE;\n \t\telse\n \t\t\tcore_eol = EOL_UNSET;\n-\t\tif (core_eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)\n-\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\treturn 0;\n \t}\n \n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"283784","messageId":"1461072362-2835-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v5 3/4] t0027: test cases for combined attributes","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-19T13:26:02Z","receivedAt":"2016-04-19T13:26:02Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nAdd more test cases for the not normalized files (\"NNO\").  The\n\"text\" attribute is most important, use it as the first parameter.\n\"ident\", if set, is the second paramater followed by the eol\nattribute.  The eol attribute overrides core.autocrlf, which\noverrides core.eol.\nindent is not yet uses, this will be done in the next commit.\n\nUse loops to test more combinations of attributes, like\n\"* text eol=crlf\" or especially \"*text=auto eol=crlf\".\n\nCurrently \"* text=auto eol=lf\" does the same as \"* text eol=lf\",\nas the eol attribute overrides \"text=auto\", this will change in\nfuture.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n t/t0027-auto-crlf.sh | 298 ++++++++++++++++++++++-----------------------------\n 1 file changed, 129 insertions(+), 169 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 9fe539b..fd5e326 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -52,14 +52,17 @@ create_gitattributes () {\n create_NNO_files () {\n \tfor crlf in false true input\n \tdo\n-\t\tfor attr in \"\" auto text -text lf crlf\n+\t\tfor attr in \"\" auto text -text\n \t\tdo\n-\t\t\tpfx=NNO_${crlf}_attr_${attr} &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tfor aeol in \"\" lf crlf\n+\t\t\tdo\n+\t\t\t\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tdone\n \t\tdone\n \tdone\n }\n@@ -100,16 +103,17 @@ commit_check_warn () {\n }\n \n commit_chk_wrnNNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfwarn=$3\n-\tcrlfwarn=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfwarn=$1 ; shift\n+\tcrlfwarn=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n \t#Commit files on top of existing file\n-\tcreate_gitattributes \"$attr\" &&\n+\tcreate_gitattributes \"$attr\" $aeol &&\n \tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n@@ -122,19 +126,19 @@ commit_chk_wrnNNO () {\n \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n \t'\n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF\" '\n \t\tcheck_warning \"$crlfwarn\" ${pfx}_CRLF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_mix_LF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_mix_LF\" '\n \t\tcheck_warning \"$lfmixcrlf\" ${pfx}_CRLF_mix_LF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF_mix_cr\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf LF_mix_cr\" '\n \t\tcheck_warning \"$lfmixcr\" ${pfx}_LF_mix_CR.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_nul\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_nul\" '\n \t\tcheck_warning \"$crlfnul\" ${pfx}_CRLF_nul.err\n \t'\n }\n@@ -163,6 +167,7 @@ stats_ascii () {\n \n # contruct the attr/ returned by git ls-files --eol\n # Take none (=empty), one or two args\n+# convert.c: eol=XX overrides text=auto\n attr_ascii () {\n \tcase $1,$2 in\n \t-text,*)   echo \"-text\" ;;\n@@ -170,8 +175,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text=auto eol=lf\" ;;\n-\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n+\tauto,lf)   echo \"text eol=lf\" ;;\n+\tauto,crlf) echo \"text eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -196,28 +201,29 @@ check_files_in_repo () {\n }\n \n check_in_repo_NNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfname=$3\n-\tcrlfname=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}_\n-\ttest_expect_success \"compare_files $lfname ${pfx}LF.txt\" '\n-\t\tcompare_files $lfname ${pfx}LF.txt\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfname=$1 ; shift\n+\tcrlfname=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\ttest_expect_success \"compare_files $lfname ${pfx}_LF.txt\" '\n+\t\tcompare_files $lfname ${pfx}_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfname ${pfx}CRLF.txt\" '\n-\t\tcompare_files $crlfname ${pfx}CRLF.txt\n+\ttest_expect_success \"compare_files $crlfname ${pfx}_CRLF.txt\" '\n+\t\tcompare_files $crlfname ${pfx}_CRLF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\" '\n-\t\tcompare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\n+\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\" '\n+\t\tcompare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcr ${pfx}LF_mix_CR.txt\" '\n-\t\tcompare_files $lfmixcr ${pfx}LF_mix_CR.txt\n+\ttest_expect_success \"compare_files $lfmixcr ${pfx}_LF_mix_CR.txt\" '\n+\t\tcompare_files $lfmixcr ${pfx}_LF_mix_CR.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfnul ${pfx}CRLF_nul.txt\" '\n-\t\tcompare_files $crlfnul ${pfx}CRLF_nul.txt\n+\ttest_expect_success \"compare_files $crlfnul ${pfx}_CRLF_nul.txt\" '\n+\t\tcompare_files $crlfnul ${pfx}_CRLF_nul.txt\n \t'\n }\n \n@@ -232,7 +238,7 @@ checkout_files () {\n \tlfmixcrlf=$1 ; shift\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n-\tcreate_gitattributes \"$attr\" \"$ident\" &&\n+\tcreate_gitattributes \"$attr\" $ident $aeol &&\n \tgit config core.autocrlf $crlf &&\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n@@ -245,7 +251,7 @@ checkout_files () {\n \t\tfi\n \tdone\n \n-\ttest_expect_success \"ls-files --eol attr=$attr $ident $aeol core.autocrlf=$crlf core.eol=$ceol\" '\n+\ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n \t\ttest_when_finished \"rm expect actual\" &&\n \t\tsort <<-EOF >expect &&\n \t\ti/crlf w/$(stats_ascii $crlfname) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF.txt\n@@ -260,19 +266,19 @@ checkout_files () {\n \t\tsort >actual &&\n \t\ttest_cmp expect actual\n \t'\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n \t\tcompare_ws_file $pfx $lfname    crlf_false_attr__LF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n \t\tcompare_ws_file $pfx $crlfname  crlf_false_attr__CRLF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n \t\tcompare_ws_file $pfx $lfmixcrlf crlf_false_attr__CRLF_mix_LF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n \t\tcompare_ws_file $pfx $lfmixcr   crlf_false_attr__LF_mix_CR.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n \t\tcompare_ws_file $pfx $crlfnul   crlf_false_attr__LF_nul.txt\n \t\"\n }\n@@ -386,31 +392,31 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                       attr   LF        CRLF      CRLFmixLF \t LF_mix_CR   CRLFNUL\n-commit_chk_wrnNNO false \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"\"     \"LF_CRLF\" \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-\n+#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO false \"auto\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"auto\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"auto\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n \n-commit_chk_wrnNNO false \"text\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"$WILC\"   \t \"$WICL\"\n-commit_chk_wrnNNO true  \"text\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"text\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"CRLF_LF\"\n-\n-commit_chk_wrnNNO false \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-\n-commit_chk_wrnNNO false \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO true  \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO input \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n+for crlf in true false input\n+do\n+\tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+done\n \n-commit_chk_wrnNNO false \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO true  \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n \n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n@@ -441,24 +447,20 @@ test_expect_success 'commit -text' '\n \tcheck_files_in_repo input \"-text\" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n '\n \n-#                       attr    LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLFNUL\n-check_in_repo_NNO false \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO true  \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO input \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-\n-check_in_repo_NNO false \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-\n+for crlf in true false input\n+do\n+\t#                 attr  aeol           LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLFNUL\n+\tcheck_in_repo_NNO \"\"    \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n # How to read the table below:\n@@ -490,89 +492,47 @@ LFNUL=LF_nul\n fi\n export CRLF_MIX_LF_CR MIX NL\n \n-checkout_files \"\"      \"\" \t \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   native   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   native   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\n-for id in \"\" ident;\n+# Same handling with and without ident\n+for id in \"\"\n do\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tfor ceol in lf crlf native\n+\tdo\n+\t\tfor crlf in true false input\n+\t\tdo\n+\t\t\t# -text overrides core.autocrlf and core.eol\n+\t\t\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n+\t\t\tcheckout_files -text \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files -text \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files -text \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\t# text\n+\t\t\tcheckout_files text  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\t# currently the same as text, eol=XXX\n+\t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tdone\n+\n+\t\t# core.autocrlf false, different core.eol\n+\t\tcheckout_files   \"\"    \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# core.autocrlf true\n+\t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# text: core.autocrlf = true overrides core.eol\n+\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t# text: core.autocrlf = input overrides core.eol\n+\t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# text=auto + eol=XXX\n+\tdone\n+\t# text: core.autocrlf=false uses core.eol\n+\tcheckout_files     text  \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\tcheckout_files     text  \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"283785","messageId":"1461072363-2874-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v5 4/4] convert.c: ident + core.autocrlf didn't work","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-19T13:26:03Z","receivedAt":"2016-04-19T13:26:03Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen the ident attributes is set, get_stream_filter() did not obey\ncore.autocrlf=true, and the file was checked out with LF.\n\nChange the rule when a streaming filter can be used:\n- if an external filter is specified, don't use a stream filter.\n- if the worktree eol is CRLF and \"auto\" is active, don't use a stream filter.\n- Otherwise the stream filter can be used.\n\nAdd test cases in t0027.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c            | 18 ++++++------------\n t/t0027-auto-crlf.sh |  2 +-\n 2 files changed, 7 insertions(+), 13 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex f524b8d..e8b0187 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1380,27 +1380,21 @@ static struct stream_filter *ident_filter(const unsigned char *sha1)\n struct stream_filter *get_stream_filter(const char *path, const unsigned char *sha1)\n {\n \tstruct conv_attrs ca;\n-\tenum crlf_action crlf_action;\n \tstruct stream_filter *filter = NULL;\n \n \tconvert_attrs(&ca, path);\n-\n \tif (ca.drv && (ca.drv->smudge || ca.drv->clean))\n-\t\treturn filter;\n+\t\treturn NULL;\n \n \tif (ca.ident)\n \t\tfilter = ident_filter(sha1);\n \n-\tcrlf_action = ca.crlf_action;\n-\n-\tif ((crlf_action == CRLF_BINARY) ||\n-\t\t\tcrlf_action == CRLF_AUTO_INPUT ||\n-\t\t\t(crlf_action == CRLF_TEXT_INPUT))\n-\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n-\n-\telse if (output_eol(crlf_action) == EOL_CRLF &&\n-\t\t !(crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_CRLF))\n+\tif (output_eol(ca.crlf_action) == EOL_CRLF) {\n+\t\tif (ca.crlf_action == CRLF_AUTO || ca.crlf_action == CRLF_AUTO_CRLF)\n+\t\t\treturn NULL;\n \t\tfilter = cascade_filter(filter, lf_to_crlf_filter());\n+\t} else\n+\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n \n \treturn filter;\n }\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex fd5e326..9372589 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -493,7 +493,7 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-for id in \"\"\n+for id in \"\" ident\n do\n \tfor ceol in lf crlf native\n \tdo\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"283854","messageId":"xmqq4maxz3lt.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1461072362-2835-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v5 3/4] t0027: test cases for combined attributes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-19T21:32:46Z","receivedAt":"2016-04-19T21:32:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> Add more test cases for the not normalized files (\"NNO\").  The\n> \"text\" attribute is most important, use it as the first parameter.\n> \"ident\", if set, is the second paramater followed by the eol\n> attribute.  The eol attribute overrides core.autocrlf, which\n> overrides core.eol.\n> indent is not yet uses, this will be done in the next commit.\n>\n> Use loops to test more combinations of attributes, like\n> \"* text eol=crlf\" or especially \"*text=auto eol=crlf\".\n>\n> Currently \"* text=auto eol=lf\" does the same as \"* text eol=lf\",\n> as the eol attribute overrides \"text=auto\", this will change in\n> future.\n\nWill change in future in what way?  In patch 5/4?\n\n>\n> Signed-off-by: Torsten Bögershausen <tboegi@web.de>\n> ---\n>  t/t0027-auto-crlf.sh | 298 ++++++++++++++++++++++-----------------------------\n>  1 file changed, 129 insertions(+), 169 deletions(-)\n>\n> diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\n> index 9fe539b..fd5e326 100755\n> --- a/t/t0027-auto-crlf.sh\n> +++ b/t/t0027-auto-crlf.sh\n> @@ -52,14 +52,17 @@ create_gitattributes () {\n>  create_NNO_files () {\n>  \tfor crlf in false true input\n>  \tdo\n> -\t\tfor attr in \"\" auto text -text lf crlf\n> +\t\tfor attr in \"\" auto text -text\n>  \t\tdo\n> -\t\t\tpfx=NNO_${crlf}_attr_${attr} &&\n> -\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n> -\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n> -\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n> -\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n> -\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n> +\t\t\tfor aeol in \"\" lf crlf\n> +\t\t\tdo\n> +\t\t\t\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n> +\t\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n> +\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n> +\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n> +\t\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n> +\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n> +\t\t\tdone\n>  \t\tdone\n>  \tdone\n>  }\n> @@ -100,16 +103,17 @@ commit_check_warn () {\n>  }\n>  \n>  commit_chk_wrnNNO () {\n> -\tcrlf=$1\n> -\tattr=$2\n> -\tlfwarn=$3\n> -\tcrlfwarn=$4\n> -\tlfmixcrlf=$5\n> -\tlfmixcr=$6\n> -\tcrlfnul=$7\n> -\tpfx=NNO_${crlf}_attr_${attr}\n> +\tattr=$1 ; shift\n> +\taeol=$1 ; shift\n> +\tcrlf=$1 ; shift\n> +\tlfwarn=$1 ; shift\n> +\tcrlfwarn=$1 ; shift\n> +\tlfmixcrlf=$1 ; shift\n> +\tlfmixcr=$1 ; shift\n> +\tcrlfnul=$1 ; shift\n> +\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n>  \t#Commit files on top of existing file\n> -\tcreate_gitattributes \"$attr\" &&\n> +\tcreate_gitattributes \"$attr\" $aeol &&\n>  \tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n>  \tdo\n>  \t\tfname=${pfx}_$f.txt &&\n> @@ -122,19 +126,19 @@ commit_chk_wrnNNO () {\n>  \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n>  \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n>  \t'\n> -\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF\" '\n> +\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF\" '\n>  \t\tcheck_warning \"$crlfwarn\" ${pfx}_CRLF.err\n>  \t'\n>  \n> -\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_mix_LF\" '\n> +\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_mix_LF\" '\n>  \t\tcheck_warning \"$lfmixcrlf\" ${pfx}_CRLF_mix_LF.err\n>  \t'\n>  \n> -\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF_mix_cr\" '\n> +\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf LF_mix_cr\" '\n>  \t\tcheck_warning \"$lfmixcr\" ${pfx}_LF_mix_CR.err\n>  \t'\n>  \n> -\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_nul\" '\n> +\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_nul\" '\n>  \t\tcheck_warning \"$crlfnul\" ${pfx}_CRLF_nul.err\n>  \t'\n>  }\n> @@ -163,6 +167,7 @@ stats_ascii () {\n>  \n>  # contruct the attr/ returned by git ls-files --eol\n>  # Take none (=empty), one or two args\n> +# convert.c: eol=XX overrides text=auto\n>  attr_ascii () {\n>  \tcase $1,$2 in\n>  \t-text,*)   echo \"-text\" ;;\n> @@ -170,8 +175,8 @@ attr_ascii () {\n>  \ttext,lf)   echo \"text eol=lf\" ;;\n>  \ttext,crlf) echo \"text eol=crlf\" ;;\n>  \tauto,)     echo \"text=auto\" ;;\n> -\tauto,lf)   echo \"text=auto eol=lf\" ;;\n> -\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n> +\tauto,lf)   echo \"text eol=lf\" ;;\n> +\tauto,crlf) echo \"text eol=crlf\" ;;\n>  \tlf,)       echo \"text eol=lf\" ;;\n>  \tcrlf,)     echo \"text eol=crlf\" ;;\n>  \t,) echo \"\" ;;\n> @@ -196,28 +201,29 @@ check_files_in_repo () {\n>  }\n>  \n>  check_in_repo_NNO () {\n> -\tcrlf=$1\n> -\tattr=$2\n> -\tlfname=$3\n> -\tcrlfname=$4\n> -\tlfmixcrlf=$5\n> -\tlfmixcr=$6\n> -\tcrlfnul=$7\n> -\tpfx=NNO_${crlf}_attr_${attr}_\n> -\ttest_expect_success \"compare_files $lfname ${pfx}LF.txt\" '\n> -\t\tcompare_files $lfname ${pfx}LF.txt\n> +\tattr=$1 ; shift\n> +\taeol=$1 ; shift\n> +\tcrlf=$1 ; shift\n> +\tlfname=$1 ; shift\n> +\tcrlfname=$1 ; shift\n> +\tlfmixcrlf=$1 ; shift\n> +\tlfmixcr=$1 ; shift\n> +\tcrlfnul=$1 ; shift\n> +\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n> +\ttest_expect_success \"compare_files $lfname ${pfx}_LF.txt\" '\n> +\t\tcompare_files $lfname ${pfx}_LF.txt\n>  \t'\n> -\ttest_expect_success \"compare_files $crlfname ${pfx}CRLF.txt\" '\n> -\t\tcompare_files $crlfname ${pfx}CRLF.txt\n> +\ttest_expect_success \"compare_files $crlfname ${pfx}_CRLF.txt\" '\n> +\t\tcompare_files $crlfname ${pfx}_CRLF.txt\n>  \t'\n> -\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\" '\n> -\t\tcompare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\n> +\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\" '\n> +\t\tcompare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\n>  \t'\n> -\ttest_expect_success \"compare_files $lfmixcr ${pfx}LF_mix_CR.txt\" '\n> -\t\tcompare_files $lfmixcr ${pfx}LF_mix_CR.txt\n> +\ttest_expect_success \"compare_files $lfmixcr ${pfx}_LF_mix_CR.txt\" '\n> +\t\tcompare_files $lfmixcr ${pfx}_LF_mix_CR.txt\n>  \t'\n> -\ttest_expect_success \"compare_files $crlfnul ${pfx}CRLF_nul.txt\" '\n> -\t\tcompare_files $crlfnul ${pfx}CRLF_nul.txt\n> +\ttest_expect_success \"compare_files $crlfnul ${pfx}_CRLF_nul.txt\" '\n> +\t\tcompare_files $crlfnul ${pfx}_CRLF_nul.txt\n>  \t'\n>  }\n>  \n> @@ -232,7 +238,7 @@ checkout_files () {\n>  \tlfmixcrlf=$1 ; shift\n>  \tlfmixcr=$1 ; shift\n>  \tcrlfnul=$1 ; shift\n> -\tcreate_gitattributes \"$attr\" \"$ident\" &&\n> +\tcreate_gitattributes \"$attr\" $ident $aeol &&\n>  \tgit config core.autocrlf $crlf &&\n>  \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n>  \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n> @@ -245,7 +251,7 @@ checkout_files () {\n>  \t\tfi\n>  \tdone\n>  \n> -\ttest_expect_success \"ls-files --eol attr=$attr $ident $aeol core.autocrlf=$crlf core.eol=$ceol\" '\n> +\ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n>  \t\ttest_when_finished \"rm expect actual\" &&\n>  \t\tsort <<-EOF >expect &&\n>  \t\ti/crlf w/$(stats_ascii $crlfname) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF.txt\n> @@ -260,19 +266,19 @@ checkout_files () {\n>  \t\tsort >actual &&\n>  \t\ttest_cmp expect actual\n>  \t'\n> -\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n> +\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n>  \t\tcompare_ws_file $pfx $lfname    crlf_false_attr__LF.txt\n>  \t\"\n> -\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n> +\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n>  \t\tcompare_ws_file $pfx $crlfname  crlf_false_attr__CRLF.txt\n>  \t\"\n> -\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n> +\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n>  \t\tcompare_ws_file $pfx $lfmixcrlf crlf_false_attr__CRLF_mix_LF.txt\n>  \t\"\n> -\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n> +\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n>  \t\tcompare_ws_file $pfx $lfmixcr   crlf_false_attr__LF_mix_CR.txt\n>  \t\"\n> -\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n> +\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n>  \t\tcompare_ws_file $pfx $crlfnul   crlf_false_attr__LF_nul.txt\n>  \t\"\n>  }\n> @@ -386,31 +392,31 @@ test_expect_success 'commit files attr=crlf' '\n>  \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n>  '\n>  \n> -#                       attr   LF        CRLF      CRLFmixLF \t LF_mix_CR   CRLFNUL\n> -commit_chk_wrnNNO false \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n> -commit_chk_wrnNNO true  \"\"     \"LF_CRLF\" \"\"        \"\"        \t \"\"        \t \"\"\n> -commit_chk_wrnNNO input \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n> -\n> +#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n> +commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n> +commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n> +commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n>  \n> -commit_chk_wrnNNO false \"auto\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"\"        \t \"\"\n> -commit_chk_wrnNNO true  \"auto\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"\"        \t \"\"\n> -commit_chk_wrnNNO input \"auto\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"\"\n> +commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n> +commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n> +commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n>  \n> -commit_chk_wrnNNO false \"text\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"$WILC\"   \t \"$WICL\"\n> -commit_chk_wrnNNO true  \"text\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n> -commit_chk_wrnNNO input \"text\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"CRLF_LF\"\n> -\n> -commit_chk_wrnNNO false \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n> -commit_chk_wrnNNO true  \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n> -commit_chk_wrnNNO input \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n> -\n> -commit_chk_wrnNNO false \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n> -commit_chk_wrnNNO true  \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n> -commit_chk_wrnNNO input \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n> +for crlf in true false input\n> +do\n> +\tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n> +\tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n> +\tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n> +\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n> +\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n> +\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n> +\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n> +\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n> +\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n> +done\n>  \n> -commit_chk_wrnNNO false \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n> -commit_chk_wrnNNO true  \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n> -commit_chk_wrnNNO input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n> +commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n> +commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n> +commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n>  \n>  test_expect_success 'create files cleanup' '\n>  \trm -f *.txt &&\n> @@ -441,24 +447,20 @@ test_expect_success 'commit -text' '\n>  \tcheck_files_in_repo input \"-text\" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n>  '\n>  \n> -#                       attr    LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLFNUL\n> -check_in_repo_NNO false \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n> -check_in_repo_NNO true  \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n> -check_in_repo_NNO input \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n> -\n> -check_in_repo_NNO false \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n> -check_in_repo_NNO true  \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n> -check_in_repo_NNO input \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n> -\n> -check_in_repo_NNO false \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n> -check_in_repo_NNO true  \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n> -check_in_repo_NNO input \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n> -\n> -check_in_repo_NNO false \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n> -check_in_repo_NNO true  \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n> -check_in_repo_NNO input \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n> -\n> -\n> +for crlf in true false input\n> +do\n> +\t#                 attr  aeol           LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLFNUL\n> +\tcheck_in_repo_NNO \"\"    \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n> +\tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n> +\tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n> +\tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n> +\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n> +\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n> +\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n> +\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n> +\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n> +\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n> +done\n>  ################################################################################\n>  # Check how files in the repo are changed when they are checked out\n>  # How to read the table below:\n> @@ -490,89 +492,47 @@ LFNUL=LF_nul\n>  fi\n>  export CRLF_MIX_LF_CR MIX NL\n>  \n> -checkout_files \"\"      \"\" \t \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      \"\" \t \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      \"\" \t \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      \"\" \t \"\"    true   native   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"\"      ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  \"\" \t \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  \"\" \t \"\"    false  crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  \"\" \t \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  \"\" \t \"\"    true   native   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -checkout_files \"auto\"  ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\n> -for id in \"\" ident;\n> +# Same handling with and without ident\n> +for id in \"\"\n>  do\n> -\tcheckout_files \"crlf\"  \"$id\" \"\"    false  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"crlf\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"crlf\"  \"$id\" \"\"    false  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"crlf\"  \"$id\" \"\"    false  native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"crlf\"  \"$id\" \"\"    input  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"crlf\"  \"$id\" \"\"    input  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"crlf\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"crlf\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"crlf\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"crlf\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"lf\"    \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"lf\"    \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"lf\"    \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"lf\"    \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"lf\"    \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"lf\"    \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"lf\"    \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"lf\"    \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"lf\"    \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"lf\"    \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"text\"  \"$id\" \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n> -\tcheckout_files \"text\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"text\"  \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"text\"  \"$id\" \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n> -\tcheckout_files \"text\"  \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"text\"  \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"text\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"text\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"text\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"text\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> -\tcheckout_files \"-text\" \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"-text\" \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"-text\" \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"-text\" \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"-text\" \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"-text\" \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"-text\" \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"-text\" \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"-text\" \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> -\tcheckout_files \"-text\" \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> +\tfor ceol in lf crlf native\n> +\tdo\n> +\t\tfor crlf in true false input\n> +\t\tdo\n> +\t\t\t# -text overrides core.autocrlf and core.eol\n> +\t\t\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n> +\t\t\tcheckout_files -text \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> +\t\t\tcheckout_files -text \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> +\t\t\tcheckout_files -text \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> +\t\t\t# text\n> +\t\t\tcheckout_files text  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> +\t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> +\t\t\t# currently the same as text, eol=XXX\n> +\t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> +\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> +\t\tdone\n> +\n> +\t\t# core.autocrlf false, different core.eol\n> +\t\tcheckout_files   \"\"    \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> +\t\t# core.autocrlf true\n> +\t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> +\t\t# text: core.autocrlf = true overrides core.eol\n> +\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n> +\t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> +\t\t# text: core.autocrlf = input overrides core.eol\n> +\t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> +\t\tcheckout_files   auto  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> +\t\t# text=auto + eol=XXX\n> +\tdone\n> +\t# text: core.autocrlf=false uses core.eol\n> +\tcheckout_files     text  \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n> +\tcheckout_files     text  \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n> +\t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n> +\tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n> +\tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n> +\t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n> +\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n> +\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n>  done\n>  \n>  # Should be the last test case: remove some files from the worktree\n"},{"id":"283957","messageId":"d0d290f7-9c13-610d-8f22-059270bf2c6c@web.de","threadId":"41391","inReplyTo":"xmqq4maxz3lt.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v5 3/4] t0027: test cases for combined attributes","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-04-20T15:52:16Z","receivedAt":"2016-04-20T15:52:16Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"\n>> Currently \"* text=auto eol=lf\" does the same as \"* text eol=lf\",\n>> as the eol attribute overrides \"text=auto\", this will change in\n>> future.\n> Will change in future in what way?  In patch 5/4?\n>\n>\nYes, kind of.\nI'm fighting to get the test passed under Windows,\nand if this 4/4 could make it into pu, I don't need to\nresend all of it.\n"},{"id":"284010","messageId":"xmqqoa93ud9i.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1461072363-2874-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v5 4/4] convert.c: ident + core.autocrlf didn't work","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-20T22:27:37Z","receivedAt":"2016-04-20T22:27:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n>  \tif (ca.drv && (ca.drv->smudge || ca.drv->clean))\n> -\t\treturn filter;\n> +\t\treturn NULL;\n>  \n>  \tif (ca.ident)\n>  \t\tfilter = ident_filter(sha1);\n\nWe allocated an ident-filter here...\n\n> -\tcrlf_action = ca.crlf_action;\n> -\n> -\tif ((crlf_action == CRLF_BINARY) ||\n> -\t\t\tcrlf_action == CRLF_AUTO_INPUT ||\n> -\t\t\t(crlf_action == CRLF_TEXT_INPUT))\n> -\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n> -\n> -\telse if (output_eol(crlf_action) == EOL_CRLF &&\n> -\t\t !(crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_CRLF))\n> +\tif (output_eol(ca.crlf_action) == EOL_CRLF) {\n> +\t\tif (ca.crlf_action == CRLF_AUTO || ca.crlf_action == CRLF_AUTO_CRLF)\n> +\t\t\treturn NULL;\n\nand then by returning NULL, we lost it.\n\n>  \t\tfilter = cascade_filter(filter, lf_to_crlf_filter());\n> +\t} else\n> +\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n>  \n>  \treturn filter;\n>  }\n"},{"id":"284134","messageId":"1461335908-5013-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6 01/10] t0027: Make more reliable","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-22T14:38:28Z","receivedAt":"2016-04-22T14:38:28Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nMake the commit_chk_wrnNNO test in t0027 more reliable:\nWhen the attributes of a commited file are changed and the file is otherwise\nunchanged, Git may not detect that the next commit may need to treat the\nfile as changed.\nThis happens when lstat() doesn't detect a change, since neither inode,\nmtime nor size are changed.\n\nAdd a singe \"Z\" character to change the file size.\nIgnore it when comparing the files later.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Changes since v5:\n - send the whole series, now 10/10\n - Removed the \"will change in future\" in one commit msg\n - Don't leak the filer in 4/10\n t/t0027-auto-crlf.sh | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex f33962b..9fe539b 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -12,7 +12,7 @@ fi\n \n compare_files () {\n \ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n-\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n+\ttr '\\015\\000' QN <\"$2\" | tr -d 'Z' >\"$2\".actual &&\n \ttest_cmp \"$1\".expect \"$2\".actual &&\n \trm \"$1\".expect \"$2\".actual\n }\n@@ -114,6 +114,7 @@ commit_chk_wrnNNO () {\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n \t\tcp $f $fname &&\n+\t\tprintf Z >>\"$fname\" &&\n \t\tgit -c core.autocrlf=$crlf add $fname 2>/dev/null &&\n \t\tgit -c core.autocrlf=$crlf commit -m \"commit_$fname\" $fname >\"${pfx}_$f.err\" 2>&1\n \tdone\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284133","messageId":"1461336826-5068-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6 02/10] convert: allow core.autocrlf=input and core.eol=crlf","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-22T14:53:46Z","receivedAt":"2016-04-22T14:53:46Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nEven though the configuration parser errors out when core.autocrlf\nis set to 'input' when core.eol is set to 'crlf', there is no need\nto do so, because the core.autocrlf setting trumps core.eol.\n\nAllow all combinations of core.crlf and core.eol and document\nthat core.autocrlf overrides core.eol.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt | 6 +++---\n config.c                 | 4 ----\n 2 files changed, 3 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 42d2b50..155f988 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -337,9 +337,9 @@ core.quotePath::\n \n core.eol::\n \tSets the line ending type to use in the working directory for\n-\tfiles that have the `text` property set.  Alternatives are\n-\t'lf', 'crlf' and 'native', which uses the platform's native\n-\tline ending.  The default value is `native`.  See\n+\tfiles that have the `text` property set when core.autocrlf is false.\n+\tAlternatives are 'lf', 'crlf' and 'native', which uses the platform's\n+\tnative line ending.  The default value is `native`.  See\n \tlinkgit:gitattributes[5] for more information on end-of-line\n \tconversion.\n \ndiff --git a/config.c b/config.c\nindex 4c92699..c8ac9c2 100644\n--- a/config.c\n+++ b/config.c\n@@ -803,8 +803,6 @@ static int git_default_core_config(const char *var, const char *value)\n \n \tif (!strcmp(var, \"core.autocrlf\")) {\n \t\tif (value && !strcasecmp(value, \"input\")) {\n-\t\t\tif (core_eol == EOL_CRLF)\n-\t\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\t\tauto_crlf = AUTO_CRLF_INPUT;\n \t\t\treturn 0;\n \t\t}\n@@ -830,8 +828,6 @@ static int git_default_core_config(const char *var, const char *value)\n \t\t\tcore_eol = EOL_NATIVE;\n \t\telse\n \t\t\tcore_eol = EOL_UNSET;\n-\t\tif (core_eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)\n-\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\treturn 0;\n \t}\n \n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284135","messageId":"1461336827-5107-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6 03/10] t0027: test cases for combined attributes","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-22T14:53:47Z","receivedAt":"2016-04-22T14:53:47Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nAdd more test cases for the not normalized files (\"NNO\").  The\n\"text\" attribute is most important, use it as the first parameter.\n\"ident\", if set, is the second paramater followed by the eol\nattribute.  The eol attribute overrides core.autocrlf, which\noverrides core.eol.\nindent is not yet uses, this will be done in the next commit.\n\nUse loops to test more combinations of attributes, like\n\"* text eol=crlf\" or especially \"*text=auto eol=crlf\".\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n t/t0027-auto-crlf.sh | 298 ++++++++++++++++++++++-----------------------------\n 1 file changed, 129 insertions(+), 169 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 9fe539b..fd5e326 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -52,14 +52,17 @@ create_gitattributes () {\n create_NNO_files () {\n \tfor crlf in false true input\n \tdo\n-\t\tfor attr in \"\" auto text -text lf crlf\n+\t\tfor attr in \"\" auto text -text\n \t\tdo\n-\t\t\tpfx=NNO_${crlf}_attr_${attr} &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tfor aeol in \"\" lf crlf\n+\t\t\tdo\n+\t\t\t\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tdone\n \t\tdone\n \tdone\n }\n@@ -100,16 +103,17 @@ commit_check_warn () {\n }\n \n commit_chk_wrnNNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfwarn=$3\n-\tcrlfwarn=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfwarn=$1 ; shift\n+\tcrlfwarn=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n \t#Commit files on top of existing file\n-\tcreate_gitattributes \"$attr\" &&\n+\tcreate_gitattributes \"$attr\" $aeol &&\n \tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n@@ -122,19 +126,19 @@ commit_chk_wrnNNO () {\n \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n \t'\n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF\" '\n \t\tcheck_warning \"$crlfwarn\" ${pfx}_CRLF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_mix_LF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_mix_LF\" '\n \t\tcheck_warning \"$lfmixcrlf\" ${pfx}_CRLF_mix_LF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF_mix_cr\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf LF_mix_cr\" '\n \t\tcheck_warning \"$lfmixcr\" ${pfx}_LF_mix_CR.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_nul\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_nul\" '\n \t\tcheck_warning \"$crlfnul\" ${pfx}_CRLF_nul.err\n \t'\n }\n@@ -163,6 +167,7 @@ stats_ascii () {\n \n # contruct the attr/ returned by git ls-files --eol\n # Take none (=empty), one or two args\n+# convert.c: eol=XX overrides text=auto\n attr_ascii () {\n \tcase $1,$2 in\n \t-text,*)   echo \"-text\" ;;\n@@ -170,8 +175,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text=auto eol=lf\" ;;\n-\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n+\tauto,lf)   echo \"text eol=lf\" ;;\n+\tauto,crlf) echo \"text eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -196,28 +201,29 @@ check_files_in_repo () {\n }\n \n check_in_repo_NNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfname=$3\n-\tcrlfname=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}_\n-\ttest_expect_success \"compare_files $lfname ${pfx}LF.txt\" '\n-\t\tcompare_files $lfname ${pfx}LF.txt\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfname=$1 ; shift\n+\tcrlfname=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\ttest_expect_success \"compare_files $lfname ${pfx}_LF.txt\" '\n+\t\tcompare_files $lfname ${pfx}_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfname ${pfx}CRLF.txt\" '\n-\t\tcompare_files $crlfname ${pfx}CRLF.txt\n+\ttest_expect_success \"compare_files $crlfname ${pfx}_CRLF.txt\" '\n+\t\tcompare_files $crlfname ${pfx}_CRLF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\" '\n-\t\tcompare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\n+\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\" '\n+\t\tcompare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcr ${pfx}LF_mix_CR.txt\" '\n-\t\tcompare_files $lfmixcr ${pfx}LF_mix_CR.txt\n+\ttest_expect_success \"compare_files $lfmixcr ${pfx}_LF_mix_CR.txt\" '\n+\t\tcompare_files $lfmixcr ${pfx}_LF_mix_CR.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfnul ${pfx}CRLF_nul.txt\" '\n-\t\tcompare_files $crlfnul ${pfx}CRLF_nul.txt\n+\ttest_expect_success \"compare_files $crlfnul ${pfx}_CRLF_nul.txt\" '\n+\t\tcompare_files $crlfnul ${pfx}_CRLF_nul.txt\n \t'\n }\n \n@@ -232,7 +238,7 @@ checkout_files () {\n \tlfmixcrlf=$1 ; shift\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n-\tcreate_gitattributes \"$attr\" \"$ident\" &&\n+\tcreate_gitattributes \"$attr\" $ident $aeol &&\n \tgit config core.autocrlf $crlf &&\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n@@ -245,7 +251,7 @@ checkout_files () {\n \t\tfi\n \tdone\n \n-\ttest_expect_success \"ls-files --eol attr=$attr $ident $aeol core.autocrlf=$crlf core.eol=$ceol\" '\n+\ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n \t\ttest_when_finished \"rm expect actual\" &&\n \t\tsort <<-EOF >expect &&\n \t\ti/crlf w/$(stats_ascii $crlfname) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF.txt\n@@ -260,19 +266,19 @@ checkout_files () {\n \t\tsort >actual &&\n \t\ttest_cmp expect actual\n \t'\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n \t\tcompare_ws_file $pfx $lfname    crlf_false_attr__LF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n \t\tcompare_ws_file $pfx $crlfname  crlf_false_attr__CRLF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n \t\tcompare_ws_file $pfx $lfmixcrlf crlf_false_attr__CRLF_mix_LF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n \t\tcompare_ws_file $pfx $lfmixcr   crlf_false_attr__LF_mix_CR.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n \t\tcompare_ws_file $pfx $crlfnul   crlf_false_attr__LF_nul.txt\n \t\"\n }\n@@ -386,31 +392,31 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                       attr   LF        CRLF      CRLFmixLF \t LF_mix_CR   CRLFNUL\n-commit_chk_wrnNNO false \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"\"     \"LF_CRLF\" \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-\n+#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO false \"auto\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"auto\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"auto\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n \n-commit_chk_wrnNNO false \"text\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"$WILC\"   \t \"$WICL\"\n-commit_chk_wrnNNO true  \"text\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"text\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"CRLF_LF\"\n-\n-commit_chk_wrnNNO false \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-\n-commit_chk_wrnNNO false \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO true  \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO input \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n+for crlf in true false input\n+do\n+\tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+done\n \n-commit_chk_wrnNNO false \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO true  \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n \n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n@@ -441,24 +447,20 @@ test_expect_success 'commit -text' '\n \tcheck_files_in_repo input \"-text\" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n '\n \n-#                       attr    LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLFNUL\n-check_in_repo_NNO false \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO true  \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO input \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-\n-check_in_repo_NNO false \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-\n+for crlf in true false input\n+do\n+\t#                 attr  aeol           LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLFNUL\n+\tcheck_in_repo_NNO \"\"    \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n # How to read the table below:\n@@ -490,89 +492,47 @@ LFNUL=LF_nul\n fi\n export CRLF_MIX_LF_CR MIX NL\n \n-checkout_files \"\"      \"\" \t \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   native   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   native   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\n-for id in \"\" ident;\n+# Same handling with and without ident\n+for id in \"\"\n do\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tfor ceol in lf crlf native\n+\tdo\n+\t\tfor crlf in true false input\n+\t\tdo\n+\t\t\t# -text overrides core.autocrlf and core.eol\n+\t\t\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n+\t\t\tcheckout_files -text \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files -text \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files -text \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\t# text\n+\t\t\tcheckout_files text  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\t# currently the same as text, eol=XXX\n+\t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tdone\n+\n+\t\t# core.autocrlf false, different core.eol\n+\t\tcheckout_files   \"\"    \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# core.autocrlf true\n+\t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# text: core.autocrlf = true overrides core.eol\n+\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t# text: core.autocrlf = input overrides core.eol\n+\t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# text=auto + eol=XXX\n+\tdone\n+\t# text: core.autocrlf=false uses core.eol\n+\tcheckout_files     text  \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\tcheckout_files     text  \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284136","messageId":"1461336829-5146-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6 04/10] convert.c: ident + core.autocrlf didn't work","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-22T14:53:49Z","receivedAt":"2016-04-22T14:53:49Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen the ident attributes is set, get_stream_filter() did not obey\ncore.autocrlf=true, and the file was checked out with LF.\n\nChange the rule when a streaming filter can be used:\n- if an external filter is specified, don't use a stream filter.\n- if the worktree eol is CRLF and \"auto\" is active, don't use a stream filter.\n- Otherwise the stream filter can be used.\n\nAdd test cases in t0027.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c            | 19 +++++++------------\n t/t0027-auto-crlf.sh |  2 +-\n 2 files changed, 8 insertions(+), 13 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex f524b8d..b1614bf 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1380,27 +1380,22 @@ static struct stream_filter *ident_filter(const unsigned char *sha1)\n struct stream_filter *get_stream_filter(const char *path, const unsigned char *sha1)\n {\n \tstruct conv_attrs ca;\n-\tenum crlf_action crlf_action;\n \tstruct stream_filter *filter = NULL;\n \n \tconvert_attrs(&ca, path);\n-\n \tif (ca.drv && (ca.drv->smudge || ca.drv->clean))\n-\t\treturn filter;\n+\t\treturn NULL;\n+\n+\tif (ca.crlf_action == CRLF_AUTO || ca.crlf_action == CRLF_AUTO_CRLF)\n+\t\treturn NULL;\n \n \tif (ca.ident)\n \t\tfilter = ident_filter(sha1);\n \n-\tcrlf_action = ca.crlf_action;\n-\n-\tif ((crlf_action == CRLF_BINARY) ||\n-\t\t\tcrlf_action == CRLF_AUTO_INPUT ||\n-\t\t\t(crlf_action == CRLF_TEXT_INPUT))\n-\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n-\n-\telse if (output_eol(crlf_action) == EOL_CRLF &&\n-\t\t !(crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_CRLF))\n+\tif (output_eol(ca.crlf_action) == EOL_CRLF)\n \t\tfilter = cascade_filter(filter, lf_to_crlf_filter());\n+\telse\n+\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n \n \treturn filter;\n }\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex fd5e326..9372589 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -493,7 +493,7 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-for id in \"\"\n+for id in \"\" ident\n do\n \tfor ceol in lf crlf native\n \tdo\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284137","messageId":"1461336830-5185-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6 05/10] read-cache: factor out get_sha1_from_index() helper","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-22T14:53:50Z","receivedAt":"2016-04-22T14:53:50Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nFactor out the retrieval of the sha1 for a given path in\nread_blob_data_from_index() into the function get_sha1_from_index().\n\nThis will be used in the next commit, when convert.c can do the\nanalyze for \"text=auto\" without slurping the whole blob into memory\nat once.\n\nAdd a wrapper definition get_sha1_from_cache().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n cache.h      |  3 +++\n read-cache.c | 29 ++++++++++++++++++-----------\n 2 files changed, 21 insertions(+), 11 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 2711048..867ceb5 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -379,6 +379,7 @@ extern void free_name_hash(struct index_state *istate);\n #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)\n #define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)\n #define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))\n+#define get_sha1_from_cache(path)  get_sha1_from_index (&the_index, (path))\n #endif\n \n enum object_type {\n@@ -1040,6 +1041,8 @@ static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *\n \treturn read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);\n }\n \n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path);\n+\n /*\n  * This internal function is only declared here for the benefit of\n  * lookup_replace_object().  Please do not call it directly.\ndiff --git a/read-cache.c b/read-cache.c\nindex d9fb78b..a3ef967 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -2263,13 +2263,27 @@ int index_name_is_other(const struct index_state *istate, const char *name,\n \n void *read_blob_data_from_index(struct index_state *istate, const char *path, unsigned long *size)\n {\n-\tint pos, len;\n+\tconst unsigned char *sha1;\n \tunsigned long sz;\n \tenum object_type type;\n \tvoid *data;\n \n-\tlen = strlen(path);\n-\tpos = index_name_pos(istate, path, len);\n+\tsha1 = get_sha1_from_index(istate, path);\n+\tif (!sha1)\n+\t\treturn NULL;\n+\tdata = read_sha1_file(sha1, &type, &sz);\n+\tif (!data || type != OBJ_BLOB) {\n+\t\tfree(data);\n+\t\treturn NULL;\n+\t}\n+\tif (size)\n+\t\t*size = sz;\n+\treturn data;\n+}\n+\n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path)\n+{\n+\tint pos = index_name_pos(istate, path, strlen(path));\n \tif (pos < 0) {\n \t\t/*\n \t\t * We might be in the middle of a merge, in which\n@@ -2285,14 +2299,7 @@ void *read_blob_data_from_index(struct index_state *istate, const char *path, un\n \t}\n \tif (pos < 0)\n \t\treturn NULL;\n-\tdata = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);\n-\tif (!data || type != OBJ_BLOB) {\n-\t\tfree(data);\n-\t\treturn NULL;\n-\t}\n-\tif (size)\n-\t\t*size = sz;\n-\treturn data;\n+\treturn (istate->cache[pos]->sha1);\n }\n \n void stat_validity_clear(struct stat_validity *sv)\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284142","messageId":"1461336831-5224-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6 06/10] convert.c: stream and early out","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-22T14:53:51Z","receivedAt":"2016-04-22T14:53:51Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen statistics are done for the autocrlf handling, the search in\nthe content can be stopped, if e.g\n- a search for binary is done, and a NUL character is found\n- a search for CRLF is done, and the first CRLF is found.\n\nSimilar when statistics for binary vs non-binary are gathered:\nWhenever a lone CR or NUL is found, the search can be aborted.\n\nWhen checking out files in \"auto\" mode, any file that has a \"lone CR\"\nor a CRLF will not be converted, so the search can be aborted early.\n\nAdd the new bit, CONVERT_STAT_BITS_ANY_CR,\nwhich is set for either lone CR or CRLF.\n\nMany binary files have a NUL very early (within the first few bytes,\nlatest within the first 1..2K).\nIt is often not necessary to load the whole content of a file or blob\ninto memory.\n\nUse a streaming handling for blobs and files in the worktree.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c | 159 ++++++++++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 103 insertions(+), 56 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex b1614bf..24ab095 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -3,6 +3,7 @@\n #include \"run-command.h\"\n #include \"quote.h\"\n #include \"sigchain.h\"\n+#include \"streaming.h\"\n \n /*\n  * convert.c - convert a file when checking it out and checking it in.\n@@ -13,10 +14,10 @@\n  * translation when the \"text\" attribute or \"auto_crlf\" option is set.\n  */\n \n-/* Stat bits: When BIN is set, the txt bits are unset */\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n+#define CONVERT_STAT_BITS_ANY_CR    0x8\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -31,30 +32,36 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned nul, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonecr, lonelf, crlf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n };\n \n-static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)\n+static void do_gather_stats(const char *buf, unsigned long size,\n+\t\t\t    struct text_stat *stats, unsigned earlyout)\n {\n \tunsigned long i;\n \n-\tmemset(stats, 0, sizeof(*stats));\n-\n+\tif (!buf || !size)\n+\t\treturn;\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n \t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n-\t\t\t} else\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\t} else {\n \t\t\t\tstats->lonecr++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+\t\t\t}\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == '\\n') {\n \t\t\tstats->lonelf++;\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_LF;\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == 127)\n@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t\t\tstats->printable++;\n \t\t\t\tbreak;\n \t\t\tcase 0:\n-\t\t\t\tstats->nul++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t\t/* fall through */\n \t\t\tdefault:\n \t\t\t\tstats->nonprintable++;\n@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t}\n \t\telse\n \t\t\tstats->printable++;\n+\t\tif (stats->stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n \t}\n \n \t/* If file ends with EOF then don't count this EOF as non-printable. */\n@@ -86,41 +95,62 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n  * The same heuristics as diff.c::mmfile_is_binary()\n  * We treat files with bare CR as binary\n  */\n-static int convert_is_binary(unsigned long size, const struct text_stat *stats)\n+static void convert_nonprintable(struct text_stat *stats)\n {\n-\tif (stats->lonecr)\n-\t\treturn 1;\n-\tif (stats->nul)\n-\t\treturn 1;\n \tif ((stats->printable >> 7) < stats->nonprintable)\n-\t\treturn 1;\n-\treturn 0;\n+\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+}\n+\n+static void gather_stats(const char *buf, unsigned long size,\n+\t\t\t struct text_stat *stats, unsigned earlyout)\n+{\n+\tmemset(stats, 0, sizeof(*stats));\n+\tdo_gather_stats(buf, size, stats, earlyout);\n+\tconvert_nonprintable(stats);\n }\n \n-static unsigned int gather_convert_stats(const char *data, unsigned long size)\n+\n+static unsigned get_convert_stats_sha1(unsigned const char *sha1,\n+\t\t\t\t       unsigned earlyout)\n {\n+\tstruct git_istream *st;\n \tstruct text_stat stats;\n-\tint ret = 0;\n-\tif (!data || !size)\n-\t\treturn 0;\n-\tgather_stats(data, size, &stats);\n-\tif (convert_is_binary(size, &stats))\n-\t\tret |= CONVERT_STAT_BITS_BIN;\n-\tif (stats.crlf)\n-\t\tret |= CONVERT_STAT_BITS_TXT_CRLF;\n-\tif (stats.lonelf)\n-\t\tret |=  CONVERT_STAT_BITS_TXT_LF;\n+\tenum object_type type;\n+\tunsigned long sz;\n \n-\treturn ret;\n+\tif (!sha1)\n+\t\treturn 0;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tst = open_istream(sha1, &type, &sz, NULL);\n+\tif (!st) {\n+\t\treturn 0;\n+\t}\n+\tif (type != OBJ_BLOB)\n+\t\tgoto close_and_exit_i;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read_istream(st, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+close_and_exit_i:\n+\tclose_istream(st);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n }\n \n-static const char *gather_convert_stats_ascii(const char *data, unsigned long size)\n+static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned int convert_stats = gather_convert_stats(data, size);\n-\n+\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n+\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats) {\n+\tswitch (convert_stats & mask) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -132,24 +162,45 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si\n \t}\n }\n \n+static unsigned get_convert_stats_wt(const char *path)\n+{\n+\tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tint fd;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tfd = open(path, O_RDONLY);\n+\tif (fd < 0)\n+\t\treturn 0;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read(fd, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+\tclose(fd);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n+}\n+\n const char *get_cached_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret;\n-\tunsigned long sz;\n-\tvoid *data = read_blob_data_from_cache(path, &sz);\n-\tret = gather_convert_stats_ascii(data, sz);\n-\tfree(data);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n const char *get_wt_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret = \"\";\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (strbuf_read_file(&sb, path, 0) >= 0)\n-\t\tret = gather_convert_stats_ascii(sb.buf, sb.len);\n-\tstrbuf_release(&sb);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_wt(path);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n static int text_eol_is_crlf(void)\n@@ -219,16 +270,10 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \n static int has_cr_in_index(const char *path)\n {\n-\tunsigned long sz;\n-\tvoid *data;\n-\tint has_cr;\n-\n-\tdata = read_blob_data_from_cache(path, &sz);\n-\tif (!data)\n-\t\treturn 0;\n-\thas_cr = memchr(data, '\\r', sz) != NULL;\n-\tfree(data);\n-\treturn has_cr;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n+\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -249,10 +294,10 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \n \t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n@@ -309,11 +354,13 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n+\n \n \tif (!len || output_eol(crlf_action) != EOL_CRLF)\n \t\treturn 0;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, earlyout);\n \n \t/* No \"naked\" LF? Nothing to convert, regardless. */\n \tif (!stats.lonelf)\n@@ -327,7 +374,7 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\t\t\treturn 0;\n \t\t}\n \n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \t}\n \n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284141","messageId":"1461336833-5263-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6 07/10] convert: unify the \"auto\" handling of CRLF","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-22T14:53:53Z","receivedAt":"2016-04-22T14:53:53Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nBefore this change,\n$ echo \"* text=auto\" >.gitattributes\n$ echo \"* eol=crlf\" >>.gitattributes\n\nwould have the same effect as\n$ echo \"* text\" >.gitattributes\n$ git config core.eol crlf\n\nSince the 'eol' attribute had higher priority than 'text=auto', this may\ncorrupt binary files and is not what most users expect to happen.\n\nMake the 'eol' attribute to obey 'text=auto', and now\n$ echo \"* text=auto\" >.gitattributes\n$ echo \"* eol=crlf\" >>.gitattributes\nbehaves the same as\n$ echo \"* text=auto\" >.gitattributes\n$ git config core.eol crlf\n\nIn other words,\n$ echo \"* text=auto eol=crlf\" >.gitattributes\nhas the same effect as\n$ git config core.autocrlf true\n\nand\n$ echo \"* text=auto eol=lf\" >.gitattributes\nhas the same effect as\n$ git config core.autocrlf input\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt        | 14 +++++++-------\n Documentation/gitattributes.txt | 15 +++++++++------\n convert.c                       | 42 +++++++++++++++++++++--------------------\n convert.h                       |  3 ++-\n t/t0025-crlf-auto.sh            |  4 ++--\n t/t0027-auto-crlf.sh            | 32 +++++++++++++++----------------\n t/t6038-merge-text-auto.sh      | 23 ++++++++++++++--------\n 7 files changed, 73 insertions(+), 60 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 155f988..117c2f3 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf`\n mechanism.\n \n core.autocrlf::\n-\tSetting this variable to \"true\" is almost the same as setting\n-\tthe `text` attribute to \"auto\" on all files except that text\n-\tfiles are not guaranteed to be normalized: files that contain\n-\t`CRLF` in the repository will not be touched.  Use this\n-\tsetting if you want to have `CRLF` line endings in your\n-\tworking directory even though the repository does not have\n-\tnormalized line endings.  This variable can be set to 'input',\n+\tSetting this variable to \"true\" is the same as setting\n+\tthe `text` attribute to \"auto\" on all files and core.eol to \"crlf\".\n+\tSet to true if you want to have `CRLF` line endings in your\n+\tworking directory and the repository has LF line endings.\n+\tText files are guaranteed not to be normalized: files that contain\n+\t`CRLF` in the repository will not be touched.\n+\tThis variable can be set to 'input',\n \tin which case no output conversion is performed.\n \n core.symlinks::\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex e3b1de8..d7a124b 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n `core.eol` configuration variable for all text files.\n+Note that `core.autocrlf` overrides `core.eol`\n \n Set::\n \n@@ -130,8 +131,9 @@ Unset::\n Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n-\tend-of-line normalization.  If Git decides that the content is\n-\ttext, its line endings are normalized to LF on checkin.\n+\tend-of-line conversion.  If Git decides that the content is\n+\ttext, its line endings are converted to LF on checkin.\n+\tWhen the file has been commited with CRLF, no conversion is done.\n \n Unspecified::\n \n@@ -146,7 +148,7 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It enables end-of-line normalization without any\n+working directory.  It enables end-of-line conversion without any\n content checks, effectively setting the `text` attribute.\n \n Set to string value \"crlf\"::\n@@ -186,9 +188,10 @@ the working directory, and prevent .jpg files from being normalized\n regardless of their content.\n \n ------------------------\n+*               text=auto\n *.txt\t\ttext\n-*.vcproj\teol=crlf\n-*.sh\t\teol=lf\n+*.vcproj\ttext eol=crlf\n+*.sh\t\ttext eol=lf\n *.jpg\t\t-text\n ------------------------\n \n@@ -198,7 +201,7 @@ normalization in Git.\n \n If you simply want to have CRLF line endings in your working directory\n regardless of the repository you are working with, you can set the\n-config variable \"core.autocrlf\" without changing any attributes.\n+config variable \"core.autocrlf\" without using any attributes.\n \n ------------------------\n [core]\ndiff --git a/convert.c b/convert.c\nindex 24ab095..3782172 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -227,7 +227,9 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \t\treturn EOL_LF;\n \tcase CRLF_UNDEFINED:\n \tcase CRLF_AUTO_CRLF:\n+\t\treturn EOL_CRLF;\n \tcase CRLF_AUTO_INPUT:\n+\t\treturn EOL_LF;\n \tcase CRLF_TEXT:\n \tcase CRLF_AUTO:\n \t\t/* fall through */\n@@ -299,17 +301,15 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/*\n-\t\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t\t * This is the new safer autocrlf handling.\n-\t\t\t */\n-\t\t\tif (has_cr_in_index(path))\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/*\n+\t\t * If the file in the index has any CR in it, do not convert.\n+\t\t * This is the new safer autocrlf handling.\n+\t\t */\n+\t\tif (checksafe == SAFE_CRLF_RENORMALIZE)\n+\t\t\tchecksafe = SAFE_CRLF_FALSE;\n+\t\telse if (has_cr_in_index(path))\n+\t\t\treturn 0;\n \t}\n-\n \tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n \n \t/* Optimization: No CRLF? Nothing to convert, regardless. */\n@@ -367,12 +367,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\treturn 0;\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t\t/* This is the new safer autocrlf-handling */\n-\t\t\tif (stats.lonecr || stats.crlf )\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n+\t\t/* This is the new safer autocrlf-handling */\n+\t\tif (stats.lonecr || stats.crlf )\n+\t\t\treturn 0;\n \n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n@@ -833,7 +831,11 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tca->drv = git_path_check_convert(ccheck + 2);\n \t\tif (ca->crlf_action != CRLF_BINARY) {\n \t\t\tenum eol eol_attr = git_path_check_eol(ccheck + 3);\n-\t\t\tif (eol_attr == EOL_LF)\n+\t\t\tif (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_INPUT;\n+\t\t\telse if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_CRLF;\n+\t\t\telse if (eol_attr == EOL_LF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_INPUT;\n \t\t\telse if (eol_attr == EOL_CRLF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_CRLF;\n@@ -892,9 +894,9 @@ const char *get_convert_attr_ascii(const char *path)\n \tcase CRLF_AUTO:\n \t\treturn \"text=auto\";\n \tcase CRLF_AUTO_CRLF:\n-\t\treturn \"text=auto eol=crlf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=crlf\";\n \tcase CRLF_AUTO_INPUT:\n-\t\treturn \"text=auto eol=lf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=lf\";\n \t}\n \treturn \"\";\n }\n@@ -996,7 +998,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_FALSE);\n+\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n }\n \n /*****************************************************************\ndiff --git a/convert.h b/convert.h\nindex ccf436b..81b6cdf 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -7,7 +7,8 @@\n enum safe_crlf {\n \tSAFE_CRLF_FALSE = 0,\n \tSAFE_CRLF_FAIL = 1,\n-\tSAFE_CRLF_WARN = 2\n+\tSAFE_CRLF_WARN = 2,\n+\tSAFE_CRLF_RENORMALIZE = 4\n };\n \n extern enum safe_crlf safe_crlf;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex c164b46..d0bee08 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -114,7 +114,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n+test_expect_success 'text=auto, autocrlf=true does not normalize CRLF files' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \tgit config core.autocrlf true &&\n@@ -126,7 +126,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n \tLFonlydiff=$(git diff LFonly) &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n \tLFwithNULdiff=$(git diff LFwithNUL) &&\n-\ttest -z \"$LFonlydiff\" -a -n \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n+\ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 9372589..8367d0b 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -175,8 +175,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text eol=lf\" ;;\n-\tauto,crlf) echo \"text eol=crlf\" ;;\n+\tauto,lf)   echo \"text=auto eol=lf\" ;;\n+\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -397,10 +397,9 @@ commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n-\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n@@ -408,8 +407,8 @@ do\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n \tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n \tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n done\n@@ -454,9 +453,9 @@ do\n \tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n@@ -493,7 +492,8 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-for id in \"\" ident\n+#for id in \"\" ident\n+for id in \"\"\n do\n \tfor ceol in lf crlf native\n \tdo\n@@ -509,7 +509,7 @@ do\n \t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n \t\t\t# currently the same as text, eol=XXX\n \t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \n \t\t# core.autocrlf false, different core.eol\n@@ -517,7 +517,7 @@ do\n \t\t# core.autocrlf true\n \t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n \t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n@@ -531,8 +531,8 @@ do\n \tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 85c10b0..33b77ee 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -16,6 +16,13 @@ test_description='CRLF merge conflict across text=auto change\n \n test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b\n \n+compare_files () {\n+\ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n+\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n+\ttest_cmp \"$1\".expect \"$2\".actual &&\n+\trm \"$1\".expect \"$2\".actual\n+}\n+\n test_expect_success setup '\n \tgit config core.autocrlf false &&\n \n@@ -30,7 +37,7 @@ test_expect_success setup '\n \tgit branch side &&\n \n \techo \"* text=auto\" >.gitattributes &&\n-\ttouch file &&\n+\techo first line >file &&\n \tgit add .gitattributes file &&\n \ttest_tick &&\n \tgit commit -m \"normalize file\" &&\n@@ -81,7 +88,7 @@ test_expect_success 'Merge after setting text=auto' '\n \trm -f .gitattributes &&\n \tgit reset --hard a &&\n \tgit merge b &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_success 'Merge addition of text=auto' '\n@@ -99,7 +106,7 @@ test_expect_success 'Merge addition of text=auto' '\n \trm -f .gitattributes &&\n \tgit reset --hard b &&\n \tgit merge a &&\n-\ttest_cmp expected file\n+\tcompare_files  expected file\n '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n@@ -121,7 +128,7 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \tgit reset --hard a &&\n \ttest_must_fail git merge b &&\n \tfuzz_conflict file >file.fuzzy &&\n-\ttest_cmp expected file.fuzzy\n+\tcompare_files expected file.fuzzy\n '\n \n test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n@@ -143,7 +150,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \tgit reset --hard b &&\n \ttest_must_fail git merge a &&\n \tfuzz_conflict file >file.fuzzy &&\n-\ttest_cmp expected file.fuzzy\n+\tcompare_files expected file.fuzzy\n '\n \n test_expect_failure 'checkout -m after setting text=auto' '\n@@ -158,7 +165,7 @@ test_expect_failure 'checkout -m after setting text=auto' '\n \tgit reset --hard initial &&\n \tgit checkout a -- . &&\n \tgit checkout -m b &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_failure 'checkout -m addition of text=auto' '\n@@ -173,7 +180,7 @@ test_expect_failure 'checkout -m addition of text=auto' '\n \tgit reset --hard initial &&\n \tgit checkout b -- . &&\n \tgit checkout -m a &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_failure 'cherry-pick patch from after text=auto was added' '\n@@ -187,7 +194,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' '\n \tgit reset --hard b &&\n \ttest_must_fail git cherry-pick a >err 2>&1 &&\n \tgrep \"[Nn]othing added\" err &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_success 'Test delete/normalize conflict' '\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284139","messageId":"1461336834-5302-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6 08/10] convert.c: more safer crlf handling with text attribute","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-22T14:53:54Z","receivedAt":"2016-04-22T14:53:54Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nA follow-up after a discussion how to fix the flaky execution\nof t0025, gmane/$284352.\n\nThis patch extends the work done in commit c480539:\n\"Make it work also for un-normalized repositories\". Make sure that CRLF\ncan be converted round trip, or don't convert them at all.\n\nThe old handling would treat a file as unchanged after checkout,\nas long as it is not touched in the work tree and mtime matches the value\nrecorded in the index.\nWhen the mtime is changed in the working tree, or the inode is changed,\nthe file is reported as modified.\n\nThe following sequence is now handled reproducable:\n$ git init\n$ printf \"line1\\r\\n\" >file.bat\n$ git add file.bat\n$ git commit -m \"Add file with CRLF\" file.bat\n$ echo \"*.bat text eol=crlf\" >.gitattributes\n$ git commit -m \"bat files should have CRLF\"\n$ git status\n # nothing to commit, working directory clean\n$ git push <upstream>\n$ printf \"newline\\r\\n\" >>file.bat\n$ mv file.bat file.sav\n$ git checkout file.bat\n$ git status\n #modified:   file.bat\n\nThe new handling makes sure that after running \"git reset --hard\".\n\"git status\" reports the working tree as clean regarding CRLF conversion.\nIt makes sure that the Git-internal eol conversion is\ndoing roundtrip. A user can still write an external smudge/clean filter\noutside Git, which doesn't do a roundtrip and the working directory is\nnot clean.\n\nThe functionality of has_cr_in_index() is turned into has_crlf_in_index(),\nand the function is integrated into would_convert_crlf_at_commit().\n\nCheck for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR\nis no longer used and removed, as well as \"lonecr\" in struct text_stat.\n\nRewrite check_safe_crlf() in convert.c to simulate checkin-checkout,\nto detect whether any line endings are converted.\n\nAdd a warning, similar to the CRLF-LF replacement, when a file is commited,\nand after the next checkout the line endings are not they should be.\n\nModify the lf_to_crlf_filter:\nFiles with LF are converted into CRLF, file with CRLF are not changed.\nFiles with mixed line endings are not converted, the filter fails, and Git\nfalls back to the non-streaming handling, see write_entry().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/gitattributes.txt |  19 ++--\n convert.c                       | 233 +++++++++++++++++++++++++---------------\n t/t0025-crlf-auto.sh            |   8 +-\n t/t0027-auto-crlf.sh            |  92 ++++++++--------\n 4 files changed, 212 insertions(+), 140 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex d7a124b..836461d 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'.\n `text`\n ^^^^^^\n \n-This attribute enables and controls end-of-line normalization.  When a\n+This attribute enables and controls end-of-line conversion.  When a\n text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol`\n Set::\n \n \tSetting the `text` attribute on a path enables end-of-line\n-\tnormalization and marks the path as a text file.  End-of-line\n+\tconversion and marks the path as a text file.  End-of-line\n \tconversion takes place without guessing the content type.\n+\tFiles that have been commited with CRLF before the text attribute\n+\tis set and commited are not normalized. No end-of-line conversion\n+\tis done at checkout or checkin.\n \n Unset::\n \n@@ -131,9 +134,9 @@ Unset::\n Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n-\tend-of-line conversion.  If Git decides that the content is\n-\ttext, its line endings are converted to LF on checkin.\n-\tWhen the file has been commited with CRLF, no conversion is done.\n+\tend-of-line normalization.  If Git decides that the content is\n+\ttext, and the path has no CRLF in the index,\n+\tits line endings are converted to LF on checkin.\n \n Unspecified::\n \n@@ -148,8 +151,10 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It enables end-of-line conversion without any\n-content checks, effectively setting the `text` attribute.\n+working directory.  It sets the `text` attribute, unless `text=auto`\n+is specified.\n+When the file had been commited with CRLF in the index, no conversion\n+is done at checkout or commit.\n \n Set to string value \"crlf\"::\n \ndiff --git a/convert.c b/convert.c\nindex 3782172..8d4c42a 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -17,7 +17,8 @@\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n-#define CONVERT_STAT_BITS_ANY_CR    0x8\n+\n+#define CONVERT_STAT_BITS_MIXED (CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF)\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -32,7 +33,7 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned stat_bits, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonelf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n@@ -48,13 +49,10 @@ static void do_gather_stats(const char *buf, unsigned long size,\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n-\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n-\t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n \t\t\t} else {\n-\t\t\t\tstats->lonecr++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t}\n \t\t\tcontinue;\n@@ -135,7 +133,7 @@ static unsigned get_convert_stats_sha1(unsigned const char *sha1,\n \t\tif (!readlen)\n \t\t\tbreak;\n \t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n-\t\tif (stats.stat_bits & earlyout)\n+\t\tif ((stats.stat_bits & earlyout) == earlyout)\n \t\t\tbreak; /* We found what we have been searching for */\n \t}\n close_and_exit_i:\n@@ -146,11 +144,9 @@ close_and_exit_i:\n \n static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n-\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats & mask) {\n+\tswitch (convert_stats) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -162,7 +158,16 @@ static const char *convert_stats_ascii(unsigned convert_stats)\n \t}\n }\n \n-static unsigned get_convert_stats_wt(const char *path)\n+const char *get_cached_convert_stats_ascii(const char *path)\n+{\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n+}\n+\n+const char *get_wt_convert_stats_ascii(const char *path)\n {\n \tstruct text_stat stats;\n \tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n@@ -184,23 +189,7 @@ static unsigned get_convert_stats_wt(const char *path)\n \t}\n \tclose(fd);\n \tconvert_nonprintable(&stats);\n-\treturn stats.stat_bits;\n-}\n-\n-const char *get_cached_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n-\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n-\t\t\t\t\t       earlyout);\n-\treturn convert_stats_ascii(convert_stats);\n-}\n-\n-const char *get_wt_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_wt(path);\n-\treturn convert_stats_ascii(convert_stats);\n+\treturn convert_stats_ascii(stats.stat_bits);\n }\n \n static int text_eol_is_crlf(void)\n@@ -239,43 +228,95 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \treturn core_eol;\n }\n \n+static int would_convert_lf_at_checkout(unsigned convert_stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tif (output_eol(crlf_action) != EOL_CRLF)\n+\t\treturn 0;\n+\n+\t/* No \"naked\" LF? Nothing to convert, regardless. */\n+\tif (!convert_stats & CONVERT_STAT_BITS_TXT_LF)\n+\t\treturn 0;\n+\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\t/* auto: binary files are not converted */\n+\t\tif (convert_stats & CONVERT_STAT_BITS_BIN)\n+\t\t\treturn 0;\n+\t}\n+\t/* If we have any CRLF line endings, we do not touch it */\n+\t/* This is the new safer autocrlf-handling */\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+\n+}\n+\n+static int would_convert_crlf_at_commit(const char * path,\n+\t\t\t\t\tconst struct text_stat *stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tunsigned stat_bits_index;\n+\t/* No CRLF? Nothing to convert, regardless. */\n+\tif (!(stats->stat_bits & CONVERT_STAT_BITS_TXT_CRLF))\n+\t\treturn 0;\n+\t/*\n+\t * If the file in the index has any CRLF in it, do not convert.\n+\t * This is the new safer autocrlf handling.\n+\t */\n+\tstat_bits_index = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t\t CONVERT_STAT_BITS_TXT_CRLF);\n+\tif (stat_bits_index & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+}\n+\n static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n-                            struct text_stat *stats, enum safe_crlf checksafe)\n+\t\t\t    enum safe_crlf checksafe,\n+\t\t\t    unsigned convert_stats, unsigned new_convert_stats)\n {\n+\tenum eol new_eol = output_eol(crlf_action);\n+\tconst char *err_warn_msg = NULL;\n \tif (!checksafe)\n \t\treturn;\n-\n-\tif (output_eol(crlf_action) == EOL_LF) {\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n \t\t/*\n \t\t * CRLFs would not be restored by checkout:\n \t\t * check if we'd remove CRLFs\n \t\t */\n-\t\tif (stats->crlf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n-\t\t}\n-\t} else if (output_eol(crlf_action) == EOL_CRLF) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n+\t}\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_LF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_LF)) {\n \t\t/*\n \t\t * CRLFs would be added by checkout:\n \t\t * check if we have \"naked\" LFs\n \t\t */\n-\t\tif (stats->lonelf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n-\t\t}\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n+\t}\n+\tif ((new_convert_stats & CONVERT_STAT_BITS_MIXED) == CONVERT_STAT_BITS_MIXED)\n+\t\terr_warn_msg = \"mixed eol\";\n+\telse if (new_eol == EOL_LF && new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\terr_warn_msg = \"CRLF\";\n+\n+\tif (err_warn_msg) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"%s will be present after commit and checkout in %s.\",\n+\t\t\t\terr_warn_msg, path);\n+\t\telse\n+\t\t\tdie(\"%s will be present after commit and checkout in %s\",\n+\t\t\t    err_warn_msg, path);\n \t}\n-}\n-\n-static int has_cr_in_index(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n-\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n-\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -284,7 +325,7 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n {\n \tstruct text_stat stats;\n \tchar *dst;\n-\n+\tint convert_crlf;\n \tif (crlf_action == CRLF_BINARY ||\n \t    (src && !len))\n \t\treturn 0;\n@@ -296,24 +337,42 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n-\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\t\t/*\n-\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t * This is the new safer autocrlf handling.\n-\t\t */\n-\t\tif (checksafe == SAFE_CRLF_RENORMALIZE)\n-\t\t\tchecksafe = SAFE_CRLF_FALSE;\n-\t\telse if (has_cr_in_index(path))\n-\t\t\treturn 0;\n+\t} else {\n+\t\tgather_stats(src, len, &stats, 0);\n+\t}\n+\tif (checksafe == SAFE_CRLF_RENORMALIZE) {\n+\t\tconvert_crlf = 1;\n+\t\tchecksafe = SAFE_CRLF_FALSE;\n+\t} else {\n+\t\tconvert_crlf = would_convert_crlf_at_commit(path, &stats, len,\n+\t\t\t\t\t\t\t    crlf_action);\n \t}\n-\tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n \n-\t/* Optimization: No CRLF? Nothing to convert, regardless. */\n-\tif (!stats.crlf)\n+\tif (checksafe) {\n+\t\tunsigned convert_stats = stats.stat_bits;\n+\t\tunsigned new_convert_stats = convert_stats;\n+\t\t/* Simulate commit */\n+\t\tif (convert_crlf &&\n+\t\t    (new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_LF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t}\n+\t\t/* Simulate checkout */\n+\t\tif (would_convert_lf_at_checkout(new_convert_stats,\n+\t\t\t\t\t\t len, crlf_action)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_LF;\n+\t\t}\n+\t\tcheck_safe_crlf(path, crlf_action, checksafe,\n+\t\t\t\tconvert_stats, new_convert_stats);\n+\t}\n+\tif (!convert_crlf)\n \t\treturn 0;\n \n \t/*\n@@ -327,7 +386,9 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (strbuf_avail(buf) + buf->len < len)\n \t\tstrbuf_grow(buf, len - buf->len);\n \tdst = buf->buf;\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n \t\t/*\n \t\t * If we guessed, we already know we rejected a file with\n \t\t * lone CR, and we can strip a CR without looking at what\n@@ -354,28 +415,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n-\n-\n-\tif (!len || output_eol(crlf_action) != EOL_CRLF)\n+\tunsigned earlyout = 0; /* Need to count lonelf */\n+\tif (!len)\n \t\treturn 0;\n \n \tgather_stats(src, len, &stats, earlyout);\n-\n-\t/* No \"naked\" LF? Nothing to convert, regardless. */\n-\tif (!stats.lonelf)\n+\tif (!would_convert_lf_at_checkout(stats.stat_bits,\n+\t\t\t\t\t  len, crlf_action))\n \t\treturn 0;\n \n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t/* This is the new safer autocrlf-handling */\n-\t\tif (stats.lonecr || stats.crlf )\n-\t\t\treturn 0;\n-\n-\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n-\t\t\treturn 0;\n-\t}\n-\n \t/* are we \"faking\" in place editing ? */\n \tif (src == buf->buf)\n \t\tto_free = strbuf_detach(buf, NULL);\n@@ -1067,6 +1115,8 @@ int is_null_stream_filter(struct stream_filter *filter)\n struct lf_to_crlf_filter {\n \tstruct stream_filter filter;\n \tunsigned has_held:1;\n+\tunsigned expanded_loneLF:1;\n+\tunsigned had_CRLF:1;\n \tchar held;\n };\n \n@@ -1107,7 +1157,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \t\t\tchar ch = input[i];\n \n \t\t\tif (ch == '\\n') {\n-\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\tif (!lf_to_crlf->had_CRLF) {\n+\t\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\t\tlf_to_crlf->expanded_loneLF = 1;\n+\t\t\t\t}\n+\t\t\t\tif (was_cr)\n+\t\t\t\t\tlf_to_crlf->had_CRLF = 1;\n \t\t\t} else if (was_cr) {\n \t\t\t\t/*\n \t\t\t\t * Previous round saw CR and it is not followed\n@@ -1136,6 +1191,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \n \t\t\twas_cr = 0;\n \t\t\toutput[o++] = ch;\n+\t\t\tif (lf_to_crlf->expanded_loneLF &&\n+\t\t\t    lf_to_crlf->had_CRLF) {\n+\t\t\t\t/*\n+\t\t\t\t * Mixed EOL, round trip not possible.\n+\t\t\t\t */\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n \t\t}\n \n \t\t*osize_p -= o;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex d0bee08..b5f93e2 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n+test_expect_success 'crlf=true causes a CRLF file not to be normalized' '\n \n \t# Backwards compatibility check\n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n-test_expect_success 'text=true causes a CRLF file to be normalized' '\n+test_expect_success 'text=true causes a CRLF file not to be normalized' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \techo \"CRLFonly text\" > .gitattributes &&\n@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 8367d0b..a16e513 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -71,10 +71,14 @@ check_warning () {\n \tcase \"$1\" in\n \tLF_CRLF) echo \"warning: LF will be replaced by CRLF\" >\"$2\".expect ;;\n \tCRLF_LF) echo \"warning: CRLF will be replaced by LF\" >\"$2\".expect ;;\n+\tCRLF)    echo \"warning: CRLF will be present after commit and checkout\" >\"$2\".expect ;;\n+\tmixed)   echo \"warning: mixed eol will be present after commit and checkout\" >\"$2\".expect ;;\n \t'')\t                                                 >\"$2\".expect ;;\n \t*) echo >&2 \"Illegal 1\": \"$1\" ; return false ;;\n \tesac\n-\tgrep \"will be replaced by\" \"$2\" | sed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" | uniq  >\"$2\".actual\n+\tegrep \"will be replaced by|will be present after commit\" \"$2\" |\n+\t\tsed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" |\n+\t\tuniq  >\"$2\".actual\n \ttest_cmp \"$2\".expect \"$2\".actual\n }\n \n@@ -169,7 +173,7 @@ stats_ascii () {\n # Take none (=empty), one or two args\n # convert.c: eol=XX overrides text=auto\n attr_ascii () {\n-\tcase $1,$2 in\n+\tcase \"$1\",\"$2\" in\n \t-text,*)   echo \"-text\" ;;\n \ttext,)     echo \"text\" ;;\n \ttext,lf)   echo \"text eol=lf\" ;;\n@@ -349,10 +353,12 @@ then\n \tWILC=LF_CRLF\n \tWICL=\n \tWAMIX=LF_CRLF\n+\tPcrlf=\n else\n \tWILC=\n \tWICL=CRLF_LF\n \tWAMIX=CRLF_LF\n+\tPcrlf=CRLF\n fi\n \n #                         attr   LF        CRLF      CRLFmixLF LFmixCR   CRLFNUL\n@@ -392,31 +398,32 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+#                 attr    aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n+\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$Pcrlf\"  mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$Pcrlf\"  mixed       \"$WILC\"     \"$Pcrlf\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF      mixed       \"\"          CRLF\n+\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n-\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf      $crlf   \"\"        CRLF      mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf    $crlf   LF_CRLF   \"\"        mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO text  lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO text  crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n done\n \n-commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n-commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n-\n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n \tgit -c core.autocrlf=false reset --hard\n@@ -456,9 +463,9 @@ do\n \tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n@@ -479,12 +486,10 @@ done\n \n if test_have_prereq NATIVE_CRLF\n then\n-MIX_CRLF_LF=CRLF\n MIX_LF_CR=CRLF_mix_CR\n NL=CRLF\n LFNUL=CRLF_nul\n else\n-MIX_CRLF_LF=CRLF_mix_LF\n MIX_LF_CR=LF_mix_CR\n NL=LF\n LFNUL=LF_nul\n@@ -492,8 +497,7 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-#for id in \"\" ident\n-for id in \"\"\n+for id in \"\" ident\n do\n \tfor ceol in lf crlf native\n \tdo\n@@ -501,38 +505,38 @@ do\n \t\tdo\n \t\t\t# -text overrides core.autocrlf and core.eol\n \t\t\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n-\t\t\tcheckout_files -text \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files -text \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files -text \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\t# text\n-\t\t\tcheckout_files text  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files text    \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files text    \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t\t# currently the same as text, eol=XXX\n-\t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto    \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto    \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \n \t\t# core.autocrlf false, different core.eol\n-\t\tcheckout_files   \"\"    \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   \"\"      \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# core.autocrlf true\n-\t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   \"\"      \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tcheckout_files   auto    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   text    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n-\t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files   auto  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   text    \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto    \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text=auto + eol=XXX\n \tdone\n \t# text: core.autocrlf=false uses core.eol\n-\tcheckout_files     text  \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files     text  \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     text    \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n+\tcheckout_files     text    \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files     text    \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  \"$MIX_LF_CR\" \"$LFNUL\"\n+\tcheckout_files     text    \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  \"$MIX_LF_CR\" \"$LFNUL\"\n \t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto    \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto    \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284140","messageId":"1461336836-5341-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6 09/10] t6038; use crlf on all platforms","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-22T14:53:56Z","receivedAt":"2016-04-22T14:53:56Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nt6038 uses different code, dependig if NATIVE_CRLF is set ot not.\nWhen the native line endings are LF, merge.renormalize is not tested very well.\nChange the test to always use CRLF by setting core.eol=crlf.\nAfter doing so, the test fails:\n\nrm '.gitattributes'\nrm 'control_file'\nrm 'file'\nrm 'inert_file'\nHEAD is now at 0d9ffb6 add line from b\nerror: addinfo_cache failed for path 'file'\nfile: unmerged (cbd69ec7cd12dd0989e853923867d94c8519aa52)\nfile: unmerged (ad55e240aeb42e0d9a0e18d6d8b02dd82ee3e527)\nfile: unmerged (99b633103c15c20cebebf821133ab526b0ff90b2)\nfatal: git write-tree failed to write a tree\nMerging:\n0d9ffb6 add line from b\nvirtual a\nfound 1 common ancestor:\n1c56df1 Initial\nAuto-merging file\nnot ok 4 - Merge addition of text=auto\n\nThis will be addressed in the next commit.\n---\n t/t6038-merge-text-auto.sh | 37 +++++++++++--------------------------\n 1 file changed, 11 insertions(+), 26 deletions(-)\n\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 33b77ee..0108ead 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -25,6 +25,7 @@ compare_files () {\n \n test_expect_success setup '\n \tgit config core.autocrlf false &&\n+\tgit config core.eol crlf &&\n \n \techo first line | append_cr >file &&\n \techo first line >control_file &&\n@@ -79,10 +80,8 @@ test_expect_success 'Merge after setting text=auto' '\n \tsame line\n \tEOF\n \n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\tappend_cr <expected >expected.temp &&\n-\t\tmv expected.temp expected\n-\tfi &&\n+\tappend_cr <expected >expected.temp &&\n+\tmv expected.temp expected &&\n \tgit config merge.renormalize true &&\n \tgit rm -fr . &&\n \trm -f .gitattributes &&\n@@ -97,10 +96,8 @@ test_expect_success 'Merge addition of text=auto' '\n \tsame line\n \tEOF\n \n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\tappend_cr <expected >expected.temp &&\n-\t\tmv expected.temp expected\n-\tfi &&\n+\tappend_cr <expected >expected.temp &&\n+\tmv expected.temp expected &&\n \tgit config merge.renormalize true &&\n \tgit rm -fr . &&\n \trm -f .gitattributes &&\n@@ -111,15 +108,9 @@ test_expect_success 'Merge addition of text=auto' '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \techo \"<<<<<<<\" >expected &&\n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\techo first line | append_cr >>expected &&\n-\t\techo same line | append_cr >>expected &&\n-\t\techo ======= | append_cr >>expected\n-\telse\n-\t\techo first line >>expected &&\n-\t\techo same line >>expected &&\n-\t\techo ======= >>expected\n-\tfi &&\n+\techo first line | append_cr >>expected &&\n+\techo same line | append_cr >>expected &&\n+\techo ======= | append_cr >>expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n@@ -135,15 +126,9 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \techo \"<<<<<<<\" >expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\techo ======= | append_cr >>expected &&\n-\t\techo first line | append_cr >>expected &&\n-\t\techo same line | append_cr >>expected\n-\telse\n-\t\techo ======= >>expected &&\n-\t\techo first line >>expected &&\n-\t\techo same line >>expected\n-\tfi &&\n+\techo ======= | append_cr >>expected &&\n+\techo first line | append_cr >>expected &&\n+\techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n \tgit config merge.renormalize false &&\n \trm -f .gitattributes &&\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284138","messageId":"1461336837-5380-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6 10/10] ce_compare_data() did not respect conversion","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-22T14:53:57Z","receivedAt":"2016-04-22T14:53:57Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWe define the working tree file is clean if either:\n\n  * the result of running convert_to_git() on the working tree\n    contents matches what is in the index (because that would mean\n    doing another \"git add\" on the path is a no-op); OR\n\n  * the result of running convert_to_working_tree() on the content\n    in the index matches what is in the working tree (because that\n    would mean doing another \"git checkout -f\" on the path is a\n    no-op).\n\nAdd an extra check in ce_compare_data() in read_cache.c.\n\nWhen a file has CRLF in the index, and is checked out into the working tree,\nbut left unchabged, it is not normalized at the next commit.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n read-cache.c               | 61 ++++++++++++++++++++++++++++++++++++++++++++++\n t/t6038-merge-text-auto.sh | 14 +++++------\n 2 files changed, 68 insertions(+), 7 deletions(-)\n\ndiff --git a/read-cache.c b/read-cache.c\nindex a3ef967..48c4b31 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -156,17 +156,78 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)\n \t\tce_mark_uptodate(ce);\n }\n \n+/*\n+ * Compare the data in buf with the data in the file pointed by fd and\n+ * return 0 if they are identical, and non-zero if they differ.\n+ */\n+static int compare_with_fd(const char *input, ssize_t len, int fd)\n+{\n+\tfor (;;) {\n+\t\tchar buf[1024 * 16];\n+\t\tssize_t chunk_len, read_len;\n+\n+\t\tchunk_len = sizeof(buf) < len ? sizeof(buf) : len;\n+\t\tread_len = xread(fd, buf, chunk_len ? chunk_len : 1);\n+\n+\t\tif (!read_len)\n+\t\t\t/* EOF on the working tree file */\n+\t\t\treturn !len ? 0 : -1;\n+\n+\t\tif (!len)\n+\t\t\t/* we expected there is nothing left */\n+\t\t\treturn -1;\n+\n+\t\tif (memcmp(buf, input, read_len))\n+\t\t\treturn -1;\n+\t\tinput += read_len;\n+\t\tlen -= read_len;\n+\t}\n+}\n+\n static int ce_compare_data(const struct cache_entry *ce, struct stat *st)\n {\n \tint match = -1;\n \tint fd = open(ce->name, O_RDONLY);\n \n+\t/*\n+\t * Would another \"git add\" on the path change what is in the\n+\t * index for the path?\n+\t */\n \tif (fd >= 0) {\n \t\tunsigned char sha1[20];\n \t\tif (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, 0))\n \t\t\tmatch = hashcmp(sha1, ce->sha1);\n \t\t/* index_fd() closed the file descriptor already */\n \t}\n+\tif (!match)\n+\t\treturn match;\n+\n+\t/*\n+\t * Would another \"git checkout -f\" out of the index change\n+\t * what is in the working tree file?\n+\t */\n+\tfd = open(ce->name, O_RDONLY);\n+\tif (fd >= 0) {\n+\t\tenum object_type type;\n+\t\tunsigned long size_long;\n+\t\tvoid *data = read_sha1_file(ce->sha1, &type, &size_long);\n+\n+\t\tif (type == OBJ_BLOB) {\n+\t\t\tstruct strbuf worktree = STRBUF_INIT;\n+\t\t\tif (convert_to_working_tree(ce->name, data,\n+\t\t\t\t\t\t    size_long,\n+\t\t\t\t\t\t    &worktree)) {\n+\t\t\t\tsize_t size;\n+\t\t\t\tfree(data);\n+\t\t\t\tdata = strbuf_detach(&worktree, &size);\n+\t\t\t\tsize_long = size;\n+\t\t\t}\n+\t\t\tif (!compare_with_fd(data, size_long, fd))\n+\t\t\t\tmatch = 0;\n+\t\t}\n+\t\tfree(data);\n+\t\tclose(fd);\n+\t}\n \treturn match;\n }\n \ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 0108ead..565daf3 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -108,9 +108,9 @@ test_expect_success 'Merge addition of text=auto' '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \techo \"<<<<<<<\" >expected &&\n-\techo first line | append_cr >>expected &&\n-\techo same line | append_cr >>expected &&\n-\techo ======= | append_cr >>expected &&\n+\techo first line >>expected &&\n+\techo same line >>expected &&\n+\techo ======= >>expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n@@ -121,14 +121,13 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \tfuzz_conflict file >file.fuzzy &&\n \tcompare_files expected file.fuzzy\n '\n-\n test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \techo \"<<<<<<<\" >expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n-\techo ======= | append_cr >>expected &&\n-\techo first line | append_cr >>expected &&\n-\techo same line | append_cr >>expected &&\n+\techo =======  >>expected &&\n+\techo first line >>expected &&\n+\techo same line  >>expected &&\n \techo \">>>>>>>\" >>expected &&\n \tgit config merge.renormalize false &&\n \trm -f .gitattributes &&\n@@ -138,6 +137,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \tcompare_files expected file.fuzzy\n '\n \n+\n test_expect_failure 'checkout -m after setting text=auto' '\n \tcat <<-\\EOF >expected &&\n \tfirst line\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284206","messageId":"xmqqbn51nvwt.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1461335908-5013-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v6 01/10] t0027: Make more reliable","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-22T22:03:30Z","receivedAt":"2016-04-22T22:03:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n> Subject: Re: [PATCH v6 01/10] t0027: Make more reliable\n\n\"Make more reliable\" does not sound very grammatical.\n\n> Make the commit_chk_wrnNNO test in t0027 more reliable:\n\nNeither is the colon at the end.\n\n> When the attributes of a commited file are changed and the file is otherwise\n> unchanged, Git may not detect that the next commit may need to treat the\n> file as changed.\n> This happens when lstat() doesn't detect a change, since neither inode,\n> mtime nor size are changed.\n>\n> Add a singe \"Z\" character to change the file size.\n> Ignore it when comparing the files later.\n>\n> Signed-off-by: Torsten Bögershausen <tboegi@web.de>\n> ---\n>  Changes since v5:\n>  - send the whole series, now 10/10\n>  - Removed the \"will change in future\" in one commit msg\n>  - Don't leak the filer in 4/10\n>  t/t0027-auto-crlf.sh | 3 ++-\n>  1 file changed, 2 insertions(+), 1 deletion(-)\n>\n> diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\n> index f33962b..9fe539b 100755\n> --- a/t/t0027-auto-crlf.sh\n> +++ b/t/t0027-auto-crlf.sh\n> @@ -12,7 +12,7 @@ fi\n>  \n>  compare_files () {\n>  \ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n> -\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n> +\ttr '\\015\\000' QN <\"$2\" | tr -d 'Z' >\"$2\".actual &&\n>  \ttest_cmp \"$1\".expect \"$2\".actual &&\n>  \trm \"$1\".expect \"$2\".actual\n>  }\n> @@ -114,6 +114,7 @@ commit_chk_wrnNNO () {\n>  \tdo\n>  \t\tfname=${pfx}_$f.txt &&\n>  \t\tcp $f $fname &&\n> +\t\tprintf Z >>\"$fname\" &&\n>  \t\tgit -c core.autocrlf=$crlf add $fname 2>/dev/null &&\n>  \t\tgit -c core.autocrlf=$crlf commit -m \"commit_$fname\" $fname >\"${pfx}_$f.err\" 2>&1\n>  \tdone\n"},{"id":"284233","messageId":"571C4144.2080701@web.de","threadId":"41391","inReplyTo":"xmqqbn51nvwt.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v6 01/10] t0027: Make more reliable","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-04-24T03:45:08Z","receivedAt":"2016-04-24T03:45:08Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 2016-04-23 00.03, Junio C Hamano wrote:\n> tboegi@web.de writes:\n> \n>> From: Torsten Bögershausen <tboegi@web.de>\n>> Subject: Re: [PATCH v6 01/10] t0027: Make more reliable\n> \n> \"Make more reliable\" does not sound very grammatical.\n> \n>> Make the commit_chk_wrnNNO test in t0027 more reliable:\n> \n> Neither is the colon at the end.\n> \n\nAfter Re-reading the series (with fresh eyes)\nI found more spelling errors, typos in different commit messages.\n9/10 is missing the SOB.\nHow about this for 1/10:\n\nSubject: [PATCH v6 01/10] t0027: Make commit_chk_wrnNNO() reliable\n\nWhen the content of a commited file is unchanged and the attributes are changed,\nGit may not detect that the next commit must treat the\nfile as changed.\nThis happens when lstat() doesn't detect a change, since neither inode,\nmtime nor size are changed.\n\nAdd a singe \"Z\" character to change the file size.\nIgnore it when comparing the files later.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n"},{"id":"284331","messageId":"1461510621-20887-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6b 01/10] t0027: Make commit_chk_wrnNNO() reliable","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-24T15:10:21Z","receivedAt":"2016-04-24T15:10:21Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen the content of a commited file is unchanged and the attributes are changed,\nGit may not detect that the next commit must treat the file as changed.\nThis happens when lstat() doesn't detect a change, since neither inode,\nmtime nor size are changed.\n\nAdd a singe \"Z\" character to change the file size (and content).\nWhen the files are compared later in checkout_files(), the \"Z\" is removed\nbefore the comparison.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\nChanges since v5:\n - send the whole series, now 10/10\n - Removed the \"will change in future\" in one commit msg\n - Don't leak the filer in 4/10\n t/t0027-auto-crlf.sh | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n Changes since v6:\n - Reword commit msg in 1/10\n - Add SOB in 9/10\n - Correct typos\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex f33962b..9fe539b 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -12,7 +12,7 @@ fi\n \n compare_files () {\n \ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n-\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n+\ttr '\\015\\000' QN <\"$2\" | tr -d 'Z' >\"$2\".actual &&\n \ttest_cmp \"$1\".expect \"$2\".actual &&\n \trm \"$1\".expect \"$2\".actual\n }\n@@ -114,6 +114,7 @@ commit_chk_wrnNNO () {\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n \t\tcp $f $fname &&\n+\t\tprintf Z >>\"$fname\" &&\n \t\tgit -c core.autocrlf=$crlf add $fname 2>/dev/null &&\n \t\tgit -c core.autocrlf=$crlf commit -m \"commit_$fname\" $fname >\"${pfx}_$f.err\" 2>&1\n \tdone\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284330","messageId":"1461510679-20927-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6b 02/10] convert: allow core.autocrlf=input and core.eol=crlf","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-24T15:11:19Z","receivedAt":"2016-04-24T15:11:19Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nEven though the configuration parser errors out when core.autocrlf\nis set to 'input' when core.eol is set to 'crlf', there is no need\nto do so, because the core.autocrlf setting trumps core.eol.\n\nAllow all combinations of core.crlf and core.eol and document\nthat core.autocrlf overrides core.eol.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt | 6 +++---\n config.c                 | 4 ----\n 2 files changed, 3 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 42d2b50..155f988 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -337,9 +337,9 @@ core.quotePath::\n \n core.eol::\n \tSets the line ending type to use in the working directory for\n-\tfiles that have the `text` property set.  Alternatives are\n-\t'lf', 'crlf' and 'native', which uses the platform's native\n-\tline ending.  The default value is `native`.  See\n+\tfiles that have the `text` property set when core.autocrlf is false.\n+\tAlternatives are 'lf', 'crlf' and 'native', which uses the platform's\n+\tnative line ending.  The default value is `native`.  See\n \tlinkgit:gitattributes[5] for more information on end-of-line\n \tconversion.\n \ndiff --git a/config.c b/config.c\nindex 4c92699..c8ac9c2 100644\n--- a/config.c\n+++ b/config.c\n@@ -803,8 +803,6 @@ static int git_default_core_config(const char *var, const char *value)\n \n \tif (!strcmp(var, \"core.autocrlf\")) {\n \t\tif (value && !strcasecmp(value, \"input\")) {\n-\t\t\tif (core_eol == EOL_CRLF)\n-\t\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\t\tauto_crlf = AUTO_CRLF_INPUT;\n \t\t\treturn 0;\n \t\t}\n@@ -830,8 +828,6 @@ static int git_default_core_config(const char *var, const char *value)\n \t\t\tcore_eol = EOL_NATIVE;\n \t\telse\n \t\t\tcore_eol = EOL_UNSET;\n-\t\tif (core_eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)\n-\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\treturn 0;\n \t}\n \n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284332","messageId":"1461510681-20966-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6b 03/10] t0027: test cases for combined attributes","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-24T15:11:21Z","receivedAt":"2016-04-24T15:11:21Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nAdd more test cases for the not normalized files (\"NNO\"). The\n\"text\" attribute is most important, use it as the first parameter.\n\"ident\", if set, is the second paramater followed by the eol\nattribute.  The eol attribute overrides core.autocrlf, which\noverrides core.eol.\nindent is not yet used, this will be done in the next commit.\n\nUse loops to test more combinations of attributes, like\n\"* text eol=crlf\" or especially \"*text=auto eol=crlf\".\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n t/t0027-auto-crlf.sh | 298 ++++++++++++++++++++++-----------------------------\n 1 file changed, 129 insertions(+), 169 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 9fe539b..fd5e326 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -52,14 +52,17 @@ create_gitattributes () {\n create_NNO_files () {\n \tfor crlf in false true input\n \tdo\n-\t\tfor attr in \"\" auto text -text lf crlf\n+\t\tfor attr in \"\" auto text -text\n \t\tdo\n-\t\t\tpfx=NNO_${crlf}_attr_${attr} &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tfor aeol in \"\" lf crlf\n+\t\t\tdo\n+\t\t\t\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tdone\n \t\tdone\n \tdone\n }\n@@ -100,16 +103,17 @@ commit_check_warn () {\n }\n \n commit_chk_wrnNNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfwarn=$3\n-\tcrlfwarn=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfwarn=$1 ; shift\n+\tcrlfwarn=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n \t#Commit files on top of existing file\n-\tcreate_gitattributes \"$attr\" &&\n+\tcreate_gitattributes \"$attr\" $aeol &&\n \tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n@@ -122,19 +126,19 @@ commit_chk_wrnNNO () {\n \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n \t'\n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF\" '\n \t\tcheck_warning \"$crlfwarn\" ${pfx}_CRLF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_mix_LF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_mix_LF\" '\n \t\tcheck_warning \"$lfmixcrlf\" ${pfx}_CRLF_mix_LF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF_mix_cr\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf LF_mix_cr\" '\n \t\tcheck_warning \"$lfmixcr\" ${pfx}_LF_mix_CR.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_nul\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_nul\" '\n \t\tcheck_warning \"$crlfnul\" ${pfx}_CRLF_nul.err\n \t'\n }\n@@ -163,6 +167,7 @@ stats_ascii () {\n \n # contruct the attr/ returned by git ls-files --eol\n # Take none (=empty), one or two args\n+# convert.c: eol=XX overrides text=auto\n attr_ascii () {\n \tcase $1,$2 in\n \t-text,*)   echo \"-text\" ;;\n@@ -170,8 +175,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text=auto eol=lf\" ;;\n-\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n+\tauto,lf)   echo \"text eol=lf\" ;;\n+\tauto,crlf) echo \"text eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -196,28 +201,29 @@ check_files_in_repo () {\n }\n \n check_in_repo_NNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfname=$3\n-\tcrlfname=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}_\n-\ttest_expect_success \"compare_files $lfname ${pfx}LF.txt\" '\n-\t\tcompare_files $lfname ${pfx}LF.txt\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfname=$1 ; shift\n+\tcrlfname=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\ttest_expect_success \"compare_files $lfname ${pfx}_LF.txt\" '\n+\t\tcompare_files $lfname ${pfx}_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfname ${pfx}CRLF.txt\" '\n-\t\tcompare_files $crlfname ${pfx}CRLF.txt\n+\ttest_expect_success \"compare_files $crlfname ${pfx}_CRLF.txt\" '\n+\t\tcompare_files $crlfname ${pfx}_CRLF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\" '\n-\t\tcompare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\n+\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\" '\n+\t\tcompare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcr ${pfx}LF_mix_CR.txt\" '\n-\t\tcompare_files $lfmixcr ${pfx}LF_mix_CR.txt\n+\ttest_expect_success \"compare_files $lfmixcr ${pfx}_LF_mix_CR.txt\" '\n+\t\tcompare_files $lfmixcr ${pfx}_LF_mix_CR.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfnul ${pfx}CRLF_nul.txt\" '\n-\t\tcompare_files $crlfnul ${pfx}CRLF_nul.txt\n+\ttest_expect_success \"compare_files $crlfnul ${pfx}_CRLF_nul.txt\" '\n+\t\tcompare_files $crlfnul ${pfx}_CRLF_nul.txt\n \t'\n }\n \n@@ -232,7 +238,7 @@ checkout_files () {\n \tlfmixcrlf=$1 ; shift\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n-\tcreate_gitattributes \"$attr\" \"$ident\" &&\n+\tcreate_gitattributes \"$attr\" $ident $aeol &&\n \tgit config core.autocrlf $crlf &&\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n@@ -245,7 +251,7 @@ checkout_files () {\n \t\tfi\n \tdone\n \n-\ttest_expect_success \"ls-files --eol attr=$attr $ident $aeol core.autocrlf=$crlf core.eol=$ceol\" '\n+\ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n \t\ttest_when_finished \"rm expect actual\" &&\n \t\tsort <<-EOF >expect &&\n \t\ti/crlf w/$(stats_ascii $crlfname) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF.txt\n@@ -260,19 +266,19 @@ checkout_files () {\n \t\tsort >actual &&\n \t\ttest_cmp expect actual\n \t'\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n \t\tcompare_ws_file $pfx $lfname    crlf_false_attr__LF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n \t\tcompare_ws_file $pfx $crlfname  crlf_false_attr__CRLF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n \t\tcompare_ws_file $pfx $lfmixcrlf crlf_false_attr__CRLF_mix_LF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n \t\tcompare_ws_file $pfx $lfmixcr   crlf_false_attr__LF_mix_CR.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n \t\tcompare_ws_file $pfx $crlfnul   crlf_false_attr__LF_nul.txt\n \t\"\n }\n@@ -386,31 +392,31 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                       attr   LF        CRLF      CRLFmixLF \t LF_mix_CR   CRLFNUL\n-commit_chk_wrnNNO false \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"\"     \"LF_CRLF\" \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-\n+#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO false \"auto\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"auto\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"auto\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n \n-commit_chk_wrnNNO false \"text\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"$WILC\"   \t \"$WICL\"\n-commit_chk_wrnNNO true  \"text\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"text\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"CRLF_LF\"\n-\n-commit_chk_wrnNNO false \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-\n-commit_chk_wrnNNO false \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO true  \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO input \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n+for crlf in true false input\n+do\n+\tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+done\n \n-commit_chk_wrnNNO false \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO true  \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n \n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n@@ -441,24 +447,20 @@ test_expect_success 'commit -text' '\n \tcheck_files_in_repo input \"-text\" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n '\n \n-#                       attr    LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLFNUL\n-check_in_repo_NNO false \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO true  \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO input \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-\n-check_in_repo_NNO false \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-\n+for crlf in true false input\n+do\n+\t#                 attr  aeol           LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLFNUL\n+\tcheck_in_repo_NNO \"\"    \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n # How to read the table below:\n@@ -490,89 +492,47 @@ LFNUL=LF_nul\n fi\n export CRLF_MIX_LF_CR MIX NL\n \n-checkout_files \"\"      \"\" \t \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   native   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   native   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\n-for id in \"\" ident;\n+# Same handling with and without ident\n+for id in \"\"\n do\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tfor ceol in lf crlf native\n+\tdo\n+\t\tfor crlf in true false input\n+\t\tdo\n+\t\t\t# -text overrides core.autocrlf and core.eol\n+\t\t\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n+\t\t\tcheckout_files -text \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files -text \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files -text \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\t# text\n+\t\t\tcheckout_files text  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\t# currently the same as text, eol=XXX\n+\t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tdone\n+\n+\t\t# core.autocrlf false, different core.eol\n+\t\tcheckout_files   \"\"    \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# core.autocrlf true\n+\t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# text: core.autocrlf = true overrides core.eol\n+\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t# text: core.autocrlf = input overrides core.eol\n+\t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# text=auto + eol=XXX\n+\tdone\n+\t# text: core.autocrlf=false uses core.eol\n+\tcheckout_files     text  \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\tcheckout_files     text  \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284334","messageId":"1461510683-21005-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6b 04/10] convert.c: ident + core.autocrlf didn't work","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-24T15:11:22Z","receivedAt":"2016-04-24T15:11:22Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen the ident attributes is set, get_stream_filter() did not obey\ncore.autocrlf=true, and the file was checked out with LF.\n\nChange the rule when a streaming filter can be used:\n- if an external filter is specified, don't use a stream filter.\n- if the worktree eol is CRLF and \"auto\" is active, don't use a stream filter.\n- Otherwise the stream filter can be used.\n\nAdd test cases in t0027.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c            | 19 +++++++------------\n t/t0027-auto-crlf.sh |  2 +-\n 2 files changed, 8 insertions(+), 13 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex f524b8d..b1614bf 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1380,27 +1380,22 @@ static struct stream_filter *ident_filter(const unsigned char *sha1)\n struct stream_filter *get_stream_filter(const char *path, const unsigned char *sha1)\n {\n \tstruct conv_attrs ca;\n-\tenum crlf_action crlf_action;\n \tstruct stream_filter *filter = NULL;\n \n \tconvert_attrs(&ca, path);\n-\n \tif (ca.drv && (ca.drv->smudge || ca.drv->clean))\n-\t\treturn filter;\n+\t\treturn NULL;\n+\n+\tif (ca.crlf_action == CRLF_AUTO || ca.crlf_action == CRLF_AUTO_CRLF)\n+\t\treturn NULL;\n \n \tif (ca.ident)\n \t\tfilter = ident_filter(sha1);\n \n-\tcrlf_action = ca.crlf_action;\n-\n-\tif ((crlf_action == CRLF_BINARY) ||\n-\t\t\tcrlf_action == CRLF_AUTO_INPUT ||\n-\t\t\t(crlf_action == CRLF_TEXT_INPUT))\n-\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n-\n-\telse if (output_eol(crlf_action) == EOL_CRLF &&\n-\t\t !(crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_CRLF))\n+\tif (output_eol(ca.crlf_action) == EOL_CRLF)\n \t\tfilter = cascade_filter(filter, lf_to_crlf_filter());\n+\telse\n+\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n \n \treturn filter;\n }\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex fd5e326..9372589 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -493,7 +493,7 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-for id in \"\"\n+for id in \"\" ident\n do\n \tfor ceol in lf crlf native\n \tdo\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284333","messageId":"1461510684-21044-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6b 05/10] read-cache: factor out get_sha1_from_index() helper","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-24T15:11:24Z","receivedAt":"2016-04-24T15:11:24Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nFactor out the retrieval of the sha1 for a given path in\nread_blob_data_from_index() into the function get_sha1_from_index().\n\nThis will be used in the next commit, when convert.c can do the\nanalyze for \"text=auto\" without slurping the whole blob into memory\nat once.\n\nAdd a wrapper definition get_sha1_from_cache().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n cache.h      |  3 +++\n read-cache.c | 29 ++++++++++++++++++-----------\n 2 files changed, 21 insertions(+), 11 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 2711048..867ceb5 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -379,6 +379,7 @@ extern void free_name_hash(struct index_state *istate);\n #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)\n #define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)\n #define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))\n+#define get_sha1_from_cache(path)  get_sha1_from_index (&the_index, (path))\n #endif\n \n enum object_type {\n@@ -1040,6 +1041,8 @@ static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *\n \treturn read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);\n }\n \n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path);\n+\n /*\n  * This internal function is only declared here for the benefit of\n  * lookup_replace_object().  Please do not call it directly.\ndiff --git a/read-cache.c b/read-cache.c\nindex d9fb78b..a3ef967 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -2263,13 +2263,27 @@ int index_name_is_other(const struct index_state *istate, const char *name,\n \n void *read_blob_data_from_index(struct index_state *istate, const char *path, unsigned long *size)\n {\n-\tint pos, len;\n+\tconst unsigned char *sha1;\n \tunsigned long sz;\n \tenum object_type type;\n \tvoid *data;\n \n-\tlen = strlen(path);\n-\tpos = index_name_pos(istate, path, len);\n+\tsha1 = get_sha1_from_index(istate, path);\n+\tif (!sha1)\n+\t\treturn NULL;\n+\tdata = read_sha1_file(sha1, &type, &sz);\n+\tif (!data || type != OBJ_BLOB) {\n+\t\tfree(data);\n+\t\treturn NULL;\n+\t}\n+\tif (size)\n+\t\t*size = sz;\n+\treturn data;\n+}\n+\n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path)\n+{\n+\tint pos = index_name_pos(istate, path, strlen(path));\n \tif (pos < 0) {\n \t\t/*\n \t\t * We might be in the middle of a merge, in which\n@@ -2285,14 +2299,7 @@ void *read_blob_data_from_index(struct index_state *istate, const char *path, un\n \t}\n \tif (pos < 0)\n \t\treturn NULL;\n-\tdata = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);\n-\tif (!data || type != OBJ_BLOB) {\n-\t\tfree(data);\n-\t\treturn NULL;\n-\t}\n-\tif (size)\n-\t\t*size = sz;\n-\treturn data;\n+\treturn (istate->cache[pos]->sha1);\n }\n \n void stat_validity_clear(struct stat_validity *sv)\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284329","messageId":"1461510686-21083-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6b 06/10] convert.c: stream and early out","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-24T15:11:26Z","receivedAt":"2016-04-24T15:11:26Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen statistics are done for the autocrlf handling, the search in\nthe content can be stopped, if e.g\n- a search for binary is done, and a NUL character is found\n- a search for CRLF is done, and the first CRLF is found.\n\nSimilar when statistics for binary vs non-binary are gathered:\nWhenever a lone CR or NUL is found, the search can be aborted.\n\nWhen checking out files in \"auto\" mode, any file that has a \"lone CR\"\nor a CRLF will not be converted, so the search can be aborted early.\n\nAdd the new bit, CONVERT_STAT_BITS_ANY_CR,\nwhich is set for either lone CR or CRLF.\n\nMany binary files have a NUL very early (within the first few bytes,\nlatest within the first 1..2K).\nIt is often not necessary to load the whole content of a file or blob\ninto memory.\n\nUse a streaming handling for blobs and files in the worktree.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c | 159 ++++++++++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 103 insertions(+), 56 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex b1614bf..24ab095 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -3,6 +3,7 @@\n #include \"run-command.h\"\n #include \"quote.h\"\n #include \"sigchain.h\"\n+#include \"streaming.h\"\n \n /*\n  * convert.c - convert a file when checking it out and checking it in.\n@@ -13,10 +14,10 @@\n  * translation when the \"text\" attribute or \"auto_crlf\" option is set.\n  */\n \n-/* Stat bits: When BIN is set, the txt bits are unset */\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n+#define CONVERT_STAT_BITS_ANY_CR    0x8\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -31,30 +32,36 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned nul, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonecr, lonelf, crlf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n };\n \n-static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)\n+static void do_gather_stats(const char *buf, unsigned long size,\n+\t\t\t    struct text_stat *stats, unsigned earlyout)\n {\n \tunsigned long i;\n \n-\tmemset(stats, 0, sizeof(*stats));\n-\n+\tif (!buf || !size)\n+\t\treturn;\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n \t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n-\t\t\t} else\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\t} else {\n \t\t\t\tstats->lonecr++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+\t\t\t}\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == '\\n') {\n \t\t\tstats->lonelf++;\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_LF;\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == 127)\n@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t\t\tstats->printable++;\n \t\t\t\tbreak;\n \t\t\tcase 0:\n-\t\t\t\tstats->nul++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t\t/* fall through */\n \t\t\tdefault:\n \t\t\t\tstats->nonprintable++;\n@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t}\n \t\telse\n \t\t\tstats->printable++;\n+\t\tif (stats->stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n \t}\n \n \t/* If file ends with EOF then don't count this EOF as non-printable. */\n@@ -86,41 +95,62 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n  * The same heuristics as diff.c::mmfile_is_binary()\n  * We treat files with bare CR as binary\n  */\n-static int convert_is_binary(unsigned long size, const struct text_stat *stats)\n+static void convert_nonprintable(struct text_stat *stats)\n {\n-\tif (stats->lonecr)\n-\t\treturn 1;\n-\tif (stats->nul)\n-\t\treturn 1;\n \tif ((stats->printable >> 7) < stats->nonprintable)\n-\t\treturn 1;\n-\treturn 0;\n+\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+}\n+\n+static void gather_stats(const char *buf, unsigned long size,\n+\t\t\t struct text_stat *stats, unsigned earlyout)\n+{\n+\tmemset(stats, 0, sizeof(*stats));\n+\tdo_gather_stats(buf, size, stats, earlyout);\n+\tconvert_nonprintable(stats);\n }\n \n-static unsigned int gather_convert_stats(const char *data, unsigned long size)\n+\n+static unsigned get_convert_stats_sha1(unsigned const char *sha1,\n+\t\t\t\t       unsigned earlyout)\n {\n+\tstruct git_istream *st;\n \tstruct text_stat stats;\n-\tint ret = 0;\n-\tif (!data || !size)\n-\t\treturn 0;\n-\tgather_stats(data, size, &stats);\n-\tif (convert_is_binary(size, &stats))\n-\t\tret |= CONVERT_STAT_BITS_BIN;\n-\tif (stats.crlf)\n-\t\tret |= CONVERT_STAT_BITS_TXT_CRLF;\n-\tif (stats.lonelf)\n-\t\tret |=  CONVERT_STAT_BITS_TXT_LF;\n+\tenum object_type type;\n+\tunsigned long sz;\n \n-\treturn ret;\n+\tif (!sha1)\n+\t\treturn 0;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tst = open_istream(sha1, &type, &sz, NULL);\n+\tif (!st) {\n+\t\treturn 0;\n+\t}\n+\tif (type != OBJ_BLOB)\n+\t\tgoto close_and_exit_i;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read_istream(st, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+close_and_exit_i:\n+\tclose_istream(st);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n }\n \n-static const char *gather_convert_stats_ascii(const char *data, unsigned long size)\n+static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned int convert_stats = gather_convert_stats(data, size);\n-\n+\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n+\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats) {\n+\tswitch (convert_stats & mask) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -132,24 +162,45 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si\n \t}\n }\n \n+static unsigned get_convert_stats_wt(const char *path)\n+{\n+\tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tint fd;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tfd = open(path, O_RDONLY);\n+\tif (fd < 0)\n+\t\treturn 0;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read(fd, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+\tclose(fd);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n+}\n+\n const char *get_cached_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret;\n-\tunsigned long sz;\n-\tvoid *data = read_blob_data_from_cache(path, &sz);\n-\tret = gather_convert_stats_ascii(data, sz);\n-\tfree(data);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n const char *get_wt_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret = \"\";\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (strbuf_read_file(&sb, path, 0) >= 0)\n-\t\tret = gather_convert_stats_ascii(sb.buf, sb.len);\n-\tstrbuf_release(&sb);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_wt(path);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n static int text_eol_is_crlf(void)\n@@ -219,16 +270,10 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \n static int has_cr_in_index(const char *path)\n {\n-\tunsigned long sz;\n-\tvoid *data;\n-\tint has_cr;\n-\n-\tdata = read_blob_data_from_cache(path, &sz);\n-\tif (!data)\n-\t\treturn 0;\n-\thas_cr = memchr(data, '\\r', sz) != NULL;\n-\tfree(data);\n-\treturn has_cr;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n+\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -249,10 +294,10 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \n \t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n@@ -309,11 +354,13 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n+\n \n \tif (!len || output_eol(crlf_action) != EOL_CRLF)\n \t\treturn 0;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, earlyout);\n \n \t/* No \"naked\" LF? Nothing to convert, regardless. */\n \tif (!stats.lonelf)\n@@ -327,7 +374,7 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\t\t\treturn 0;\n \t\t}\n \n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \t}\n \n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284335","messageId":"1461510687-21122-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6b 07/10] convert: unify the \"auto\" handling of CRLF","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-24T15:11:27Z","receivedAt":"2016-04-24T15:11:27Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nBefore this change,\n$ echo \"* text=auto\" >.gitattributes\n$ echo \"* eol=crlf\" >>.gitattributes\n\nwould have the same effect as\n$ echo \"* text\" >.gitattributes\n$ git config core.eol crlf\n\nSince the 'eol' attribute had higher priority than 'text=auto', this may\ncorrupt binary files and is not what users expect to happen.\n\nMake the 'eol' attribute to obey 'text=auto', and now\n$ echo \"* text=auto\" >.gitattributes\n$ echo \"* eol=crlf\" >>.gitattributes\nbehaves the same as\n$ echo \"* text=auto\" >.gitattributes\n$ git config core.eol crlf\n\nIn other words,\n$ echo \"* text=auto eol=crlf\" >.gitattributes\nhas the same effect as\n$ git config core.autocrlf true\n\nand\n$ echo \"* text=auto eol=lf\" >.gitattributes\nhas the same effect as\n$ git config core.autocrlf input\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt        | 14 +++++++-------\n Documentation/gitattributes.txt | 15 +++++++++------\n convert.c                       | 42 +++++++++++++++++++++--------------------\n convert.h                       |  3 ++-\n t/t0025-crlf-auto.sh            |  4 ++--\n t/t0027-auto-crlf.sh            | 32 +++++++++++++++----------------\n t/t6038-merge-text-auto.sh      | 23 ++++++++++++++--------\n 7 files changed, 73 insertions(+), 60 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 155f988..117c2f3 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf`\n mechanism.\n \n core.autocrlf::\n-\tSetting this variable to \"true\" is almost the same as setting\n-\tthe `text` attribute to \"auto\" on all files except that text\n-\tfiles are not guaranteed to be normalized: files that contain\n-\t`CRLF` in the repository will not be touched.  Use this\n-\tsetting if you want to have `CRLF` line endings in your\n-\tworking directory even though the repository does not have\n-\tnormalized line endings.  This variable can be set to 'input',\n+\tSetting this variable to \"true\" is the same as setting\n+\tthe `text` attribute to \"auto\" on all files and core.eol to \"crlf\".\n+\tSet to true if you want to have `CRLF` line endings in your\n+\tworking directory and the repository has LF line endings.\n+\tText files are guaranteed not to be normalized: files that contain\n+\t`CRLF` in the repository will not be touched.\n+\tThis variable can be set to 'input',\n \tin which case no output conversion is performed.\n \n core.symlinks::\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex e3b1de8..d7a124b 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n `core.eol` configuration variable for all text files.\n+Note that `core.autocrlf` overrides `core.eol`\n \n Set::\n \n@@ -130,8 +131,9 @@ Unset::\n Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n-\tend-of-line normalization.  If Git decides that the content is\n-\ttext, its line endings are normalized to LF on checkin.\n+\tend-of-line conversion.  If Git decides that the content is\n+\ttext, its line endings are converted to LF on checkin.\n+\tWhen the file has been commited with CRLF, no conversion is done.\n \n Unspecified::\n \n@@ -146,7 +148,7 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It enables end-of-line normalization without any\n+working directory.  It enables end-of-line conversion without any\n content checks, effectively setting the `text` attribute.\n \n Set to string value \"crlf\"::\n@@ -186,9 +188,10 @@ the working directory, and prevent .jpg files from being normalized\n regardless of their content.\n \n ------------------------\n+*               text=auto\n *.txt\t\ttext\n-*.vcproj\teol=crlf\n-*.sh\t\teol=lf\n+*.vcproj\ttext eol=crlf\n+*.sh\t\ttext eol=lf\n *.jpg\t\t-text\n ------------------------\n \n@@ -198,7 +201,7 @@ normalization in Git.\n \n If you simply want to have CRLF line endings in your working directory\n regardless of the repository you are working with, you can set the\n-config variable \"core.autocrlf\" without changing any attributes.\n+config variable \"core.autocrlf\" without using any attributes.\n \n ------------------------\n [core]\ndiff --git a/convert.c b/convert.c\nindex 24ab095..3782172 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -227,7 +227,9 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \t\treturn EOL_LF;\n \tcase CRLF_UNDEFINED:\n \tcase CRLF_AUTO_CRLF:\n+\t\treturn EOL_CRLF;\n \tcase CRLF_AUTO_INPUT:\n+\t\treturn EOL_LF;\n \tcase CRLF_TEXT:\n \tcase CRLF_AUTO:\n \t\t/* fall through */\n@@ -299,17 +301,15 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/*\n-\t\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t\t * This is the new safer autocrlf handling.\n-\t\t\t */\n-\t\t\tif (has_cr_in_index(path))\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/*\n+\t\t * If the file in the index has any CR in it, do not convert.\n+\t\t * This is the new safer autocrlf handling.\n+\t\t */\n+\t\tif (checksafe == SAFE_CRLF_RENORMALIZE)\n+\t\t\tchecksafe = SAFE_CRLF_FALSE;\n+\t\telse if (has_cr_in_index(path))\n+\t\t\treturn 0;\n \t}\n-\n \tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n \n \t/* Optimization: No CRLF? Nothing to convert, regardless. */\n@@ -367,12 +367,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\treturn 0;\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t\t/* This is the new safer autocrlf-handling */\n-\t\t\tif (stats.lonecr || stats.crlf )\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n+\t\t/* This is the new safer autocrlf-handling */\n+\t\tif (stats.lonecr || stats.crlf )\n+\t\t\treturn 0;\n \n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n@@ -833,7 +831,11 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tca->drv = git_path_check_convert(ccheck + 2);\n \t\tif (ca->crlf_action != CRLF_BINARY) {\n \t\t\tenum eol eol_attr = git_path_check_eol(ccheck + 3);\n-\t\t\tif (eol_attr == EOL_LF)\n+\t\t\tif (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_INPUT;\n+\t\t\telse if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_CRLF;\n+\t\t\telse if (eol_attr == EOL_LF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_INPUT;\n \t\t\telse if (eol_attr == EOL_CRLF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_CRLF;\n@@ -892,9 +894,9 @@ const char *get_convert_attr_ascii(const char *path)\n \tcase CRLF_AUTO:\n \t\treturn \"text=auto\";\n \tcase CRLF_AUTO_CRLF:\n-\t\treturn \"text=auto eol=crlf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=crlf\";\n \tcase CRLF_AUTO_INPUT:\n-\t\treturn \"text=auto eol=lf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=lf\";\n \t}\n \treturn \"\";\n }\n@@ -996,7 +998,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_FALSE);\n+\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n }\n \n /*****************************************************************\ndiff --git a/convert.h b/convert.h\nindex ccf436b..81b6cdf 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -7,7 +7,8 @@\n enum safe_crlf {\n \tSAFE_CRLF_FALSE = 0,\n \tSAFE_CRLF_FAIL = 1,\n-\tSAFE_CRLF_WARN = 2\n+\tSAFE_CRLF_WARN = 2,\n+\tSAFE_CRLF_RENORMALIZE = 4\n };\n \n extern enum safe_crlf safe_crlf;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex c164b46..d0bee08 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -114,7 +114,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n+test_expect_success 'text=auto, autocrlf=true does not normalize CRLF files' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \tgit config core.autocrlf true &&\n@@ -126,7 +126,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n \tLFonlydiff=$(git diff LFonly) &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n \tLFwithNULdiff=$(git diff LFwithNUL) &&\n-\ttest -z \"$LFonlydiff\" -a -n \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n+\ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 9372589..8367d0b 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -175,8 +175,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text eol=lf\" ;;\n-\tauto,crlf) echo \"text eol=crlf\" ;;\n+\tauto,lf)   echo \"text=auto eol=lf\" ;;\n+\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -397,10 +397,9 @@ commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n-\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n@@ -408,8 +407,8 @@ do\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n \tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n \tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n done\n@@ -454,9 +453,9 @@ do\n \tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n@@ -493,7 +492,8 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-for id in \"\" ident\n+#for id in \"\" ident\n+for id in \"\"\n do\n \tfor ceol in lf crlf native\n \tdo\n@@ -509,7 +509,7 @@ do\n \t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n \t\t\t# currently the same as text, eol=XXX\n \t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \n \t\t# core.autocrlf false, different core.eol\n@@ -517,7 +517,7 @@ do\n \t\t# core.autocrlf true\n \t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n \t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n@@ -531,8 +531,8 @@ do\n \tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 85c10b0..33b77ee 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -16,6 +16,13 @@ test_description='CRLF merge conflict across text=auto change\n \n test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b\n \n+compare_files () {\n+\ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n+\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n+\ttest_cmp \"$1\".expect \"$2\".actual &&\n+\trm \"$1\".expect \"$2\".actual\n+}\n+\n test_expect_success setup '\n \tgit config core.autocrlf false &&\n \n@@ -30,7 +37,7 @@ test_expect_success setup '\n \tgit branch side &&\n \n \techo \"* text=auto\" >.gitattributes &&\n-\ttouch file &&\n+\techo first line >file &&\n \tgit add .gitattributes file &&\n \ttest_tick &&\n \tgit commit -m \"normalize file\" &&\n@@ -81,7 +88,7 @@ test_expect_success 'Merge after setting text=auto' '\n \trm -f .gitattributes &&\n \tgit reset --hard a &&\n \tgit merge b &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_success 'Merge addition of text=auto' '\n@@ -99,7 +106,7 @@ test_expect_success 'Merge addition of text=auto' '\n \trm -f .gitattributes &&\n \tgit reset --hard b &&\n \tgit merge a &&\n-\ttest_cmp expected file\n+\tcompare_files  expected file\n '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n@@ -121,7 +128,7 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \tgit reset --hard a &&\n \ttest_must_fail git merge b &&\n \tfuzz_conflict file >file.fuzzy &&\n-\ttest_cmp expected file.fuzzy\n+\tcompare_files expected file.fuzzy\n '\n \n test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n@@ -143,7 +150,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \tgit reset --hard b &&\n \ttest_must_fail git merge a &&\n \tfuzz_conflict file >file.fuzzy &&\n-\ttest_cmp expected file.fuzzy\n+\tcompare_files expected file.fuzzy\n '\n \n test_expect_failure 'checkout -m after setting text=auto' '\n@@ -158,7 +165,7 @@ test_expect_failure 'checkout -m after setting text=auto' '\n \tgit reset --hard initial &&\n \tgit checkout a -- . &&\n \tgit checkout -m b &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_failure 'checkout -m addition of text=auto' '\n@@ -173,7 +180,7 @@ test_expect_failure 'checkout -m addition of text=auto' '\n \tgit reset --hard initial &&\n \tgit checkout b -- . &&\n \tgit checkout -m a &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_failure 'cherry-pick patch from after text=auto was added' '\n@@ -187,7 +194,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' '\n \tgit reset --hard b &&\n \ttest_must_fail git cherry-pick a >err 2>&1 &&\n \tgrep \"[Nn]othing added\" err &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_success 'Test delete/normalize conflict' '\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284338","messageId":"1461510689-21161-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6b 08/10] convert.c: more safer crlf handling with text attribute","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-24T15:11:29Z","receivedAt":"2016-04-24T15:11:29Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nThis patch extends the work done in commit c480539:\n\"Make it work also for un-normalized repositories\". Make sure that CRLF\ncan be converted round trip, or don't convert them at all.\n\nThe old handling would treat a file as unchanged after checkout,\nas long as it is not touched in the work tree and mtime matches the value\nrecorded in the index.\nWhen the mtime is changed in the working tree, or the inode is changed,\nthe file is reported as modified.\n\nThe following sequence is now handled reproducable:\n$ git init\n$ printf \"line1\\r\\n\" >file.bat\n$ git add file.bat\n$ git commit -m \"Add file with CRLF\" file.bat\n$ echo \"*.bat text eol=crlf\" >.gitattributes\n$ git commit -m \"bat files should have CRLF\"\n$ git status\n # nothing to commit, working directory clean\n$ git push <upstream>\n$ printf \"newline\\r\\n\" >>file.bat\n$ mv file.bat file.sav\n$ git checkout file.bat\n$ git status\n #modified:   file.bat\n\nThe new handling makes sure that after running \"git reset --hard\".\n\"git status\" reports the working tree as clean regarding CRLF conversion.\nIt makes sure that the Git-internal eol conversion is\ndoing roundtrip. A user can still write an external smudge/clean filter\noutside Git, which doesn't do a roundtrip and the working directory is\nnot clean.\n\nThe functionality of has_cr_in_index() is turned into has_crlf_in_index(),\nand the function is integrated into would_convert_crlf_at_commit().\n\nCheck for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR\nis no longer used and removed, as well as \"lonecr\" in struct text_stat.\n\nRewrite check_safe_crlf() in convert.c to simulate checkin-checkout,\nto detect whether any line endings are converted.\n\nAdd a warning, similar to the CRLF-LF replacement, when a file is commited,\nand after the next checkout the line endings are not what they should be.\n\nModify the lf_to_crlf_filter:\nFiles with LF are converted into CRLF, file with CRLF are not changed.\nFiles with mixed line endings are not converted, the filter fails, and Git\nfalls back to the non-streaming handling, see write_entry().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/gitattributes.txt |  19 ++--\n convert.c                       | 233 +++++++++++++++++++++++++---------------\n t/t0025-crlf-auto.sh            |   8 +-\n t/t0027-auto-crlf.sh            |  92 ++++++++--------\n 4 files changed, 212 insertions(+), 140 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex d7a124b..836461d 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'.\n `text`\n ^^^^^^\n \n-This attribute enables and controls end-of-line normalization.  When a\n+This attribute enables and controls end-of-line conversion.  When a\n text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol`\n Set::\n \n \tSetting the `text` attribute on a path enables end-of-line\n-\tnormalization and marks the path as a text file.  End-of-line\n+\tconversion and marks the path as a text file.  End-of-line\n \tconversion takes place without guessing the content type.\n+\tFiles that have been commited with CRLF before the text attribute\n+\tis set and commited are not normalized. No end-of-line conversion\n+\tis done at checkout or checkin.\n \n Unset::\n \n@@ -131,9 +134,9 @@ Unset::\n Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n-\tend-of-line conversion.  If Git decides that the content is\n-\ttext, its line endings are converted to LF on checkin.\n-\tWhen the file has been commited with CRLF, no conversion is done.\n+\tend-of-line normalization.  If Git decides that the content is\n+\ttext, and the path has no CRLF in the index,\n+\tits line endings are converted to LF on checkin.\n \n Unspecified::\n \n@@ -148,8 +151,10 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It enables end-of-line conversion without any\n-content checks, effectively setting the `text` attribute.\n+working directory.  It sets the `text` attribute, unless `text=auto`\n+is specified.\n+When the file had been commited with CRLF in the index, no conversion\n+is done at checkout or commit.\n \n Set to string value \"crlf\"::\n \ndiff --git a/convert.c b/convert.c\nindex 3782172..8d4c42a 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -17,7 +17,8 @@\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n-#define CONVERT_STAT_BITS_ANY_CR    0x8\n+\n+#define CONVERT_STAT_BITS_MIXED (CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF)\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -32,7 +33,7 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned stat_bits, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonelf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n@@ -48,13 +49,10 @@ static void do_gather_stats(const char *buf, unsigned long size,\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n-\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n-\t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n \t\t\t} else {\n-\t\t\t\tstats->lonecr++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t}\n \t\t\tcontinue;\n@@ -135,7 +133,7 @@ static unsigned get_convert_stats_sha1(unsigned const char *sha1,\n \t\tif (!readlen)\n \t\t\tbreak;\n \t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n-\t\tif (stats.stat_bits & earlyout)\n+\t\tif ((stats.stat_bits & earlyout) == earlyout)\n \t\t\tbreak; /* We found what we have been searching for */\n \t}\n close_and_exit_i:\n@@ -146,11 +144,9 @@ close_and_exit_i:\n \n static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n-\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats & mask) {\n+\tswitch (convert_stats) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -162,7 +158,16 @@ static const char *convert_stats_ascii(unsigned convert_stats)\n \t}\n }\n \n-static unsigned get_convert_stats_wt(const char *path)\n+const char *get_cached_convert_stats_ascii(const char *path)\n+{\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n+}\n+\n+const char *get_wt_convert_stats_ascii(const char *path)\n {\n \tstruct text_stat stats;\n \tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n@@ -184,23 +189,7 @@ static unsigned get_convert_stats_wt(const char *path)\n \t}\n \tclose(fd);\n \tconvert_nonprintable(&stats);\n-\treturn stats.stat_bits;\n-}\n-\n-const char *get_cached_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n-\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n-\t\t\t\t\t       earlyout);\n-\treturn convert_stats_ascii(convert_stats);\n-}\n-\n-const char *get_wt_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_wt(path);\n-\treturn convert_stats_ascii(convert_stats);\n+\treturn convert_stats_ascii(stats.stat_bits);\n }\n \n static int text_eol_is_crlf(void)\n@@ -239,43 +228,95 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \treturn core_eol;\n }\n \n+static int would_convert_lf_at_checkout(unsigned convert_stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tif (output_eol(crlf_action) != EOL_CRLF)\n+\t\treturn 0;\n+\n+\t/* No \"naked\" LF? Nothing to convert, regardless. */\n+\tif (!convert_stats & CONVERT_STAT_BITS_TXT_LF)\n+\t\treturn 0;\n+\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\t/* auto: binary files are not converted */\n+\t\tif (convert_stats & CONVERT_STAT_BITS_BIN)\n+\t\t\treturn 0;\n+\t}\n+\t/* If we have any CRLF line endings, we do not touch it */\n+\t/* This is the new safer autocrlf-handling */\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+\n+}\n+\n+static int would_convert_crlf_at_commit(const char * path,\n+\t\t\t\t\tconst struct text_stat *stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tunsigned stat_bits_index;\n+\t/* No CRLF? Nothing to convert, regardless. */\n+\tif (!(stats->stat_bits & CONVERT_STAT_BITS_TXT_CRLF))\n+\t\treturn 0;\n+\t/*\n+\t * If the file in the index has any CRLF in it, do not convert.\n+\t * This is the new safer autocrlf handling.\n+\t */\n+\tstat_bits_index = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t\t CONVERT_STAT_BITS_TXT_CRLF);\n+\tif (stat_bits_index & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+}\n+\n static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n-                            struct text_stat *stats, enum safe_crlf checksafe)\n+\t\t\t    enum safe_crlf checksafe,\n+\t\t\t    unsigned convert_stats, unsigned new_convert_stats)\n {\n+\tenum eol new_eol = output_eol(crlf_action);\n+\tconst char *err_warn_msg = NULL;\n \tif (!checksafe)\n \t\treturn;\n-\n-\tif (output_eol(crlf_action) == EOL_LF) {\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n \t\t/*\n \t\t * CRLFs would not be restored by checkout:\n \t\t * check if we'd remove CRLFs\n \t\t */\n-\t\tif (stats->crlf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n-\t\t}\n-\t} else if (output_eol(crlf_action) == EOL_CRLF) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n+\t}\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_LF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_LF)) {\n \t\t/*\n \t\t * CRLFs would be added by checkout:\n \t\t * check if we have \"naked\" LFs\n \t\t */\n-\t\tif (stats->lonelf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n-\t\t}\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n+\t}\n+\tif ((new_convert_stats & CONVERT_STAT_BITS_MIXED) == CONVERT_STAT_BITS_MIXED)\n+\t\terr_warn_msg = \"mixed eol\";\n+\telse if (new_eol == EOL_LF && new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\terr_warn_msg = \"CRLF\";\n+\n+\tif (err_warn_msg) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"%s will be present after commit and checkout in %s.\",\n+\t\t\t\terr_warn_msg, path);\n+\t\telse\n+\t\t\tdie(\"%s will be present after commit and checkout in %s\",\n+\t\t\t    err_warn_msg, path);\n \t}\n-}\n-\n-static int has_cr_in_index(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n-\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n-\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -284,7 +325,7 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n {\n \tstruct text_stat stats;\n \tchar *dst;\n-\n+\tint convert_crlf;\n \tif (crlf_action == CRLF_BINARY ||\n \t    (src && !len))\n \t\treturn 0;\n@@ -296,24 +337,42 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n-\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\t\t/*\n-\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t * This is the new safer autocrlf handling.\n-\t\t */\n-\t\tif (checksafe == SAFE_CRLF_RENORMALIZE)\n-\t\t\tchecksafe = SAFE_CRLF_FALSE;\n-\t\telse if (has_cr_in_index(path))\n-\t\t\treturn 0;\n+\t} else {\n+\t\tgather_stats(src, len, &stats, 0);\n+\t}\n+\tif (checksafe == SAFE_CRLF_RENORMALIZE) {\n+\t\tconvert_crlf = 1;\n+\t\tchecksafe = SAFE_CRLF_FALSE;\n+\t} else {\n+\t\tconvert_crlf = would_convert_crlf_at_commit(path, &stats, len,\n+\t\t\t\t\t\t\t    crlf_action);\n \t}\n-\tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n \n-\t/* Optimization: No CRLF? Nothing to convert, regardless. */\n-\tif (!stats.crlf)\n+\tif (checksafe) {\n+\t\tunsigned convert_stats = stats.stat_bits;\n+\t\tunsigned new_convert_stats = convert_stats;\n+\t\t/* Simulate commit */\n+\t\tif (convert_crlf &&\n+\t\t    (new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_LF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t}\n+\t\t/* Simulate checkout */\n+\t\tif (would_convert_lf_at_checkout(new_convert_stats,\n+\t\t\t\t\t\t len, crlf_action)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_LF;\n+\t\t}\n+\t\tcheck_safe_crlf(path, crlf_action, checksafe,\n+\t\t\t\tconvert_stats, new_convert_stats);\n+\t}\n+\tif (!convert_crlf)\n \t\treturn 0;\n \n \t/*\n@@ -327,7 +386,9 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (strbuf_avail(buf) + buf->len < len)\n \t\tstrbuf_grow(buf, len - buf->len);\n \tdst = buf->buf;\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n \t\t/*\n \t\t * If we guessed, we already know we rejected a file with\n \t\t * lone CR, and we can strip a CR without looking at what\n@@ -354,28 +415,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n-\n-\n-\tif (!len || output_eol(crlf_action) != EOL_CRLF)\n+\tunsigned earlyout = 0; /* Need to count lonelf */\n+\tif (!len)\n \t\treturn 0;\n \n \tgather_stats(src, len, &stats, earlyout);\n-\n-\t/* No \"naked\" LF? Nothing to convert, regardless. */\n-\tif (!stats.lonelf)\n+\tif (!would_convert_lf_at_checkout(stats.stat_bits,\n+\t\t\t\t\t  len, crlf_action))\n \t\treturn 0;\n \n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t/* This is the new safer autocrlf-handling */\n-\t\tif (stats.lonecr || stats.crlf )\n-\t\t\treturn 0;\n-\n-\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n-\t\t\treturn 0;\n-\t}\n-\n \t/* are we \"faking\" in place editing ? */\n \tif (src == buf->buf)\n \t\tto_free = strbuf_detach(buf, NULL);\n@@ -1067,6 +1115,8 @@ int is_null_stream_filter(struct stream_filter *filter)\n struct lf_to_crlf_filter {\n \tstruct stream_filter filter;\n \tunsigned has_held:1;\n+\tunsigned expanded_loneLF:1;\n+\tunsigned had_CRLF:1;\n \tchar held;\n };\n \n@@ -1107,7 +1157,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \t\t\tchar ch = input[i];\n \n \t\t\tif (ch == '\\n') {\n-\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\tif (!lf_to_crlf->had_CRLF) {\n+\t\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\t\tlf_to_crlf->expanded_loneLF = 1;\n+\t\t\t\t}\n+\t\t\t\tif (was_cr)\n+\t\t\t\t\tlf_to_crlf->had_CRLF = 1;\n \t\t\t} else if (was_cr) {\n \t\t\t\t/*\n \t\t\t\t * Previous round saw CR and it is not followed\n@@ -1136,6 +1191,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \n \t\t\twas_cr = 0;\n \t\t\toutput[o++] = ch;\n+\t\t\tif (lf_to_crlf->expanded_loneLF &&\n+\t\t\t    lf_to_crlf->had_CRLF) {\n+\t\t\t\t/*\n+\t\t\t\t * Mixed EOL, round trip not possible.\n+\t\t\t\t */\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n \t\t}\n \n \t\t*osize_p -= o;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex d0bee08..b5f93e2 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n+test_expect_success 'crlf=true causes a CRLF file not to be normalized' '\n \n \t# Backwards compatibility check\n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n-test_expect_success 'text=true causes a CRLF file to be normalized' '\n+test_expect_success 'text=true causes a CRLF file not to be normalized' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \techo \"CRLFonly text\" > .gitattributes &&\n@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 8367d0b..a16e513 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -71,10 +71,14 @@ check_warning () {\n \tcase \"$1\" in\n \tLF_CRLF) echo \"warning: LF will be replaced by CRLF\" >\"$2\".expect ;;\n \tCRLF_LF) echo \"warning: CRLF will be replaced by LF\" >\"$2\".expect ;;\n+\tCRLF)    echo \"warning: CRLF will be present after commit and checkout\" >\"$2\".expect ;;\n+\tmixed)   echo \"warning: mixed eol will be present after commit and checkout\" >\"$2\".expect ;;\n \t'')\t                                                 >\"$2\".expect ;;\n \t*) echo >&2 \"Illegal 1\": \"$1\" ; return false ;;\n \tesac\n-\tgrep \"will be replaced by\" \"$2\" | sed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" | uniq  >\"$2\".actual\n+\tegrep \"will be replaced by|will be present after commit\" \"$2\" |\n+\t\tsed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" |\n+\t\tuniq  >\"$2\".actual\n \ttest_cmp \"$2\".expect \"$2\".actual\n }\n \n@@ -169,7 +173,7 @@ stats_ascii () {\n # Take none (=empty), one or two args\n # convert.c: eol=XX overrides text=auto\n attr_ascii () {\n-\tcase $1,$2 in\n+\tcase \"$1\",\"$2\" in\n \t-text,*)   echo \"-text\" ;;\n \ttext,)     echo \"text\" ;;\n \ttext,lf)   echo \"text eol=lf\" ;;\n@@ -349,10 +353,12 @@ then\n \tWILC=LF_CRLF\n \tWICL=\n \tWAMIX=LF_CRLF\n+\tPcrlf=\n else\n \tWILC=\n \tWICL=CRLF_LF\n \tWAMIX=CRLF_LF\n+\tPcrlf=CRLF\n fi\n \n #                         attr   LF        CRLF      CRLFmixLF LFmixCR   CRLFNUL\n@@ -392,31 +398,32 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+#                 attr    aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n+\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$Pcrlf\"  mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$Pcrlf\"  mixed       \"$WILC\"     \"$Pcrlf\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF      mixed       \"\"          CRLF\n+\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n-\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf      $crlf   \"\"        CRLF      mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf    $crlf   LF_CRLF   \"\"        mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO text  lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO text  crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n done\n \n-commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n-commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n-\n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n \tgit -c core.autocrlf=false reset --hard\n@@ -456,9 +463,9 @@ do\n \tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n@@ -479,12 +486,10 @@ done\n \n if test_have_prereq NATIVE_CRLF\n then\n-MIX_CRLF_LF=CRLF\n MIX_LF_CR=CRLF_mix_CR\n NL=CRLF\n LFNUL=CRLF_nul\n else\n-MIX_CRLF_LF=CRLF_mix_LF\n MIX_LF_CR=LF_mix_CR\n NL=LF\n LFNUL=LF_nul\n@@ -492,8 +497,7 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-#for id in \"\" ident\n-for id in \"\"\n+for id in \"\" ident\n do\n \tfor ceol in lf crlf native\n \tdo\n@@ -501,38 +505,38 @@ do\n \t\tdo\n \t\t\t# -text overrides core.autocrlf and core.eol\n \t\t\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n-\t\t\tcheckout_files -text \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files -text \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files -text \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\t# text\n-\t\t\tcheckout_files text  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files text    \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files text    \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t\t# currently the same as text, eol=XXX\n-\t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto    \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto    \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \n \t\t# core.autocrlf false, different core.eol\n-\t\tcheckout_files   \"\"    \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   \"\"      \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# core.autocrlf true\n-\t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   \"\"      \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tcheckout_files   auto    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   text    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n-\t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files   auto  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   text    \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto    \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text=auto + eol=XXX\n \tdone\n \t# text: core.autocrlf=false uses core.eol\n-\tcheckout_files     text  \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files     text  \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     text    \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n+\tcheckout_files     text    \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files     text    \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  \"$MIX_LF_CR\" \"$LFNUL\"\n+\tcheckout_files     text    \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  \"$MIX_LF_CR\" \"$LFNUL\"\n \t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto    \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto    \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284337","messageId":"1461510690-21200-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6b 09/10] t6038; use crlf on all platforms","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-24T15:11:30Z","receivedAt":"2016-04-24T15:11:30Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nt6038 uses different code, dependig if NATIVE_CRLF is set ot not.\nWhen the native line endings are LF, merge.renormalize is not tested very well.\nChange the test to always use CRLF by setting core.eol=crlf.\nAfter doing so, the test fails:\n\nrm '.gitattributes'\nrm 'control_file'\nrm 'file'\nrm 'inert_file'\nHEAD is now at 0d9ffb6 add line from b\nerror: addinfo_cache failed for path 'file'\nfile: unmerged (cbd69ec7cd12dd0989e853923867d94c8519aa52)\nfile: unmerged (ad55e240aeb42e0d9a0e18d6d8b02dd82ee3e527)\nfile: unmerged (99b633103c15c20cebebf821133ab526b0ff90b2)\nfatal: git write-tree failed to write a tree\nMerging:\n0d9ffb6 add line from b\nvirtual a\nfound 1 common ancestor:\n1c56df1 Initial\nAuto-merging file\nnot ok 4 - Merge addition of text=auto\n\nThis will be addressed in the next commit.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n t/t6038-merge-text-auto.sh | 37 +++++++++++--------------------------\n 1 file changed, 11 insertions(+), 26 deletions(-)\n\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 33b77ee..0108ead 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -25,6 +25,7 @@ compare_files () {\n \n test_expect_success setup '\n \tgit config core.autocrlf false &&\n+\tgit config core.eol crlf &&\n \n \techo first line | append_cr >file &&\n \techo first line >control_file &&\n@@ -79,10 +80,8 @@ test_expect_success 'Merge after setting text=auto' '\n \tsame line\n \tEOF\n \n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\tappend_cr <expected >expected.temp &&\n-\t\tmv expected.temp expected\n-\tfi &&\n+\tappend_cr <expected >expected.temp &&\n+\tmv expected.temp expected &&\n \tgit config merge.renormalize true &&\n \tgit rm -fr . &&\n \trm -f .gitattributes &&\n@@ -97,10 +96,8 @@ test_expect_success 'Merge addition of text=auto' '\n \tsame line\n \tEOF\n \n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\tappend_cr <expected >expected.temp &&\n-\t\tmv expected.temp expected\n-\tfi &&\n+\tappend_cr <expected >expected.temp &&\n+\tmv expected.temp expected &&\n \tgit config merge.renormalize true &&\n \tgit rm -fr . &&\n \trm -f .gitattributes &&\n@@ -111,15 +108,9 @@ test_expect_success 'Merge addition of text=auto' '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \techo \"<<<<<<<\" >expected &&\n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\techo first line | append_cr >>expected &&\n-\t\techo same line | append_cr >>expected &&\n-\t\techo ======= | append_cr >>expected\n-\telse\n-\t\techo first line >>expected &&\n-\t\techo same line >>expected &&\n-\t\techo ======= >>expected\n-\tfi &&\n+\techo first line | append_cr >>expected &&\n+\techo same line | append_cr >>expected &&\n+\techo ======= | append_cr >>expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n@@ -135,15 +126,9 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \techo \"<<<<<<<\" >expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\techo ======= | append_cr >>expected &&\n-\t\techo first line | append_cr >>expected &&\n-\t\techo same line | append_cr >>expected\n-\telse\n-\t\techo ======= >>expected &&\n-\t\techo first line >>expected &&\n-\t\techo same line >>expected\n-\tfi &&\n+\techo ======= | append_cr >>expected &&\n+\techo first line | append_cr >>expected &&\n+\techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n \tgit config merge.renormalize false &&\n \trm -f .gitattributes &&\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284336","messageId":"1461510692-21239-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v6b 10/10] ce_compare_data() did not respect conversion","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-24T15:11:32Z","receivedAt":"2016-04-24T15:11:32Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWe define the working tree file is clean if either:\n\n  * the result of running convert_to_git() on the working tree\n    contents matches what is in the index (because that would mean\n    doing another \"git add\" on the path is a no-op); OR\n\n  * the result of running convert_to_working_tree() on the content\n    in the index matches what is in the working tree (because that\n    would mean doing another \"git checkout -f\" on the path is a\n    no-op).\n\nAdd an extra check in ce_compare_data() in read_cache.c.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n read-cache.c               | 61 ++++++++++++++++++++++++++++++++++++++++++++++\n t/t6038-merge-text-auto.sh | 14 +++++------\n 2 files changed, 68 insertions(+), 7 deletions(-)\n\ndiff --git a/read-cache.c b/read-cache.c\nindex a3ef967..48c4b31 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -156,17 +156,78 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)\n \t\tce_mark_uptodate(ce);\n }\n \n+/*\n+ * Compare the data in buf with the data in the file pointed by fd and\n+ * return 0 if they are identical, and non-zero if they differ.\n+ */\n+static int compare_with_fd(const char *input, ssize_t len, int fd)\n+{\n+\tfor (;;) {\n+\t\tchar buf[1024 * 16];\n+\t\tssize_t chunk_len, read_len;\n+\n+\t\tchunk_len = sizeof(buf) < len ? sizeof(buf) : len;\n+\t\tread_len = xread(fd, buf, chunk_len ? chunk_len : 1);\n+\n+\t\tif (!read_len)\n+\t\t\t/* EOF on the working tree file */\n+\t\t\treturn !len ? 0 : -1;\n+\n+\t\tif (!len)\n+\t\t\t/* we expected there is nothing left */\n+\t\t\treturn -1;\n+\n+\t\tif (memcmp(buf, input, read_len))\n+\t\t\treturn -1;\n+\t\tinput += read_len;\n+\t\tlen -= read_len;\n+\t}\n+}\n+\n static int ce_compare_data(const struct cache_entry *ce, struct stat *st)\n {\n \tint match = -1;\n \tint fd = open(ce->name, O_RDONLY);\n \n+\t/*\n+\t * Would another \"git add\" on the path change what is in the\n+\t * index for the path?\n+\t */\n \tif (fd >= 0) {\n \t\tunsigned char sha1[20];\n \t\tif (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, 0))\n \t\t\tmatch = hashcmp(sha1, ce->sha1);\n \t\t/* index_fd() closed the file descriptor already */\n \t}\n+\tif (!match)\n+\t\treturn match;\n+\n+\t/*\n+\t * Would another \"git checkout -f\" out of the index change\n+\t * what is in the working tree file?\n+\t */\n+\tfd = open(ce->name, O_RDONLY);\n+\tif (fd >= 0) {\n+\t\tenum object_type type;\n+\t\tunsigned long size_long;\n+\t\tvoid *data = read_sha1_file(ce->sha1, &type, &size_long);\n+\n+\t\tif (type == OBJ_BLOB) {\n+\t\t\tstruct strbuf worktree = STRBUF_INIT;\n+\t\t\tif (convert_to_working_tree(ce->name, data,\n+\t\t\t\t\t\t    size_long,\n+\t\t\t\t\t\t    &worktree)) {\n+\t\t\t\tsize_t size;\n+\t\t\t\tfree(data);\n+\t\t\t\tdata = strbuf_detach(&worktree, &size);\n+\t\t\t\tsize_long = size;\n+\t\t\t}\n+\t\t\tif (!compare_with_fd(data, size_long, fd))\n+\t\t\t\tmatch = 0;\n+\t\t}\n+\t\tfree(data);\n+\t\tclose(fd);\n+\t}\n \treturn match;\n }\n \ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 0108ead..565daf3 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -108,9 +108,9 @@ test_expect_success 'Merge addition of text=auto' '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \techo \"<<<<<<<\" >expected &&\n-\techo first line | append_cr >>expected &&\n-\techo same line | append_cr >>expected &&\n-\techo ======= | append_cr >>expected &&\n+\techo first line >>expected &&\n+\techo same line >>expected &&\n+\techo ======= >>expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n@@ -121,14 +121,13 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \tfuzz_conflict file >file.fuzzy &&\n \tcompare_files expected file.fuzzy\n '\n-\n test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \techo \"<<<<<<<\" >expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n-\techo ======= | append_cr >>expected &&\n-\techo first line | append_cr >>expected &&\n-\techo same line | append_cr >>expected &&\n+\techo =======  >>expected &&\n+\techo first line >>expected &&\n+\techo same line  >>expected &&\n \techo \">>>>>>>\" >>expected &&\n \tgit config merge.renormalize false &&\n \trm -f .gitattributes &&\n@@ -138,6 +137,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \tcompare_files expected file.fuzzy\n '\n \n+\n test_expect_failure 'checkout -m after setting text=auto' '\n \tcat <<-\\EOF >expected &&\n \tfirst line\n-- \n2.8.0.rc2.2.g1a4d45a.dirty\n"},{"id":"284444","messageId":"1461603387-30639-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v7 01/10] t0027: Make commit_chk_wrnNNO() reliable","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-25T16:56:27Z","receivedAt":"2016-04-25T16:56:27Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen the content of a commited file is unchanged and the attributes are changed,\nGit may not detect that the next commit must treat the file as changed.\nThis happens when lstat() doesn't detect a change, since neither inode,\nmtime nor size are changed.\n\nAdd a singe \"Z\" character to change the file size (and content).\nWhen the files are compared later in checkout_files(), the \"Z\" is removed\nbefore the comparison.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Change since v6b:\n - Remove 2 sparse warnings, thanks Ramsay\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex f33962b..9fe539b 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -12,7 +12,7 @@ fi\n \n compare_files () {\n \ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n-\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n+\ttr '\\015\\000' QN <\"$2\" | tr -d 'Z' >\"$2\".actual &&\n \ttest_cmp \"$1\".expect \"$2\".actual &&\n \trm \"$1\".expect \"$2\".actual\n }\n@@ -114,6 +114,7 @@ commit_chk_wrnNNO () {\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n \t\tcp $f $fname &&\n+\t\tprintf Z >>\"$fname\" &&\n \t\tgit -c core.autocrlf=$crlf add $fname 2>/dev/null &&\n \t\tgit -c core.autocrlf=$crlf commit -m \"commit_$fname\" $fname >\"${pfx}_$f.err\" 2>&1\n \tdone\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"284438","messageId":"1461603389-30678-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v7 02/10] convert: allow core.autocrlf=input and core.eol=crlf","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-25T16:56:29Z","receivedAt":"2016-04-25T16:56:29Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nEven though the configuration parser errors out when core.autocrlf\nis set to 'input' when core.eol is set to 'crlf', there is no need\nto do so, because the core.autocrlf setting trumps core.eol.\n\nAllow all combinations of core.crlf and core.eol and document\nthat core.autocrlf overrides core.eol.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt | 6 +++---\n config.c                 | 4 ----\n 2 files changed, 3 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2cd6bdd..4a27ad4 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -337,9 +337,9 @@ core.quotePath::\n \n core.eol::\n \tSets the line ending type to use in the working directory for\n-\tfiles that have the `text` property set.  Alternatives are\n-\t'lf', 'crlf' and 'native', which uses the platform's native\n-\tline ending.  The default value is `native`.  See\n+\tfiles that have the `text` property set when core.autocrlf is false.\n+\tAlternatives are 'lf', 'crlf' and 'native', which uses the platform's\n+\tnative line ending.  The default value is `native`.  See\n \tlinkgit:gitattributes[5] for more information on end-of-line\n \tconversion.\n \ndiff --git a/config.c b/config.c\nindex 9ba40bc..a6adc8b 100644\n--- a/config.c\n+++ b/config.c\n@@ -803,8 +803,6 @@ static int git_default_core_config(const char *var, const char *value)\n \n \tif (!strcmp(var, \"core.autocrlf\")) {\n \t\tif (value && !strcasecmp(value, \"input\")) {\n-\t\t\tif (core_eol == EOL_CRLF)\n-\t\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\t\tauto_crlf = AUTO_CRLF_INPUT;\n \t\t\treturn 0;\n \t\t}\n@@ -830,8 +828,6 @@ static int git_default_core_config(const char *var, const char *value)\n \t\t\tcore_eol = EOL_NATIVE;\n \t\telse\n \t\t\tcore_eol = EOL_UNSET;\n-\t\tif (core_eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)\n-\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\treturn 0;\n \t}\n \n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"284436","messageId":"1461603391-30717-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v7 03/10] t0027: test cases for combined attributes","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-25T16:56:31Z","receivedAt":"2016-04-25T16:56:31Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nAdd more test cases for the not normalized files (\"NNO\"). The\n\"text\" attribute is most important, use it as the first parameter.\n\"ident\", if set, is the second paramater followed by the eol\nattribute.  The eol attribute overrides core.autocrlf, which\noverrides core.eol.\nindent is not yet used, this will be done in the next commit.\n\nUse loops to test more combinations of attributes, like\n\"* text eol=crlf\" or especially \"*text=auto eol=crlf\".\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n t/t0027-auto-crlf.sh | 298 ++++++++++++++++++++++-----------------------------\n 1 file changed, 129 insertions(+), 169 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 9fe539b..fd5e326 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -52,14 +52,17 @@ create_gitattributes () {\n create_NNO_files () {\n \tfor crlf in false true input\n \tdo\n-\t\tfor attr in \"\" auto text -text lf crlf\n+\t\tfor attr in \"\" auto text -text\n \t\tdo\n-\t\t\tpfx=NNO_${crlf}_attr_${attr} &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tfor aeol in \"\" lf crlf\n+\t\t\tdo\n+\t\t\t\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tdone\n \t\tdone\n \tdone\n }\n@@ -100,16 +103,17 @@ commit_check_warn () {\n }\n \n commit_chk_wrnNNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfwarn=$3\n-\tcrlfwarn=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfwarn=$1 ; shift\n+\tcrlfwarn=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n \t#Commit files on top of existing file\n-\tcreate_gitattributes \"$attr\" &&\n+\tcreate_gitattributes \"$attr\" $aeol &&\n \tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n@@ -122,19 +126,19 @@ commit_chk_wrnNNO () {\n \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n \t'\n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF\" '\n \t\tcheck_warning \"$crlfwarn\" ${pfx}_CRLF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_mix_LF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_mix_LF\" '\n \t\tcheck_warning \"$lfmixcrlf\" ${pfx}_CRLF_mix_LF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF_mix_cr\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf LF_mix_cr\" '\n \t\tcheck_warning \"$lfmixcr\" ${pfx}_LF_mix_CR.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_nul\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_nul\" '\n \t\tcheck_warning \"$crlfnul\" ${pfx}_CRLF_nul.err\n \t'\n }\n@@ -163,6 +167,7 @@ stats_ascii () {\n \n # contruct the attr/ returned by git ls-files --eol\n # Take none (=empty), one or two args\n+# convert.c: eol=XX overrides text=auto\n attr_ascii () {\n \tcase $1,$2 in\n \t-text,*)   echo \"-text\" ;;\n@@ -170,8 +175,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text=auto eol=lf\" ;;\n-\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n+\tauto,lf)   echo \"text eol=lf\" ;;\n+\tauto,crlf) echo \"text eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -196,28 +201,29 @@ check_files_in_repo () {\n }\n \n check_in_repo_NNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfname=$3\n-\tcrlfname=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}_\n-\ttest_expect_success \"compare_files $lfname ${pfx}LF.txt\" '\n-\t\tcompare_files $lfname ${pfx}LF.txt\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfname=$1 ; shift\n+\tcrlfname=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\ttest_expect_success \"compare_files $lfname ${pfx}_LF.txt\" '\n+\t\tcompare_files $lfname ${pfx}_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfname ${pfx}CRLF.txt\" '\n-\t\tcompare_files $crlfname ${pfx}CRLF.txt\n+\ttest_expect_success \"compare_files $crlfname ${pfx}_CRLF.txt\" '\n+\t\tcompare_files $crlfname ${pfx}_CRLF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\" '\n-\t\tcompare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\n+\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\" '\n+\t\tcompare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcr ${pfx}LF_mix_CR.txt\" '\n-\t\tcompare_files $lfmixcr ${pfx}LF_mix_CR.txt\n+\ttest_expect_success \"compare_files $lfmixcr ${pfx}_LF_mix_CR.txt\" '\n+\t\tcompare_files $lfmixcr ${pfx}_LF_mix_CR.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfnul ${pfx}CRLF_nul.txt\" '\n-\t\tcompare_files $crlfnul ${pfx}CRLF_nul.txt\n+\ttest_expect_success \"compare_files $crlfnul ${pfx}_CRLF_nul.txt\" '\n+\t\tcompare_files $crlfnul ${pfx}_CRLF_nul.txt\n \t'\n }\n \n@@ -232,7 +238,7 @@ checkout_files () {\n \tlfmixcrlf=$1 ; shift\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n-\tcreate_gitattributes \"$attr\" \"$ident\" &&\n+\tcreate_gitattributes \"$attr\" $ident $aeol &&\n \tgit config core.autocrlf $crlf &&\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n@@ -245,7 +251,7 @@ checkout_files () {\n \t\tfi\n \tdone\n \n-\ttest_expect_success \"ls-files --eol attr=$attr $ident $aeol core.autocrlf=$crlf core.eol=$ceol\" '\n+\ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n \t\ttest_when_finished \"rm expect actual\" &&\n \t\tsort <<-EOF >expect &&\n \t\ti/crlf w/$(stats_ascii $crlfname) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF.txt\n@@ -260,19 +266,19 @@ checkout_files () {\n \t\tsort >actual &&\n \t\ttest_cmp expect actual\n \t'\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n \t\tcompare_ws_file $pfx $lfname    crlf_false_attr__LF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n \t\tcompare_ws_file $pfx $crlfname  crlf_false_attr__CRLF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n \t\tcompare_ws_file $pfx $lfmixcrlf crlf_false_attr__CRLF_mix_LF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n \t\tcompare_ws_file $pfx $lfmixcr   crlf_false_attr__LF_mix_CR.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n \t\tcompare_ws_file $pfx $crlfnul   crlf_false_attr__LF_nul.txt\n \t\"\n }\n@@ -386,31 +392,31 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                       attr   LF        CRLF      CRLFmixLF \t LF_mix_CR   CRLFNUL\n-commit_chk_wrnNNO false \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"\"     \"LF_CRLF\" \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-\n+#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO false \"auto\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"auto\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"auto\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n \n-commit_chk_wrnNNO false \"text\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"$WILC\"   \t \"$WICL\"\n-commit_chk_wrnNNO true  \"text\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"text\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"CRLF_LF\"\n-\n-commit_chk_wrnNNO false \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-\n-commit_chk_wrnNNO false \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO true  \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO input \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n+for crlf in true false input\n+do\n+\tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+done\n \n-commit_chk_wrnNNO false \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO true  \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n \n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n@@ -441,24 +447,20 @@ test_expect_success 'commit -text' '\n \tcheck_files_in_repo input \"-text\" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n '\n \n-#                       attr    LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLFNUL\n-check_in_repo_NNO false \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO true  \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO input \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-\n-check_in_repo_NNO false \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-\n+for crlf in true false input\n+do\n+\t#                 attr  aeol           LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLFNUL\n+\tcheck_in_repo_NNO \"\"    \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n # How to read the table below:\n@@ -490,89 +492,47 @@ LFNUL=LF_nul\n fi\n export CRLF_MIX_LF_CR MIX NL\n \n-checkout_files \"\"      \"\" \t \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   native   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   native   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\n-for id in \"\" ident;\n+# Same handling with and without ident\n+for id in \"\"\n do\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tfor ceol in lf crlf native\n+\tdo\n+\t\tfor crlf in true false input\n+\t\tdo\n+\t\t\t# -text overrides core.autocrlf and core.eol\n+\t\t\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n+\t\t\tcheckout_files -text \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files -text \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files -text \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\t# text\n+\t\t\tcheckout_files text  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\t# currently the same as text, eol=XXX\n+\t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tdone\n+\n+\t\t# core.autocrlf false, different core.eol\n+\t\tcheckout_files   \"\"    \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# core.autocrlf true\n+\t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# text: core.autocrlf = true overrides core.eol\n+\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t# text: core.autocrlf = input overrides core.eol\n+\t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# text=auto + eol=XXX\n+\tdone\n+\t# text: core.autocrlf=false uses core.eol\n+\tcheckout_files     text  \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\tcheckout_files     text  \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"284437","messageId":"1461603392-30756-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v7 04/10] convert.c: ident + core.autocrlf didn't work","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-25T16:56:32Z","receivedAt":"2016-04-25T16:56:32Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen the ident attributes is set, get_stream_filter() did not obey\ncore.autocrlf=true, and the file was checked out with LF.\n\nChange the rule when a streaming filter can be used:\n- if an external filter is specified, don't use a stream filter.\n- if the worktree eol is CRLF and \"auto\" is active, don't use a stream filter.\n- Otherwise the stream filter can be used.\n\nAdd test cases in t0027.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c            | 19 +++++++------------\n t/t0027-auto-crlf.sh |  2 +-\n 2 files changed, 8 insertions(+), 13 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex f524b8d..b1614bf 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1380,27 +1380,22 @@ static struct stream_filter *ident_filter(const unsigned char *sha1)\n struct stream_filter *get_stream_filter(const char *path, const unsigned char *sha1)\n {\n \tstruct conv_attrs ca;\n-\tenum crlf_action crlf_action;\n \tstruct stream_filter *filter = NULL;\n \n \tconvert_attrs(&ca, path);\n-\n \tif (ca.drv && (ca.drv->smudge || ca.drv->clean))\n-\t\treturn filter;\n+\t\treturn NULL;\n+\n+\tif (ca.crlf_action == CRLF_AUTO || ca.crlf_action == CRLF_AUTO_CRLF)\n+\t\treturn NULL;\n \n \tif (ca.ident)\n \t\tfilter = ident_filter(sha1);\n \n-\tcrlf_action = ca.crlf_action;\n-\n-\tif ((crlf_action == CRLF_BINARY) ||\n-\t\t\tcrlf_action == CRLF_AUTO_INPUT ||\n-\t\t\t(crlf_action == CRLF_TEXT_INPUT))\n-\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n-\n-\telse if (output_eol(crlf_action) == EOL_CRLF &&\n-\t\t !(crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_CRLF))\n+\tif (output_eol(ca.crlf_action) == EOL_CRLF)\n \t\tfilter = cascade_filter(filter, lf_to_crlf_filter());\n+\telse\n+\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n \n \treturn filter;\n }\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex fd5e326..9372589 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -493,7 +493,7 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-for id in \"\"\n+for id in \"\" ident\n do\n \tfor ceol in lf crlf native\n \tdo\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"284439","messageId":"1461603394-30795-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v7 05/10] read-cache: factor out get_sha1_from_index() helper","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-25T16:56:34Z","receivedAt":"2016-04-25T16:56:34Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nFactor out the retrieval of the sha1 for a given path in\nread_blob_data_from_index() into the function get_sha1_from_index().\n\nThis will be used in the next commit, when convert.c can do the\nanalyze for \"text=auto\" without slurping the whole blob into memory\nat once.\n\nAdd a wrapper definition get_sha1_from_cache().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n cache.h      |  3 +++\n read-cache.c | 29 ++++++++++++++++++-----------\n 2 files changed, 21 insertions(+), 11 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex b829410..bd1210a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -379,6 +379,7 @@ extern void free_name_hash(struct index_state *istate);\n #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)\n #define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)\n #define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))\n+#define get_sha1_from_cache(path)  get_sha1_from_index (&the_index, (path))\n #endif\n \n enum object_type {\n@@ -1008,6 +1009,8 @@ static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *\n \treturn read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);\n }\n \n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path);\n+\n /*\n  * This internal function is only declared here for the benefit of\n  * lookup_replace_object().  Please do not call it directly.\ndiff --git a/read-cache.c b/read-cache.c\nindex d9fb78b..a3ef967 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -2263,13 +2263,27 @@ int index_name_is_other(const struct index_state *istate, const char *name,\n \n void *read_blob_data_from_index(struct index_state *istate, const char *path, unsigned long *size)\n {\n-\tint pos, len;\n+\tconst unsigned char *sha1;\n \tunsigned long sz;\n \tenum object_type type;\n \tvoid *data;\n \n-\tlen = strlen(path);\n-\tpos = index_name_pos(istate, path, len);\n+\tsha1 = get_sha1_from_index(istate, path);\n+\tif (!sha1)\n+\t\treturn NULL;\n+\tdata = read_sha1_file(sha1, &type, &sz);\n+\tif (!data || type != OBJ_BLOB) {\n+\t\tfree(data);\n+\t\treturn NULL;\n+\t}\n+\tif (size)\n+\t\t*size = sz;\n+\treturn data;\n+}\n+\n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path)\n+{\n+\tint pos = index_name_pos(istate, path, strlen(path));\n \tif (pos < 0) {\n \t\t/*\n \t\t * We might be in the middle of a merge, in which\n@@ -2285,14 +2299,7 @@ void *read_blob_data_from_index(struct index_state *istate, const char *path, un\n \t}\n \tif (pos < 0)\n \t\treturn NULL;\n-\tdata = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);\n-\tif (!data || type != OBJ_BLOB) {\n-\t\tfree(data);\n-\t\treturn NULL;\n-\t}\n-\tif (size)\n-\t\t*size = sz;\n-\treturn data;\n+\treturn (istate->cache[pos]->sha1);\n }\n \n void stat_validity_clear(struct stat_validity *sv)\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"284443","messageId":"1461603395-30834-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v7 06/10] convert.c: stream and early out","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-25T16:56:35Z","receivedAt":"2016-04-25T16:56:35Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen statistics are done for the autocrlf handling, the search in\nthe content can be stopped, if e.g\n- a search for binary is done, and a NUL character is found\n- a search for CRLF is done, and the first CRLF is found.\n\nSimilar when statistics for binary vs non-binary are gathered:\nWhenever a lone CR or NUL is found, the search can be aborted.\n\nWhen checking out files in \"auto\" mode, any file that has a \"lone CR\"\nor a CRLF will not be converted, so the search can be aborted early.\n\nAdd the new bit, CONVERT_STAT_BITS_ANY_CR,\nwhich is set for either lone CR or CRLF.\n\nMany binary files have a NUL very early (within the first few bytes,\nlatest within the first 1..2K).\nIt is often not necessary to load the whole content of a file or blob\ninto memory.\n\nUse a streaming handling for blobs and files in the worktree.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c | 159 ++++++++++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 103 insertions(+), 56 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex b1614bf..24ab095 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -3,6 +3,7 @@\n #include \"run-command.h\"\n #include \"quote.h\"\n #include \"sigchain.h\"\n+#include \"streaming.h\"\n \n /*\n  * convert.c - convert a file when checking it out and checking it in.\n@@ -13,10 +14,10 @@\n  * translation when the \"text\" attribute or \"auto_crlf\" option is set.\n  */\n \n-/* Stat bits: When BIN is set, the txt bits are unset */\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n+#define CONVERT_STAT_BITS_ANY_CR    0x8\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -31,30 +32,36 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned nul, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonecr, lonelf, crlf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n };\n \n-static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)\n+static void do_gather_stats(const char *buf, unsigned long size,\n+\t\t\t    struct text_stat *stats, unsigned earlyout)\n {\n \tunsigned long i;\n \n-\tmemset(stats, 0, sizeof(*stats));\n-\n+\tif (!buf || !size)\n+\t\treturn;\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n \t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n-\t\t\t} else\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\t} else {\n \t\t\t\tstats->lonecr++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+\t\t\t}\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == '\\n') {\n \t\t\tstats->lonelf++;\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_LF;\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == 127)\n@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t\t\tstats->printable++;\n \t\t\t\tbreak;\n \t\t\tcase 0:\n-\t\t\t\tstats->nul++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t\t/* fall through */\n \t\t\tdefault:\n \t\t\t\tstats->nonprintable++;\n@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t}\n \t\telse\n \t\t\tstats->printable++;\n+\t\tif (stats->stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n \t}\n \n \t/* If file ends with EOF then don't count this EOF as non-printable. */\n@@ -86,41 +95,62 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n  * The same heuristics as diff.c::mmfile_is_binary()\n  * We treat files with bare CR as binary\n  */\n-static int convert_is_binary(unsigned long size, const struct text_stat *stats)\n+static void convert_nonprintable(struct text_stat *stats)\n {\n-\tif (stats->lonecr)\n-\t\treturn 1;\n-\tif (stats->nul)\n-\t\treturn 1;\n \tif ((stats->printable >> 7) < stats->nonprintable)\n-\t\treturn 1;\n-\treturn 0;\n+\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+}\n+\n+static void gather_stats(const char *buf, unsigned long size,\n+\t\t\t struct text_stat *stats, unsigned earlyout)\n+{\n+\tmemset(stats, 0, sizeof(*stats));\n+\tdo_gather_stats(buf, size, stats, earlyout);\n+\tconvert_nonprintable(stats);\n }\n \n-static unsigned int gather_convert_stats(const char *data, unsigned long size)\n+\n+static unsigned get_convert_stats_sha1(unsigned const char *sha1,\n+\t\t\t\t       unsigned earlyout)\n {\n+\tstruct git_istream *st;\n \tstruct text_stat stats;\n-\tint ret = 0;\n-\tif (!data || !size)\n-\t\treturn 0;\n-\tgather_stats(data, size, &stats);\n-\tif (convert_is_binary(size, &stats))\n-\t\tret |= CONVERT_STAT_BITS_BIN;\n-\tif (stats.crlf)\n-\t\tret |= CONVERT_STAT_BITS_TXT_CRLF;\n-\tif (stats.lonelf)\n-\t\tret |=  CONVERT_STAT_BITS_TXT_LF;\n+\tenum object_type type;\n+\tunsigned long sz;\n \n-\treturn ret;\n+\tif (!sha1)\n+\t\treturn 0;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tst = open_istream(sha1, &type, &sz, NULL);\n+\tif (!st) {\n+\t\treturn 0;\n+\t}\n+\tif (type != OBJ_BLOB)\n+\t\tgoto close_and_exit_i;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read_istream(st, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+close_and_exit_i:\n+\tclose_istream(st);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n }\n \n-static const char *gather_convert_stats_ascii(const char *data, unsigned long size)\n+static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned int convert_stats = gather_convert_stats(data, size);\n-\n+\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n+\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats) {\n+\tswitch (convert_stats & mask) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -132,24 +162,45 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si\n \t}\n }\n \n+static unsigned get_convert_stats_wt(const char *path)\n+{\n+\tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tint fd;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tfd = open(path, O_RDONLY);\n+\tif (fd < 0)\n+\t\treturn 0;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read(fd, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+\tclose(fd);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n+}\n+\n const char *get_cached_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret;\n-\tunsigned long sz;\n-\tvoid *data = read_blob_data_from_cache(path, &sz);\n-\tret = gather_convert_stats_ascii(data, sz);\n-\tfree(data);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n const char *get_wt_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret = \"\";\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (strbuf_read_file(&sb, path, 0) >= 0)\n-\t\tret = gather_convert_stats_ascii(sb.buf, sb.len);\n-\tstrbuf_release(&sb);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_wt(path);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n static int text_eol_is_crlf(void)\n@@ -219,16 +270,10 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \n static int has_cr_in_index(const char *path)\n {\n-\tunsigned long sz;\n-\tvoid *data;\n-\tint has_cr;\n-\n-\tdata = read_blob_data_from_cache(path, &sz);\n-\tif (!data)\n-\t\treturn 0;\n-\thas_cr = memchr(data, '\\r', sz) != NULL;\n-\tfree(data);\n-\treturn has_cr;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n+\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -249,10 +294,10 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \n \t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n@@ -309,11 +354,13 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n+\n \n \tif (!len || output_eol(crlf_action) != EOL_CRLF)\n \t\treturn 0;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, earlyout);\n \n \t/* No \"naked\" LF? Nothing to convert, regardless. */\n \tif (!stats.lonelf)\n@@ -327,7 +374,7 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\t\t\treturn 0;\n \t\t}\n \n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \t}\n \n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"284445","messageId":"1461603397-30873-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v7 07/10] convert: unify the \"auto\" handling of CRLF","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-25T16:56:37Z","receivedAt":"2016-04-25T16:56:37Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nBefore this change,\n$ echo \"* text=auto\" >.gitattributes\n$ echo \"* eol=crlf\" >>.gitattributes\n\nwould have the same effect as\n$ echo \"* text\" >.gitattributes\n$ git config core.eol crlf\n\nSince the 'eol' attribute had higher priority than 'text=auto', this may\ncorrupt binary files and is not what users expect to happen.\n\nMake the 'eol' attribute to obey 'text=auto', and now\n$ echo \"* text=auto\" >.gitattributes\n$ echo \"* eol=crlf\" >>.gitattributes\nbehaves the same as\n$ echo \"* text=auto\" >.gitattributes\n$ git config core.eol crlf\n\nIn other words,\n$ echo \"* text=auto eol=crlf\" >.gitattributes\nhas the same effect as\n$ git config core.autocrlf true\n\nand\n$ echo \"* text=auto eol=lf\" >.gitattributes\nhas the same effect as\n$ git config core.autocrlf input\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt        | 14 +++++++-------\n Documentation/gitattributes.txt | 15 +++++++++------\n convert.c                       | 42 +++++++++++++++++++++--------------------\n convert.h                       |  3 ++-\n t/t0025-crlf-auto.sh            |  4 ++--\n t/t0027-auto-crlf.sh            | 32 +++++++++++++++----------------\n t/t6038-merge-text-auto.sh      | 23 ++++++++++++++--------\n 7 files changed, 73 insertions(+), 60 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 4a27ad4..9caf6ae 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf`\n mechanism.\n \n core.autocrlf::\n-\tSetting this variable to \"true\" is almost the same as setting\n-\tthe `text` attribute to \"auto\" on all files except that text\n-\tfiles are not guaranteed to be normalized: files that contain\n-\t`CRLF` in the repository will not be touched.  Use this\n-\tsetting if you want to have `CRLF` line endings in your\n-\tworking directory even though the repository does not have\n-\tnormalized line endings.  This variable can be set to 'input',\n+\tSetting this variable to \"true\" is the same as setting\n+\tthe `text` attribute to \"auto\" on all files and core.eol to \"crlf\".\n+\tSet to true if you want to have `CRLF` line endings in your\n+\tworking directory and the repository has LF line endings.\n+\tText files are guaranteed not to be normalized: files that contain\n+\t`CRLF` in the repository will not be touched.\n+\tThis variable can be set to 'input',\n \tin which case no output conversion is performed.\n \n core.symlinks::\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex e3b1de8..d7a124b 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n `core.eol` configuration variable for all text files.\n+Note that `core.autocrlf` overrides `core.eol`\n \n Set::\n \n@@ -130,8 +131,9 @@ Unset::\n Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n-\tend-of-line normalization.  If Git decides that the content is\n-\ttext, its line endings are normalized to LF on checkin.\n+\tend-of-line conversion.  If Git decides that the content is\n+\ttext, its line endings are converted to LF on checkin.\n+\tWhen the file has been commited with CRLF, no conversion is done.\n \n Unspecified::\n \n@@ -146,7 +148,7 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It enables end-of-line normalization without any\n+working directory.  It enables end-of-line conversion without any\n content checks, effectively setting the `text` attribute.\n \n Set to string value \"crlf\"::\n@@ -186,9 +188,10 @@ the working directory, and prevent .jpg files from being normalized\n regardless of their content.\n \n ------------------------\n+*               text=auto\n *.txt\t\ttext\n-*.vcproj\teol=crlf\n-*.sh\t\teol=lf\n+*.vcproj\ttext eol=crlf\n+*.sh\t\ttext eol=lf\n *.jpg\t\t-text\n ------------------------\n \n@@ -198,7 +201,7 @@ normalization in Git.\n \n If you simply want to have CRLF line endings in your working directory\n regardless of the repository you are working with, you can set the\n-config variable \"core.autocrlf\" without changing any attributes.\n+config variable \"core.autocrlf\" without using any attributes.\n \n ------------------------\n [core]\ndiff --git a/convert.c b/convert.c\nindex 24ab095..3782172 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -227,7 +227,9 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \t\treturn EOL_LF;\n \tcase CRLF_UNDEFINED:\n \tcase CRLF_AUTO_CRLF:\n+\t\treturn EOL_CRLF;\n \tcase CRLF_AUTO_INPUT:\n+\t\treturn EOL_LF;\n \tcase CRLF_TEXT:\n \tcase CRLF_AUTO:\n \t\t/* fall through */\n@@ -299,17 +301,15 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/*\n-\t\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t\t * This is the new safer autocrlf handling.\n-\t\t\t */\n-\t\t\tif (has_cr_in_index(path))\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/*\n+\t\t * If the file in the index has any CR in it, do not convert.\n+\t\t * This is the new safer autocrlf handling.\n+\t\t */\n+\t\tif (checksafe == SAFE_CRLF_RENORMALIZE)\n+\t\t\tchecksafe = SAFE_CRLF_FALSE;\n+\t\telse if (has_cr_in_index(path))\n+\t\t\treturn 0;\n \t}\n-\n \tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n \n \t/* Optimization: No CRLF? Nothing to convert, regardless. */\n@@ -367,12 +367,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\treturn 0;\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t\t/* This is the new safer autocrlf-handling */\n-\t\t\tif (stats.lonecr || stats.crlf )\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n+\t\t/* This is the new safer autocrlf-handling */\n+\t\tif (stats.lonecr || stats.crlf )\n+\t\t\treturn 0;\n \n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n@@ -833,7 +831,11 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tca->drv = git_path_check_convert(ccheck + 2);\n \t\tif (ca->crlf_action != CRLF_BINARY) {\n \t\t\tenum eol eol_attr = git_path_check_eol(ccheck + 3);\n-\t\t\tif (eol_attr == EOL_LF)\n+\t\t\tif (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_INPUT;\n+\t\t\telse if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_CRLF;\n+\t\t\telse if (eol_attr == EOL_LF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_INPUT;\n \t\t\telse if (eol_attr == EOL_CRLF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_CRLF;\n@@ -892,9 +894,9 @@ const char *get_convert_attr_ascii(const char *path)\n \tcase CRLF_AUTO:\n \t\treturn \"text=auto\";\n \tcase CRLF_AUTO_CRLF:\n-\t\treturn \"text=auto eol=crlf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=crlf\";\n \tcase CRLF_AUTO_INPUT:\n-\t\treturn \"text=auto eol=lf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=lf\";\n \t}\n \treturn \"\";\n }\n@@ -996,7 +998,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_FALSE);\n+\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n }\n \n /*****************************************************************\ndiff --git a/convert.h b/convert.h\nindex ccf436b..81b6cdf 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -7,7 +7,8 @@\n enum safe_crlf {\n \tSAFE_CRLF_FALSE = 0,\n \tSAFE_CRLF_FAIL = 1,\n-\tSAFE_CRLF_WARN = 2\n+\tSAFE_CRLF_WARN = 2,\n+\tSAFE_CRLF_RENORMALIZE = 4\n };\n \n extern enum safe_crlf safe_crlf;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex c164b46..d0bee08 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -114,7 +114,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n+test_expect_success 'text=auto, autocrlf=true does not normalize CRLF files' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \tgit config core.autocrlf true &&\n@@ -126,7 +126,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n \tLFonlydiff=$(git diff LFonly) &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n \tLFwithNULdiff=$(git diff LFwithNUL) &&\n-\ttest -z \"$LFonlydiff\" -a -n \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n+\ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 9372589..8367d0b 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -175,8 +175,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text eol=lf\" ;;\n-\tauto,crlf) echo \"text eol=crlf\" ;;\n+\tauto,lf)   echo \"text=auto eol=lf\" ;;\n+\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -397,10 +397,9 @@ commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n-\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n@@ -408,8 +407,8 @@ do\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n \tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n \tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n done\n@@ -454,9 +453,9 @@ do\n \tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n@@ -493,7 +492,8 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-for id in \"\" ident\n+#for id in \"\" ident\n+for id in \"\"\n do\n \tfor ceol in lf crlf native\n \tdo\n@@ -509,7 +509,7 @@ do\n \t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n \t\t\t# currently the same as text, eol=XXX\n \t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \n \t\t# core.autocrlf false, different core.eol\n@@ -517,7 +517,7 @@ do\n \t\t# core.autocrlf true\n \t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n \t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n@@ -531,8 +531,8 @@ do\n \tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 85c10b0..33b77ee 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -16,6 +16,13 @@ test_description='CRLF merge conflict across text=auto change\n \n test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b\n \n+compare_files () {\n+\ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n+\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n+\ttest_cmp \"$1\".expect \"$2\".actual &&\n+\trm \"$1\".expect \"$2\".actual\n+}\n+\n test_expect_success setup '\n \tgit config core.autocrlf false &&\n \n@@ -30,7 +37,7 @@ test_expect_success setup '\n \tgit branch side &&\n \n \techo \"* text=auto\" >.gitattributes &&\n-\ttouch file &&\n+\techo first line >file &&\n \tgit add .gitattributes file &&\n \ttest_tick &&\n \tgit commit -m \"normalize file\" &&\n@@ -81,7 +88,7 @@ test_expect_success 'Merge after setting text=auto' '\n \trm -f .gitattributes &&\n \tgit reset --hard a &&\n \tgit merge b &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_success 'Merge addition of text=auto' '\n@@ -99,7 +106,7 @@ test_expect_success 'Merge addition of text=auto' '\n \trm -f .gitattributes &&\n \tgit reset --hard b &&\n \tgit merge a &&\n-\ttest_cmp expected file\n+\tcompare_files  expected file\n '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n@@ -121,7 +128,7 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \tgit reset --hard a &&\n \ttest_must_fail git merge b &&\n \tfuzz_conflict file >file.fuzzy &&\n-\ttest_cmp expected file.fuzzy\n+\tcompare_files expected file.fuzzy\n '\n \n test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n@@ -143,7 +150,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \tgit reset --hard b &&\n \ttest_must_fail git merge a &&\n \tfuzz_conflict file >file.fuzzy &&\n-\ttest_cmp expected file.fuzzy\n+\tcompare_files expected file.fuzzy\n '\n \n test_expect_failure 'checkout -m after setting text=auto' '\n@@ -158,7 +165,7 @@ test_expect_failure 'checkout -m after setting text=auto' '\n \tgit reset --hard initial &&\n \tgit checkout a -- . &&\n \tgit checkout -m b &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_failure 'checkout -m addition of text=auto' '\n@@ -173,7 +180,7 @@ test_expect_failure 'checkout -m addition of text=auto' '\n \tgit reset --hard initial &&\n \tgit checkout b -- . &&\n \tgit checkout -m a &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_failure 'cherry-pick patch from after text=auto was added' '\n@@ -187,7 +194,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' '\n \tgit reset --hard b &&\n \ttest_must_fail git cherry-pick a >err 2>&1 &&\n \tgrep \"[Nn]othing added\" err &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_success 'Test delete/normalize conflict' '\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"284442","messageId":"1461603398-30912-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v7 08/10] convert.c: more safer crlf handling with text attribute","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-25T16:56:38Z","receivedAt":"2016-04-25T16:56:38Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nThis patch extends the work done in commit c480539:\n\"Make it work also for un-normalized repositories\". Make sure that CRLF\ncan be converted round trip, or don't convert them at all.\n\nThe old handling would treat a file as unchanged after checkout,\nas long as it is not touched in the work tree and mtime matches the value\nrecorded in the index.\nWhen the mtime is changed in the working tree, or the inode is changed,\nthe file is reported as modified.\n\nThe following sequence is now handled reproducable:\n$ git init\n$ printf \"line1\\r\\n\" >file.bat\n$ git add file.bat\n$ git commit -m \"Add file with CRLF\" file.bat\n$ echo \"*.bat text eol=crlf\" >.gitattributes\n$ git commit -m \"bat files should have CRLF\"\n$ git status\n # nothing to commit, working directory clean\n$ git push <upstream>\n$ printf \"newline\\r\\n\" >>file.bat\n$ mv file.bat file.sav\n$ git checkout file.bat\n$ git status\n #modified:   file.bat\n\nThe new handling makes sure that after running \"git reset --hard\".\n\"git status\" reports the working tree as clean regarding CRLF conversion.\nIt makes sure that the Git-internal eol conversion is\ndoing roundtrip. A user can still write an external smudge/clean filter\noutside Git, which doesn't do a roundtrip and the working directory is\nnot clean.\n\nThe functionality of has_cr_in_index() is turned into has_crlf_in_index(),\nand the function is integrated into would_convert_crlf_at_commit().\n\nCheck for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR\nis no longer used and removed, as well as \"lonecr\" in struct text_stat.\n\nRewrite check_safe_crlf() in convert.c to simulate checkin-checkout,\nto detect whether any line endings are converted.\n\nAdd a warning, similar to the CRLF-LF replacement, when a file is commited,\nand after the next checkout the line endings are not what they should be.\n\nModify the lf_to_crlf_filter:\nFiles with LF are converted into CRLF, file with CRLF are not changed.\nFiles with mixed line endings are not converted, the filter fails, and Git\nfalls back to the non-streaming handling, see write_entry().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/gitattributes.txt |  19 ++--\n convert.c                       | 235 +++++++++++++++++++++++++---------------\n t/t0025-crlf-auto.sh            |   8 +-\n t/t0027-auto-crlf.sh            |  92 ++++++++--------\n 4 files changed, 213 insertions(+), 141 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex d7a124b..836461d 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'.\n `text`\n ^^^^^^\n \n-This attribute enables and controls end-of-line normalization.  When a\n+This attribute enables and controls end-of-line conversion.  When a\n text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol`\n Set::\n \n \tSetting the `text` attribute on a path enables end-of-line\n-\tnormalization and marks the path as a text file.  End-of-line\n+\tconversion and marks the path as a text file.  End-of-line\n \tconversion takes place without guessing the content type.\n+\tFiles that have been commited with CRLF before the text attribute\n+\tis set and commited are not normalized. No end-of-line conversion\n+\tis done at checkout or checkin.\n \n Unset::\n \n@@ -131,9 +134,9 @@ Unset::\n Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n-\tend-of-line conversion.  If Git decides that the content is\n-\ttext, its line endings are converted to LF on checkin.\n-\tWhen the file has been commited with CRLF, no conversion is done.\n+\tend-of-line normalization.  If Git decides that the content is\n+\ttext, and the path has no CRLF in the index,\n+\tits line endings are converted to LF on checkin.\n \n Unspecified::\n \n@@ -148,8 +151,10 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It enables end-of-line conversion without any\n-content checks, effectively setting the `text` attribute.\n+working directory.  It sets the `text` attribute, unless `text=auto`\n+is specified.\n+When the file had been commited with CRLF in the index, no conversion\n+is done at checkout or commit.\n \n Set to string value \"crlf\"::\n \ndiff --git a/convert.c b/convert.c\nindex 3782172..3d36c45 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -17,7 +17,8 @@\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n-#define CONVERT_STAT_BITS_ANY_CR    0x8\n+\n+#define CONVERT_STAT_BITS_MIXED (CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF)\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -32,7 +33,7 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned stat_bits, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonelf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n@@ -48,13 +49,10 @@ static void do_gather_stats(const char *buf, unsigned long size,\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n-\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n-\t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n \t\t\t} else {\n-\t\t\t\tstats->lonecr++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t}\n \t\t\tcontinue;\n@@ -135,7 +133,7 @@ static unsigned get_convert_stats_sha1(unsigned const char *sha1,\n \t\tif (!readlen)\n \t\t\tbreak;\n \t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n-\t\tif (stats.stat_bits & earlyout)\n+\t\tif ((stats.stat_bits & earlyout) == earlyout)\n \t\t\tbreak; /* We found what we have been searching for */\n \t}\n close_and_exit_i:\n@@ -146,11 +144,9 @@ close_and_exit_i:\n \n static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n-\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats & mask) {\n+\tswitch (convert_stats) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -162,7 +158,16 @@ static const char *convert_stats_ascii(unsigned convert_stats)\n \t}\n }\n \n-static unsigned get_convert_stats_wt(const char *path)\n+const char *get_cached_convert_stats_ascii(const char *path)\n+{\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n+}\n+\n+const char *get_wt_convert_stats_ascii(const char *path)\n {\n \tstruct text_stat stats;\n \tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n@@ -170,7 +175,7 @@ static unsigned get_convert_stats_wt(const char *path)\n \tmemset(&stats, 0, sizeof(stats));\n \tfd = open(path, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn 0;\n+\t\treturn NULL;\n \tfor (;;) {\n \t\tchar buf[1024];\n \t\tssize_t readlen = read(fd, buf, sizeof(buf));\n@@ -184,23 +189,7 @@ static unsigned get_convert_stats_wt(const char *path)\n \t}\n \tclose(fd);\n \tconvert_nonprintable(&stats);\n-\treturn stats.stat_bits;\n-}\n-\n-const char *get_cached_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n-\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n-\t\t\t\t\t       earlyout);\n-\treturn convert_stats_ascii(convert_stats);\n-}\n-\n-const char *get_wt_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_wt(path);\n-\treturn convert_stats_ascii(convert_stats);\n+\treturn convert_stats_ascii(stats.stat_bits);\n }\n \n static int text_eol_is_crlf(void)\n@@ -239,43 +228,95 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \treturn core_eol;\n }\n \n+static int would_convert_lf_at_checkout(unsigned convert_stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tif (output_eol(crlf_action) != EOL_CRLF)\n+\t\treturn 0;\n+\n+\t/* No \"naked\" LF? Nothing to convert, regardless. */\n+\tif (!(convert_stats & CONVERT_STAT_BITS_TXT_LF))\n+\t\treturn 0;\n+\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\t/* auto: binary files are not converted */\n+\t\tif (convert_stats & CONVERT_STAT_BITS_BIN)\n+\t\t\treturn 0;\n+\t}\n+\t/* If we have any CRLF line endings, we do not touch it */\n+\t/* This is the new safer autocrlf-handling */\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+\n+}\n+\n+static int would_convert_crlf_at_commit(const char * path,\n+\t\t\t\t\tconst struct text_stat *stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tunsigned stat_bits_index;\n+\t/* No CRLF? Nothing to convert, regardless. */\n+\tif (!(stats->stat_bits & CONVERT_STAT_BITS_TXT_CRLF))\n+\t\treturn 0;\n+\t/*\n+\t * If the file in the index has any CRLF in it, do not convert.\n+\t * This is the new safer autocrlf handling.\n+\t */\n+\tstat_bits_index = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t\t CONVERT_STAT_BITS_TXT_CRLF);\n+\tif (stat_bits_index & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+}\n+\n static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n-                            struct text_stat *stats, enum safe_crlf checksafe)\n+\t\t\t    enum safe_crlf checksafe,\n+\t\t\t    unsigned convert_stats, unsigned new_convert_stats)\n {\n+\tenum eol new_eol = output_eol(crlf_action);\n+\tconst char *err_warn_msg = NULL;\n \tif (!checksafe)\n \t\treturn;\n-\n-\tif (output_eol(crlf_action) == EOL_LF) {\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n \t\t/*\n \t\t * CRLFs would not be restored by checkout:\n \t\t * check if we'd remove CRLFs\n \t\t */\n-\t\tif (stats->crlf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n-\t\t}\n-\t} else if (output_eol(crlf_action) == EOL_CRLF) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n+\t}\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_LF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_LF)) {\n \t\t/*\n \t\t * CRLFs would be added by checkout:\n \t\t * check if we have \"naked\" LFs\n \t\t */\n-\t\tif (stats->lonelf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n-\t\t}\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n+\t}\n+\tif ((new_convert_stats & CONVERT_STAT_BITS_MIXED) == CONVERT_STAT_BITS_MIXED)\n+\t\terr_warn_msg = \"mixed eol\";\n+\telse if (new_eol == EOL_LF && new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\terr_warn_msg = \"CRLF\";\n+\n+\tif (err_warn_msg) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"%s will be present after commit and checkout in %s.\",\n+\t\t\t\terr_warn_msg, path);\n+\t\telse\n+\t\t\tdie(\"%s will be present after commit and checkout in %s\",\n+\t\t\t    err_warn_msg, path);\n \t}\n-}\n-\n-static int has_cr_in_index(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n-\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n-\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -284,7 +325,7 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n {\n \tstruct text_stat stats;\n \tchar *dst;\n-\n+\tint convert_crlf;\n \tif (crlf_action == CRLF_BINARY ||\n \t    (src && !len))\n \t\treturn 0;\n@@ -296,24 +337,42 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n-\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\t\t/*\n-\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t * This is the new safer autocrlf handling.\n-\t\t */\n-\t\tif (checksafe == SAFE_CRLF_RENORMALIZE)\n-\t\t\tchecksafe = SAFE_CRLF_FALSE;\n-\t\telse if (has_cr_in_index(path))\n-\t\t\treturn 0;\n+\t} else {\n+\t\tgather_stats(src, len, &stats, 0);\n+\t}\n+\tif (checksafe == SAFE_CRLF_RENORMALIZE) {\n+\t\tconvert_crlf = 1;\n+\t\tchecksafe = SAFE_CRLF_FALSE;\n+\t} else {\n+\t\tconvert_crlf = would_convert_crlf_at_commit(path, &stats, len,\n+\t\t\t\t\t\t\t    crlf_action);\n \t}\n-\tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n \n-\t/* Optimization: No CRLF? Nothing to convert, regardless. */\n-\tif (!stats.crlf)\n+\tif (checksafe) {\n+\t\tunsigned convert_stats = stats.stat_bits;\n+\t\tunsigned new_convert_stats = convert_stats;\n+\t\t/* Simulate commit */\n+\t\tif (convert_crlf &&\n+\t\t    (new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_LF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t}\n+\t\t/* Simulate checkout */\n+\t\tif (would_convert_lf_at_checkout(new_convert_stats,\n+\t\t\t\t\t\t len, crlf_action)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_LF;\n+\t\t}\n+\t\tcheck_safe_crlf(path, crlf_action, checksafe,\n+\t\t\t\tconvert_stats, new_convert_stats);\n+\t}\n+\tif (!convert_crlf)\n \t\treturn 0;\n \n \t/*\n@@ -327,7 +386,9 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (strbuf_avail(buf) + buf->len < len)\n \t\tstrbuf_grow(buf, len - buf->len);\n \tdst = buf->buf;\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n \t\t/*\n \t\t * If we guessed, we already know we rejected a file with\n \t\t * lone CR, and we can strip a CR without looking at what\n@@ -354,28 +415,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n-\n-\n-\tif (!len || output_eol(crlf_action) != EOL_CRLF)\n+\tunsigned earlyout = 0; /* Need to count lonelf */\n+\tif (!len)\n \t\treturn 0;\n \n \tgather_stats(src, len, &stats, earlyout);\n-\n-\t/* No \"naked\" LF? Nothing to convert, regardless. */\n-\tif (!stats.lonelf)\n+\tif (!would_convert_lf_at_checkout(stats.stat_bits,\n+\t\t\t\t\t  len, crlf_action))\n \t\treturn 0;\n \n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t/* This is the new safer autocrlf-handling */\n-\t\tif (stats.lonecr || stats.crlf )\n-\t\t\treturn 0;\n-\n-\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n-\t\t\treturn 0;\n-\t}\n-\n \t/* are we \"faking\" in place editing ? */\n \tif (src == buf->buf)\n \t\tto_free = strbuf_detach(buf, NULL);\n@@ -1067,6 +1115,8 @@ int is_null_stream_filter(struct stream_filter *filter)\n struct lf_to_crlf_filter {\n \tstruct stream_filter filter;\n \tunsigned has_held:1;\n+\tunsigned expanded_loneLF:1;\n+\tunsigned had_CRLF:1;\n \tchar held;\n };\n \n@@ -1107,7 +1157,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \t\t\tchar ch = input[i];\n \n \t\t\tif (ch == '\\n') {\n-\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\tif (!lf_to_crlf->had_CRLF) {\n+\t\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\t\tlf_to_crlf->expanded_loneLF = 1;\n+\t\t\t\t}\n+\t\t\t\tif (was_cr)\n+\t\t\t\t\tlf_to_crlf->had_CRLF = 1;\n \t\t\t} else if (was_cr) {\n \t\t\t\t/*\n \t\t\t\t * Previous round saw CR and it is not followed\n@@ -1136,6 +1191,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \n \t\t\twas_cr = 0;\n \t\t\toutput[o++] = ch;\n+\t\t\tif (lf_to_crlf->expanded_loneLF &&\n+\t\t\t    lf_to_crlf->had_CRLF) {\n+\t\t\t\t/*\n+\t\t\t\t * Mixed EOL, round trip not possible.\n+\t\t\t\t */\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n \t\t}\n \n \t\t*osize_p -= o;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex d0bee08..b5f93e2 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n+test_expect_success 'crlf=true causes a CRLF file not to be normalized' '\n \n \t# Backwards compatibility check\n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n-test_expect_success 'text=true causes a CRLF file to be normalized' '\n+test_expect_success 'text=true causes a CRLF file not to be normalized' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \techo \"CRLFonly text\" > .gitattributes &&\n@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 8367d0b..a16e513 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -71,10 +71,14 @@ check_warning () {\n \tcase \"$1\" in\n \tLF_CRLF) echo \"warning: LF will be replaced by CRLF\" >\"$2\".expect ;;\n \tCRLF_LF) echo \"warning: CRLF will be replaced by LF\" >\"$2\".expect ;;\n+\tCRLF)    echo \"warning: CRLF will be present after commit and checkout\" >\"$2\".expect ;;\n+\tmixed)   echo \"warning: mixed eol will be present after commit and checkout\" >\"$2\".expect ;;\n \t'')\t                                                 >\"$2\".expect ;;\n \t*) echo >&2 \"Illegal 1\": \"$1\" ; return false ;;\n \tesac\n-\tgrep \"will be replaced by\" \"$2\" | sed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" | uniq  >\"$2\".actual\n+\tegrep \"will be replaced by|will be present after commit\" \"$2\" |\n+\t\tsed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" |\n+\t\tuniq  >\"$2\".actual\n \ttest_cmp \"$2\".expect \"$2\".actual\n }\n \n@@ -169,7 +173,7 @@ stats_ascii () {\n # Take none (=empty), one or two args\n # convert.c: eol=XX overrides text=auto\n attr_ascii () {\n-\tcase $1,$2 in\n+\tcase \"$1\",\"$2\" in\n \t-text,*)   echo \"-text\" ;;\n \ttext,)     echo \"text\" ;;\n \ttext,lf)   echo \"text eol=lf\" ;;\n@@ -349,10 +353,12 @@ then\n \tWILC=LF_CRLF\n \tWICL=\n \tWAMIX=LF_CRLF\n+\tPcrlf=\n else\n \tWILC=\n \tWICL=CRLF_LF\n \tWAMIX=CRLF_LF\n+\tPcrlf=CRLF\n fi\n \n #                         attr   LF        CRLF      CRLFmixLF LFmixCR   CRLFNUL\n@@ -392,31 +398,32 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+#                 attr    aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n+\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$Pcrlf\"  mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$Pcrlf\"  mixed       \"$WILC\"     \"$Pcrlf\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF      mixed       \"\"          CRLF\n+\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n-\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf      $crlf   \"\"        CRLF      mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf    $crlf   LF_CRLF   \"\"        mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO text  lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO text  crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n done\n \n-commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n-commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n-\n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n \tgit -c core.autocrlf=false reset --hard\n@@ -456,9 +463,9 @@ do\n \tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n@@ -479,12 +486,10 @@ done\n \n if test_have_prereq NATIVE_CRLF\n then\n-MIX_CRLF_LF=CRLF\n MIX_LF_CR=CRLF_mix_CR\n NL=CRLF\n LFNUL=CRLF_nul\n else\n-MIX_CRLF_LF=CRLF_mix_LF\n MIX_LF_CR=LF_mix_CR\n NL=LF\n LFNUL=LF_nul\n@@ -492,8 +497,7 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-#for id in \"\" ident\n-for id in \"\"\n+for id in \"\" ident\n do\n \tfor ceol in lf crlf native\n \tdo\n@@ -501,38 +505,38 @@ do\n \t\tdo\n \t\t\t# -text overrides core.autocrlf and core.eol\n \t\t\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n-\t\t\tcheckout_files -text \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files -text \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files -text \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\t# text\n-\t\t\tcheckout_files text  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files text    \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files text    \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t\t# currently the same as text, eol=XXX\n-\t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto    \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto    \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \n \t\t# core.autocrlf false, different core.eol\n-\t\tcheckout_files   \"\"    \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   \"\"      \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# core.autocrlf true\n-\t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   \"\"      \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tcheckout_files   auto    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   text    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n-\t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files   auto  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   text    \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto    \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text=auto + eol=XXX\n \tdone\n \t# text: core.autocrlf=false uses core.eol\n-\tcheckout_files     text  \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files     text  \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     text    \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n+\tcheckout_files     text    \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files     text    \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  \"$MIX_LF_CR\" \"$LFNUL\"\n+\tcheckout_files     text    \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  \"$MIX_LF_CR\" \"$LFNUL\"\n \t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto    \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto    \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"284440","messageId":"1461603400-30952-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v7 09/10] t6038; use crlf on all platforms","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-25T16:56:40Z","receivedAt":"2016-04-25T16:56:40Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nt6038 uses different code, dependig if NATIVE_CRLF is set ot not. When\nthe native line endings are LF, merge.renormalize is not tested very well.\nChange the test to always use CRLF by setting core.eol=crlf.\nAfter doing so, the test fails:\n\nrm '.gitattributes'\nrm 'control_file'\nrm 'file'\nrm 'inert_file'\nHEAD is now at 0d9ffb6 add line from b\nerror: addinfo_cache failed for path 'file'\nfile: unmerged (cbd69ec7cd12dd0989e853923867d94c8519aa52)\nfile: unmerged (ad55e240aeb42e0d9a0e18d6d8b02dd82ee3e527)\nfile: unmerged (99b633103c15c20cebebf821133ab526b0ff90b2)\nfatal: git write-tree failed to write a tree\nMerging:\n0d9ffb6 add line from b\nvirtual a\nfound 1 common ancestor:\n1c56df1 Initial\nAuto-merging file\nnot ok 4 - Merge addition of text=auto\n\nThis will be addressed in the next commit.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n t/t6038-merge-text-auto.sh | 37 +++++++++++--------------------------\n 1 file changed, 11 insertions(+), 26 deletions(-)\n\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 33b77ee..0108ead 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -25,6 +25,7 @@ compare_files () {\n \n test_expect_success setup '\n \tgit config core.autocrlf false &&\n+\tgit config core.eol crlf &&\n \n \techo first line | append_cr >file &&\n \techo first line >control_file &&\n@@ -79,10 +80,8 @@ test_expect_success 'Merge after setting text=auto' '\n \tsame line\n \tEOF\n \n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\tappend_cr <expected >expected.temp &&\n-\t\tmv expected.temp expected\n-\tfi &&\n+\tappend_cr <expected >expected.temp &&\n+\tmv expected.temp expected &&\n \tgit config merge.renormalize true &&\n \tgit rm -fr . &&\n \trm -f .gitattributes &&\n@@ -97,10 +96,8 @@ test_expect_success 'Merge addition of text=auto' '\n \tsame line\n \tEOF\n \n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\tappend_cr <expected >expected.temp &&\n-\t\tmv expected.temp expected\n-\tfi &&\n+\tappend_cr <expected >expected.temp &&\n+\tmv expected.temp expected &&\n \tgit config merge.renormalize true &&\n \tgit rm -fr . &&\n \trm -f .gitattributes &&\n@@ -111,15 +108,9 @@ test_expect_success 'Merge addition of text=auto' '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \techo \"<<<<<<<\" >expected &&\n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\techo first line | append_cr >>expected &&\n-\t\techo same line | append_cr >>expected &&\n-\t\techo ======= | append_cr >>expected\n-\telse\n-\t\techo first line >>expected &&\n-\t\techo same line >>expected &&\n-\t\techo ======= >>expected\n-\tfi &&\n+\techo first line | append_cr >>expected &&\n+\techo same line | append_cr >>expected &&\n+\techo ======= | append_cr >>expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n@@ -135,15 +126,9 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \techo \"<<<<<<<\" >expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\techo ======= | append_cr >>expected &&\n-\t\techo first line | append_cr >>expected &&\n-\t\techo same line | append_cr >>expected\n-\telse\n-\t\techo ======= >>expected &&\n-\t\techo first line >>expected &&\n-\t\techo same line >>expected\n-\tfi &&\n+\techo ======= | append_cr >>expected &&\n+\techo first line | append_cr >>expected &&\n+\techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n \tgit config merge.renormalize false &&\n \trm -f .gitattributes &&\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"284441","messageId":"1461603401-30993-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v7 10/10] ce_compare_data() did not respect conversion","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-25T16:56:41Z","receivedAt":"2016-04-25T16:56:41Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWe define the working tree file is clean if either:\n\n  * the result of running convert_to_git() on the working tree\n    contents matches what is in the index (because that would mean\n    doing another \"git add\" on the path is a no-op); OR\n\n  * the result of running convert_to_working_tree() on the content\n    in the index matches what is in the working tree (because that\n    would mean doing another \"git checkout -f\" on the path is a\n    no-op).\n\nAdd an extra check in ce_compare_data() in read_cache.c.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n read-cache.c               | 61 ++++++++++++++++++++++++++++++++++++++++++++++\n t/t6038-merge-text-auto.sh | 14 +++++------\n 2 files changed, 68 insertions(+), 7 deletions(-)\n\ndiff --git a/read-cache.c b/read-cache.c\nindex a3ef967..48c4b31 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -156,17 +156,78 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)\n \t\tce_mark_uptodate(ce);\n }\n \n+/*\n+ * Compare the data in buf with the data in the file pointed by fd and\n+ * return 0 if they are identical, and non-zero if they differ.\n+ */\n+static int compare_with_fd(const char *input, ssize_t len, int fd)\n+{\n+\tfor (;;) {\n+\t\tchar buf[1024 * 16];\n+\t\tssize_t chunk_len, read_len;\n+\n+\t\tchunk_len = sizeof(buf) < len ? sizeof(buf) : len;\n+\t\tread_len = xread(fd, buf, chunk_len ? chunk_len : 1);\n+\n+\t\tif (!read_len)\n+\t\t\t/* EOF on the working tree file */\n+\t\t\treturn !len ? 0 : -1;\n+\n+\t\tif (!len)\n+\t\t\t/* we expected there is nothing left */\n+\t\t\treturn -1;\n+\n+\t\tif (memcmp(buf, input, read_len))\n+\t\t\treturn -1;\n+\t\tinput += read_len;\n+\t\tlen -= read_len;\n+\t}\n+}\n+\n static int ce_compare_data(const struct cache_entry *ce, struct stat *st)\n {\n \tint match = -1;\n \tint fd = open(ce->name, O_RDONLY);\n \n+\t/*\n+\t * Would another \"git add\" on the path change what is in the\n+\t * index for the path?\n+\t */\n \tif (fd >= 0) {\n \t\tunsigned char sha1[20];\n \t\tif (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, 0))\n \t\t\tmatch = hashcmp(sha1, ce->sha1);\n \t\t/* index_fd() closed the file descriptor already */\n \t}\n+\tif (!match)\n+\t\treturn match;\n+\n+\t/*\n+\t * Would another \"git checkout -f\" out of the index change\n+\t * what is in the working tree file?\n+\t */\n+\tfd = open(ce->name, O_RDONLY);\n+\tif (fd >= 0) {\n+\t\tenum object_type type;\n+\t\tunsigned long size_long;\n+\t\tvoid *data = read_sha1_file(ce->sha1, &type, &size_long);\n+\n+\t\tif (type == OBJ_BLOB) {\n+\t\t\tstruct strbuf worktree = STRBUF_INIT;\n+\t\t\tif (convert_to_working_tree(ce->name, data,\n+\t\t\t\t\t\t    size_long,\n+\t\t\t\t\t\t    &worktree)) {\n+\t\t\t\tsize_t size;\n+\t\t\t\tfree(data);\n+\t\t\t\tdata = strbuf_detach(&worktree, &size);\n+\t\t\t\tsize_long = size;\n+\t\t\t}\n+\t\t\tif (!compare_with_fd(data, size_long, fd))\n+\t\t\t\tmatch = 0;\n+\t\t}\n+\t\tfree(data);\n+\t\tclose(fd);\n+\t}\n \treturn match;\n }\n \ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 0108ead..565daf3 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -108,9 +108,9 @@ test_expect_success 'Merge addition of text=auto' '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \techo \"<<<<<<<\" >expected &&\n-\techo first line | append_cr >>expected &&\n-\techo same line | append_cr >>expected &&\n-\techo ======= | append_cr >>expected &&\n+\techo first line >>expected &&\n+\techo same line >>expected &&\n+\techo ======= >>expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n@@ -121,14 +121,13 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \tfuzz_conflict file >file.fuzzy &&\n \tcompare_files expected file.fuzzy\n '\n-\n test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \techo \"<<<<<<<\" >expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n-\techo ======= | append_cr >>expected &&\n-\techo first line | append_cr >>expected &&\n-\techo same line | append_cr >>expected &&\n+\techo =======  >>expected &&\n+\techo first line >>expected &&\n+\techo same line  >>expected &&\n \techo \">>>>>>>\" >>expected &&\n \tgit config merge.renormalize false &&\n \trm -f .gitattributes &&\n@@ -138,6 +137,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \tcompare_files expected file.fuzzy\n '\n \n+\n test_expect_failure 'checkout -m after setting text=auto' '\n \tcat <<-\\EOF >expected &&\n \tfirst line\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"284471","messageId":"xmqqy481jy9y.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1461603387-30639-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v7 01/10] t0027: Make commit_chk_wrnNNO() reliable","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-25T19:15:05Z","receivedAt":"2016-04-25T19:15:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> When the content of a commited file is unchanged and the attributes are changed,\n> Git may not detect that the next commit must treat the file as changed.\n> This happens when lstat() doesn't detect a change, since neither inode,\n> mtime nor size are changed.\n>\n> Add a singe \"Z\" character to change the file size (and content).\n\nsingLe (no need to reroll for this nit; locally fixed already).\n\n\n\n> When the files are compared later in checkout_files(), the \"Z\" is removed\n> before the comparison.\n>\n> Signed-off-by: Torsten Bögershausen <tboegi@web.de>\n> ---\n>  Change since v6b:\n>  - Remove 2 sparse warnings, thanks Ramsay\n>\n> diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\n> index f33962b..9fe539b 100755\n> --- a/t/t0027-auto-crlf.sh\n> +++ b/t/t0027-auto-crlf.sh\n> @@ -12,7 +12,7 @@ fi\n>  \n>  compare_files () {\n>  \ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n> -\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n> +\ttr '\\015\\000' QN <\"$2\" | tr -d 'Z' >\"$2\".actual &&\n>  \ttest_cmp \"$1\".expect \"$2\".actual &&\n>  \trm \"$1\".expect \"$2\".actual\n>  }\n> @@ -114,6 +114,7 @@ commit_chk_wrnNNO () {\n>  \tdo\n>  \t\tfname=${pfx}_$f.txt &&\n>  \t\tcp $f $fname &&\n> +\t\tprintf Z >>\"$fname\" &&\n>  \t\tgit -c core.autocrlf=$crlf add $fname 2>/dev/null &&\n>  \t\tgit -c core.autocrlf=$crlf commit -m \"commit_$fname\" $fname >\"${pfx}_$f.err\" 2>&1\n>  \tdone\n"},{"id":"284473","messageId":"xmqqtwipjx9f.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1461603397-30873-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v7 07/10] convert: unify the \"auto\" handling of CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-25T19:37:00Z","receivedAt":"2016-04-25T19:37:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> Before this change,\n> $ echo \"* text=auto\" >.gitattributes\n> $ echo \"* eol=crlf\" >>.gitattributes\n>\n> would have the same effect as\n> $ echo \"* text\" >.gitattributes\n> $ git config core.eol crlf\n>\n> Since the 'eol' attribute had higher priority than 'text=auto', this may\n> corrupt binary files and is not what users expect to happen.\n\nIs the last \"Since ...\" continuation of the above two, i.e. \"with\nthe current code, the first one (unfortunately) means the same as\nthe second one, BECAUSE ...\"?  If so, s/Since/since/ (I needed to\nread it twice to guess that is probably what you meant).\n\nThe above is a very good justification of the entire series,\nillustrating why this is worth doing.\n\n> Make the 'eol' attribute to obey 'text=auto', and now\n\ns/to obey/obey/ (make X do Y, not make X to do Y); I'd probably\nfurther do 's/obey/honor/' or even 's/obey/work better with/'\n\n> $ echo \"* text=auto\" >.gitattributes\n> $ echo \"* eol=crlf\" >>.gitattributes\n> behaves the same as\n> $ echo \"* text=auto\" >.gitattributes\n> $ git config core.eol crlf\n>\n> In other words,\n> $ echo \"* text=auto eol=crlf\" >.gitattributes\n> has the same effect as\n> $ git config core.autocrlf true\n> and\n> $ echo \"* text=auto eol=lf\" >.gitattributes\n> has the same effect as\n> $ git config core.autocrlf input\n\nIt is kind of disappointing that the none of the above block of\nconfiguration examples does not quite say what the reader really\nwants to know directly.  I am guessing that the point is\n\n    now text=auto does autodetection even when eol=crlf is\n    specified, and files that are declared to be non-text will not\n    get clobbered with eol=crlf conversion\n\nright?  If that is the case, replacing everything below \"In other\nwords\" with these three lines would make the text much easier to\ngrok, I would think.\n\n> Signed-off-by: Torsten Bögershausen <tboegi@web.de>\n> ---\n>  Documentation/config.txt        | 14 +++++++-------\n>  Documentation/gitattributes.txt | 15 +++++++++------\n>  convert.c                       | 42 +++++++++++++++++++++--------------------\n>  convert.h                       |  3 ++-\n>  t/t0025-crlf-auto.sh            |  4 ++--\n>  t/t0027-auto-crlf.sh            | 32 +++++++++++++++----------------\n>  t/t6038-merge-text-auto.sh      | 23 ++++++++++++++--------\n>  7 files changed, 73 insertions(+), 60 deletions(-)\n>\n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> index 4a27ad4..9caf6ae 100644\n> --- a/Documentation/config.txt\n> +++ b/Documentation/config.txt\n> @@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf`\n>  mechanism.\n>  \n>  core.autocrlf::\n> -\tSetting this variable to \"true\" is almost the same as setting\n> -\tthe `text` attribute to \"auto\" on all files except that text\n> -\tfiles are not guaranteed to be normalized: files that contain\n> -\t`CRLF` in the repository will not be touched.  Use this\n> -\tsetting if you want to have `CRLF` line endings in your\n> -\tworking directory even though the repository does not have\n> -\tnormalized line endings.  This variable can be set to 'input',\n> +\tSetting this variable to \"true\" is the same as setting\n> +\tthe `text` attribute to \"auto\" on all files and core.eol to \"crlf\".\n> +\tSet to true if you want to have `CRLF` line endings in your\n> +\tworking directory and the repository has LF line endings.\n> +\tText files are guaranteed not to be normalized: files that contain\n> +\t`CRLF` in the repository will not be touched.\n\nThis is not a new problem but the last sentence and a half look\nbad.  Telling readers \"X is not guaranteed to happen\" is not all\nthat useful--telling them what happens is.  Also the use of colon\nthere is probably ungrammatical.\n\n\tSet to true if you want to have CRLF line endings in your\n\tworking directory and LF line endings in the repository.\n\tText files that contain CRLF in the repository will not get\n\ttheir end-of-line converted.\n\nperhaps?\n\n> diff --git a/convert.h b/convert.h\n> index ccf436b..81b6cdf 100644\n> --- a/convert.h\n> +++ b/convert.h\n> @@ -7,7 +7,8 @@\n>  enum safe_crlf {\n>  \tSAFE_CRLF_FALSE = 0,\n>  \tSAFE_CRLF_FAIL = 1,\n> -\tSAFE_CRLF_WARN = 2\n> +\tSAFE_CRLF_WARN = 2,\n> +\tSAFE_CRLF_RENORMALIZE = 4\n\nAre these bits in a word?  If not where did 3 go?\n\n> diff --git a/convert.c b/convert.c\n> index 24ab095..3782172 100644\n> --- a/convert.c\n> +++ b/convert.c\n> @@ -227,7 +227,9 @@ static enum eol output_eol(enum crlf_action crlf_action)\n>  \t\treturn EOL_LF;\n>  \tcase CRLF_UNDEFINED:\n>  \tcase CRLF_AUTO_CRLF:\n> +\t\treturn EOL_CRLF;\n\nHmph, do we want UNDEFINED case to return EOL_CRLF here?\n\n>  \tcase CRLF_AUTO_INPUT:\n> +\t\treturn EOL_LF;\n>  \tcase CRLF_TEXT:\n>  \tcase CRLF_AUTO:\n>  \t\t/* fall through */\n"},{"id":"284537","messageId":"41d4d5c6-f964-8d3f-0e07-fd98b2f6b71e@web.de","threadId":"41391","inReplyTo":"xmqqtwipjx9f.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v7 07/10] convert: unify the \"auto\" handling of CRLF","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-04-26T16:33:22Z","receivedAt":"2016-04-26T16:33:22Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 25.04.16 21:37, Junio C Hamano wrote:\n> tboegi@web.de writes:\nThanks for review.\nSome comments are inline, and a suggestion to a new commit message at the end.\n[]\n>> diff --git a/Documentation/config.txt b/Documentation/config.txt\n>> index 4a27ad4..9caf6ae 100644\n>> --- a/Documentation/config.txt\n>> +++ b/Documentation/config.txt\n>> @@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf`\n>>  mechanism.\n>>  \n>>  core.autocrlf::\n>> -\tSetting this variable to \"true\" is almost the same as setting\n>> -\tthe `text` attribute to \"auto\" on all files except that text\n>> -\tfiles are not guaranteed to be normalized: files that contain\n>> -\t`CRLF` in the repository will not be touched.  Use this\n>> -\tsetting if you want to have `CRLF` line endings in your\n>> -\tworking directory even though the repository does not have\n>> -\tnormalized line endings.  This variable can be set to 'input',\n>> +\tSetting this variable to \"true\" is the same as setting\n>> +\tthe `text` attribute to \"auto\" on all files and core.eol to \"crlf\".\n>> +\tSet to true if you want to have `CRLF` line endings in your\n>> +\tworking directory and the repository has LF line endings.\n>> +\tText files are guaranteed not to be normalized: files that contain\n>> +\t`CRLF` in the repository will not be touched.\n> \n> This is not a new problem but the last sentence and a half look\n> bad.  Telling readers \"X is not guaranteed to happen\" is not all\n> that useful--telling them what happens is.  Also the use of colon\n> there is probably ungrammatical.\n\n> \n> \tSet to true if you want to have CRLF line endings in your\n> \tworking directory and LF line endings in the repository.\n> \tText files that contain CRLF in the repository will not get\n> \ttheir end-of-line converted.\n> \n> perhaps?\nOK, but may be \ns/end-of-line/line endings/\n----------\nSet to true if you want to have CRLF line endings in your\nworking directory and LF line endings in the repository.\nText files that contain CRLF in the repository will not get\ntheir line endings converted.\n\n\n> \n>> diff --git a/convert.h b/convert.h\n>> index ccf436b..81b6cdf 100644\n>> --- a/convert.h\n>> +++ b/convert.h\n>> @@ -7,7 +7,8 @@\n>>  enum safe_crlf {\n>>  \tSAFE_CRLF_FALSE = 0,\n>>  \tSAFE_CRLF_FAIL = 1,\n>> -\tSAFE_CRLF_WARN = 2\n>> +\tSAFE_CRLF_WARN = 2,\n>> +\tSAFE_CRLF_RENORMALIZE = 4\n> \n> Are these bits in a word?  If not where did 3 go?\nWe use an enum, sometimes mixed with an int, so my brain automatically\nchanged it into a bit field.\n\"3\" is probably better.\n> \n>> diff --git a/convert.c b/convert.c\n>> index 24ab095..3782172 100644\n>> --- a/convert.c\n>> +++ b/convert.c\n>> @@ -227,7 +227,9 @@ static enum eol output_eol(enum crlf_action crlf_action)\n>>  \t\treturn EOL_LF;\n>>  \tcase CRLF_UNDEFINED:\n>>  \tcase CRLF_AUTO_CRLF:\n>> +\t\treturn EOL_CRLF;\n> \n> Hmph, do we want UNDEFINED case to return EOL_CRLF here?\n> \n>>  \tcase CRLF_AUTO_INPUT:\n>> +\t\treturn EOL_LF;\nOne of the compilers claimed that UNDEFINED was not handled in switch-case.\nA Warning may be better ? \n>>  \tcase CRLF_TEXT:\n>>  \tcase CRLF_AUTO:\n>>  \t\t/* fall through */\n> \nHow about this as the commit message:\n--------------------------------------\n\nconvert: unify the \"auto\" handling of CRLF\n\nFrom: Torsten Bögershausen <tboegi@web.de>\n\nBefore this change,\n$ echo \"* text=auto\" >.gitattributes\n$ echo \"* eol=crlf\" >>.gitattributes\nwould have the same effect as\n$ echo \"* text\" >.gitattributes\n$ git config core.eol crlf\n\nThe 'eol' attribute had higher priority than 'text=auto'. Binary\nfiles may had been corrupted, and this is not what users expect to happen.\n\nMake the 'eol' attribute to work together with 'text=auto'.\n\nWith this change\n\n$ echo \"* text=auto eol=crlf\" >.gitattributes\nhas the same effect as\n$ git config core.autocrlf true\n\nand\n\n$ echo \"* text=auto eol=lf\" >.gitattributes\nhas the same effect as\n$ git config core.autocrlf input\n"},{"id":"284548","messageId":"xmqqy480gtbm.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"41d4d5c6-f964-8d3f-0e07-fd98b2f6b71e@web.de","subject":"Re: [PATCH v7 07/10] convert: unify the \"auto\" handling of CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-26T17:42:37Z","receivedAt":"2016-04-26T17:42:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n>>> diff --git a/convert.c b/convert.c\n>>> index 24ab095..3782172 100644\n>>> --- a/convert.c\n>>> +++ b/convert.c\n>>> @@ -227,7 +227,9 @@ static enum eol output_eol(enum crlf_action crlf_action)\n>>>  \t\treturn EOL_LF;\n>>>  \tcase CRLF_UNDEFINED:\n>>>  \tcase CRLF_AUTO_CRLF:\n>>> +\t\treturn EOL_CRLF;\n>> \n>> Hmph, do we want UNDEFINED case to return EOL_CRLF here?\n>> \n>>>  \tcase CRLF_AUTO_INPUT:\n>>> +\t\treturn EOL_LF;\n> One of the compilers claimed that UNDEFINED was not handled in switch-case.\n> A Warning may be better ? \n>>>  \tcase CRLF_TEXT:\n>>>  \tcase CRLF_AUTO:\n>>>  \t\t/* fall through */\n\nThe original made it fall-through; a very simple \"a patch that makes\nauto=crlf or auto=input do something different shouldn't have any\neffect on the undefined case\" was what triggered my reaction.\n\nIf returning EOL_CRLF does not make any sense for UNDEFINED case, it\nshouldn't.  If the codeflow should not reach without crlf_action\ncomputed to something other than UNDEFINED, then you should have a\ndie(\"BUG\") there.\n\nLooking at a larger context, you already have a warning there:\n\n    static enum eol output_eol(enum crlf_action crlf_action)\n    {\n            switch (crlf_action) {\n            case CRLF_BINARY:\n                    return EOL_UNSET;\n            ...\n            case CRLF_AUTO:\n                    /* fall through */\n                    return text_eol_is_crlf() ? EOL_CRLF : EOL_LF;\n            }\n            warning(\"Illegal crlf_action %d\\n\", (int)crlf_action);\n            return core_eol;\n    }\n\nwhich tells me that you shouldn't even have CRLF_UNDEFINED listed if\nyou have no intention to treat UNDEFINED as a valid input in this\ncodepath.  Instead just doing\n\n\tswitch (crlf_action) {\n        case ...: /* handle all valid inputs appropriately */\n        \treturn ...;\n\t...\n\tdefault: /* the above should cover all valid cases */\n\t\tbreak;\n\t}\n        warning(...);\n        return ...;\n\nand not listing CRLF_UNDEFINED in any of the case arms would make\nyour intention more clear.\n\n>> \n> How about this as the commit message:\n> --------------------------------------\n> ...\n> The 'eol' attribute had higher priority than 'text=auto'. Binary\n> files may had been corrupted, and this is not what users expect to happen.\n>\n> Make the 'eol' attribute to work together with 'text=auto'.\n\nThe primary issue I had was that \"work together\" was a useful\nexplanation only to those who already understand what you are trying\nto do with this patch.\n\nSomething like:\n\n\tHaving an \"eol\" attribute is taken as a declaration that the\n\tpath is text.  This may be logical (on a binary blob, you\n\twouldn't be defining an \"eol\" attribute in the first place)\n\tbut is not very useful if you wanted to say \"I do not know\n\tif the path is text; inspect the contents to see if it is\n\ttext, and apply this 'eol' conversion only if it is\".\n\n\t\"text=auto\" attribute combined with an \"eol\" attribute ought\n\tto have meant that, but it didn't.  Make it so.\n\nwould be sufficient without any configuration example, I would think.\n\n> With this change\n>\n> $ echo \"* text=auto eol=crlf\" >.gitattributes\n> has the same effect as\n> $ git config core.autocrlf true\n>\n> and\n>\n> $ echo \"* text=auto eol=lf\" >.gitattributes\n> has the same effect as\n> $ git config core.autocrlf input\n"},{"id":"284935","messageId":"1461942112-15943-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v8 01/10] t0027: make commit_chk_wrnNNO() reliable","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-29T15:01:52Z","receivedAt":"2016-04-29T15:01:52Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen the content of a commited file is unchanged and the attributes\nare changed, Git may not detect that the next commit must treat the\nfile as changed.  This happens when lstat() doesn't detect a change,\nsince neither inode, mtime nor size are changed.\n\nAdd a single \"Z\" character to change the file size and content.\nWhen the files are compared later in checkout_files(), the \"Z\" is\nremoved before the comparison.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\nChanges against tb/convert-eol-autocrlf:\n  7/10 Implemented all comments, new commit message++\nt/t0027-auto-crlf.sh | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex f33962b..9fe539b 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -12,7 +12,7 @@ fi\n \n compare_files () {\n \ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n-\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n+\ttr '\\015\\000' QN <\"$2\" | tr -d 'Z' >\"$2\".actual &&\n \ttest_cmp \"$1\".expect \"$2\".actual &&\n \trm \"$1\".expect \"$2\".actual\n }\n@@ -114,6 +114,7 @@ commit_chk_wrnNNO () {\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n \t\tcp $f $fname &&\n+\t\tprintf Z >>\"$fname\" &&\n \t\tgit -c core.autocrlf=$crlf add $fname 2>/dev/null &&\n \t\tgit -c core.autocrlf=$crlf commit -m \"commit_$fname\" $fname >\"${pfx}_$f.err\" 2>&1\n \tdone\n-- \n2.7.0.992.g0c2c796\n"},{"id":"284930","messageId":"1461942115-15982-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v8 02/10] convert: allow core.autocrlf=input and core.eol=crlf","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-29T15:01:55Z","receivedAt":"2016-04-29T15:01:55Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nEven though the configuration parser errors out when core.autocrlf\nis set to 'input' when core.eol is set to 'crlf', there is no need\nto do so, because the core.autocrlf setting trumps core.eol.\n\nAllow all combinations of core.crlf and core.eol and document\nthat core.autocrlf overrides core.eol.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt | 6 +++---\n config.c                 | 4 ----\n 2 files changed, 3 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2cd6bdd..4a27ad4 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -337,9 +337,9 @@ core.quotePath::\n \n core.eol::\n \tSets the line ending type to use in the working directory for\n-\tfiles that have the `text` property set.  Alternatives are\n-\t'lf', 'crlf' and 'native', which uses the platform's native\n-\tline ending.  The default value is `native`.  See\n+\tfiles that have the `text` property set when core.autocrlf is false.\n+\tAlternatives are 'lf', 'crlf' and 'native', which uses the platform's\n+\tnative line ending.  The default value is `native`.  See\n \tlinkgit:gitattributes[5] for more information on end-of-line\n \tconversion.\n \ndiff --git a/config.c b/config.c\nindex 9ba40bc..a6adc8b 100644\n--- a/config.c\n+++ b/config.c\n@@ -803,8 +803,6 @@ static int git_default_core_config(const char *var, const char *value)\n \n \tif (!strcmp(var, \"core.autocrlf\")) {\n \t\tif (value && !strcasecmp(value, \"input\")) {\n-\t\t\tif (core_eol == EOL_CRLF)\n-\t\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\t\tauto_crlf = AUTO_CRLF_INPUT;\n \t\t\treturn 0;\n \t\t}\n@@ -830,8 +828,6 @@ static int git_default_core_config(const char *var, const char *value)\n \t\t\tcore_eol = EOL_NATIVE;\n \t\telse\n \t\t\tcore_eol = EOL_UNSET;\n-\t\tif (core_eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)\n-\t\t\treturn error(\"core.autocrlf=input conflicts with core.eol=crlf\");\n \t\treturn 0;\n \t}\n \n-- \n2.7.0.992.g0c2c796\n"},{"id":"284934","messageId":"1461942117-16021-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v8 03/10] t0027: test cases for combined attributes","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-29T15:01:57Z","receivedAt":"2016-04-29T15:01:57Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nAdd more test cases for the not normalized files (\"NNO\"). The\n\"text\" attribute is most important, use it as the first parameter.\n\"ident\", if set, is the second paramater followed by the eol\nattribute.  The eol attribute overrides core.autocrlf, which\noverrides core.eol.\nindent is not yet used, this will be done in the next commit.\n\nUse loops to test more combinations of attributes, like\n\"* text eol=crlf\" or especially \"*text=auto eol=crlf\".\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n t/t0027-auto-crlf.sh | 298 ++++++++++++++++++++++-----------------------------\n 1 file changed, 129 insertions(+), 169 deletions(-)\n\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 9fe539b..fd5e326 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -52,14 +52,17 @@ create_gitattributes () {\n create_NNO_files () {\n \tfor crlf in false true input\n \tdo\n-\t\tfor attr in \"\" auto text -text lf crlf\n+\t\tfor attr in \"\" auto text -text\n \t\tdo\n-\t\t\tpfx=NNO_${crlf}_attr_${attr} &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n-\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tfor aeol in \"\" lf crlf\n+\t\t\tdo\n+\t\t\t\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_LF_mix_CR.txt &&\n+\t\t\t\tcp CRLF_mix_LF ${pfx}_CRLF_nul.txt\n+\t\t\tdone\n \t\tdone\n \tdone\n }\n@@ -100,16 +103,17 @@ commit_check_warn () {\n }\n \n commit_chk_wrnNNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfwarn=$3\n-\tcrlfwarn=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfwarn=$1 ; shift\n+\tcrlfwarn=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n \t#Commit files on top of existing file\n-\tcreate_gitattributes \"$attr\" &&\n+\tcreate_gitattributes \"$attr\" $aeol &&\n \tfor f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n \tdo\n \t\tfname=${pfx}_$f.txt &&\n@@ -122,19 +126,19 @@ commit_chk_wrnNNO () {\n \ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF\" '\n \t\tcheck_warning \"$lfwarn\" ${pfx}_LF.err\n \t'\n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF\" '\n \t\tcheck_warning \"$crlfwarn\" ${pfx}_CRLF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_mix_LF\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_mix_LF\" '\n \t\tcheck_warning \"$lfmixcrlf\" ${pfx}_CRLF_mix_LF.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr LF_mix_cr\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf LF_mix_cr\" '\n \t\tcheck_warning \"$lfmixcr\" ${pfx}_LF_mix_CR.err\n \t'\n \n-\ttest_expect_success \"commit NNO files crlf=$crlf attr=$attr CRLF_nul\" '\n+\ttest_expect_success \"commit NNO files attr=$attr aeol=$aeol crlf=$crlf CRLF_nul\" '\n \t\tcheck_warning \"$crlfnul\" ${pfx}_CRLF_nul.err\n \t'\n }\n@@ -163,6 +167,7 @@ stats_ascii () {\n \n # contruct the attr/ returned by git ls-files --eol\n # Take none (=empty), one or two args\n+# convert.c: eol=XX overrides text=auto\n attr_ascii () {\n \tcase $1,$2 in\n \t-text,*)   echo \"-text\" ;;\n@@ -170,8 +175,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text=auto eol=lf\" ;;\n-\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n+\tauto,lf)   echo \"text eol=lf\" ;;\n+\tauto,crlf) echo \"text eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -196,28 +201,29 @@ check_files_in_repo () {\n }\n \n check_in_repo_NNO () {\n-\tcrlf=$1\n-\tattr=$2\n-\tlfname=$3\n-\tcrlfname=$4\n-\tlfmixcrlf=$5\n-\tlfmixcr=$6\n-\tcrlfnul=$7\n-\tpfx=NNO_${crlf}_attr_${attr}_\n-\ttest_expect_success \"compare_files $lfname ${pfx}LF.txt\" '\n-\t\tcompare_files $lfname ${pfx}LF.txt\n+\tattr=$1 ; shift\n+\taeol=$1 ; shift\n+\tcrlf=$1 ; shift\n+\tlfname=$1 ; shift\n+\tcrlfname=$1 ; shift\n+\tlfmixcrlf=$1 ; shift\n+\tlfmixcr=$1 ; shift\n+\tcrlfnul=$1 ; shift\n+\tpfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}\n+\ttest_expect_success \"compare_files $lfname ${pfx}_LF.txt\" '\n+\t\tcompare_files $lfname ${pfx}_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfname ${pfx}CRLF.txt\" '\n-\t\tcompare_files $crlfname ${pfx}CRLF.txt\n+\ttest_expect_success \"compare_files $crlfname ${pfx}_CRLF.txt\" '\n+\t\tcompare_files $crlfname ${pfx}_CRLF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\" '\n-\t\tcompare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt\n+\ttest_expect_success \"compare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\" '\n+\t\tcompare_files $lfmixcrlf ${pfx}_CRLF_mix_LF.txt\n \t'\n-\ttest_expect_success \"compare_files $lfmixcr ${pfx}LF_mix_CR.txt\" '\n-\t\tcompare_files $lfmixcr ${pfx}LF_mix_CR.txt\n+\ttest_expect_success \"compare_files $lfmixcr ${pfx}_LF_mix_CR.txt\" '\n+\t\tcompare_files $lfmixcr ${pfx}_LF_mix_CR.txt\n \t'\n-\ttest_expect_success \"compare_files $crlfnul ${pfx}CRLF_nul.txt\" '\n-\t\tcompare_files $crlfnul ${pfx}CRLF_nul.txt\n+\ttest_expect_success \"compare_files $crlfnul ${pfx}_CRLF_nul.txt\" '\n+\t\tcompare_files $crlfnul ${pfx}_CRLF_nul.txt\n \t'\n }\n \n@@ -232,7 +238,7 @@ checkout_files () {\n \tlfmixcrlf=$1 ; shift\n \tlfmixcr=$1 ; shift\n \tcrlfnul=$1 ; shift\n-\tcreate_gitattributes \"$attr\" \"$ident\" &&\n+\tcreate_gitattributes \"$attr\" $ident $aeol &&\n \tgit config core.autocrlf $crlf &&\n \tpfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ &&\n \tfor f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul\n@@ -245,7 +251,7 @@ checkout_files () {\n \t\tfi\n \tdone\n \n-\ttest_expect_success \"ls-files --eol attr=$attr $ident $aeol core.autocrlf=$crlf core.eol=$ceol\" '\n+\ttest_expect_success \"ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol\" '\n \t\ttest_when_finished \"rm expect actual\" &&\n \t\tsort <<-EOF >expect &&\n \t\ti/crlf w/$(stats_ascii $crlfname) attr/$(attr_ascii $attr $aeol) crlf_false_attr__CRLF.txt\n@@ -260,19 +266,19 @@ checkout_files () {\n \t\tsort >actual &&\n \t\ttest_cmp expect actual\n \t'\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF\" \"\n \t\tcompare_ws_file $pfx $lfname    crlf_false_attr__LF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF\" \"\n \t\tcompare_ws_file $pfx $crlfname  crlf_false_attr__CRLF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=CRLF_mix_LF\" \"\n \t\tcompare_ws_file $pfx $lfmixcrlf crlf_false_attr__CRLF_mix_LF.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_mix_CR\" \"\n \t\tcompare_ws_file $pfx $lfmixcr   crlf_false_attr__LF_mix_CR.txt\n \t\"\n-\ttest_expect_success \"checkout $ident $attr $aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n+\ttest_expect_success \"checkout attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol file=LF_nul\" \"\n \t\tcompare_ws_file $pfx $crlfnul   crlf_false_attr__LF_nul.txt\n \t\"\n }\n@@ -386,31 +392,31 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                       attr   LF        CRLF      CRLFmixLF \t LF_mix_CR   CRLFNUL\n-commit_chk_wrnNNO false \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"\"     \"LF_CRLF\" \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"\"     \"\"        \"\"        \"\"        \t \"\"        \t \"\"\n-\n+#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO false \"auto\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"auto\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"auto\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n \n-commit_chk_wrnNNO false \"text\" \"$WILC\"   \"$WICL\"   \"$WAMIX\"  \t \"$WILC\"   \t \"$WICL\"\n-commit_chk_wrnNNO true  \"text\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"text\" \"\"        \"CRLF_LF\" \"CRLF_LF\" \t \"\"        \t \"CRLF_LF\"\n-\n-commit_chk_wrnNNO false \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO true  \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-commit_chk_wrnNNO input \"-text\" \"\"       \"\"        \"\"        \t \"\"        \t \"\"\n-\n-commit_chk_wrnNNO false \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO true  \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n-commit_chk_wrnNNO input \"lf\"    \"\"       \"CRLF_LF\" \"CRLF_LF\" \t  \"\"       \t \"CRLF_LF\"\n+for crlf in true false input\n+do\n+\tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n+\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+done\n \n-commit_chk_wrnNNO false \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO true  \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n-commit_chk_wrnNNO input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \t \"LF_CRLF\" \t \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n \n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n@@ -441,24 +447,20 @@ test_expect_success 'commit -text' '\n \tcheck_files_in_repo input \"-text\" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul\n '\n \n-#                       attr    LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLFNUL\n-check_in_repo_NNO false \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"\"      LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"auto\"  LF        LF        LF           LF_mix_CR \tCRLF_nul\n-\n-check_in_repo_NNO false \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO true  \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-check_in_repo_NNO input \"text\"  LF        LF        LF           LF_mix_CR \tLF_nul\n-\n-check_in_repo_NNO false \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO true  \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-check_in_repo_NNO input \"-text\" LF        CRLF      CRLF_mix_LF  LF_mix_CR \tCRLF_nul\n-\n-\n+for crlf in true false input\n+do\n+\t#                 attr  aeol           LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLFNUL\n+\tcheck_in_repo_NNO \"\"    \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n # How to read the table below:\n@@ -490,89 +492,47 @@ LFNUL=LF_nul\n fi\n export CRLF_MIX_LF_CR MIX NL\n \n-checkout_files \"\"      \"\" \t \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      \"\" \t \"\"    true   native   CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"\"      ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   \"\"       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   crlf     CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   lf       CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  \"\" \t \"\"    true   native   CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-checkout_files \"auto\"  ident \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\n-for id in \"\" ident;\n+# Same handling with and without ident\n+for id in \"\"\n do\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    false  native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    input  lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"crlf\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"lf\"    \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    false  native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   \"\"       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   lf       CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"text\"  \"$id\" \"\"    true   native   CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    false  native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    input  lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   \"\"       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   crlf     LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files \"-text\" \"$id\" \"\"    true   native   LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tfor ceol in lf crlf native\n+\tdo\n+\t\tfor crlf in true false input\n+\t\tdo\n+\t\t\t# -text overrides core.autocrlf and core.eol\n+\t\t\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n+\t\t\tcheckout_files -text \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files -text \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files -text \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\t# text\n+\t\t\tcheckout_files text  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\t# currently the same as text, eol=XXX\n+\t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tdone\n+\n+\t\t# core.autocrlf false, different core.eol\n+\t\tcheckout_files   \"\"    \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# core.autocrlf true\n+\t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# text: core.autocrlf = true overrides core.eol\n+\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t# text: core.autocrlf = input overrides core.eol\n+\t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t# text=auto + eol=XXX\n+\tdone\n+\t# text: core.autocrlf=false uses core.eol\n+\tcheckout_files     text  \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\tcheckout_files     text  \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n+\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.7.0.992.g0c2c796\n"},{"id":"284931","messageId":"1461942118-16060-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v8 04/10] convert.c: ident + core.autocrlf didn't work","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-29T15:01:58Z","receivedAt":"2016-04-29T15:01:58Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen the ident attributes is set, get_stream_filter() did not obey\ncore.autocrlf=true, and the file was checked out with LF.\n\nChange the rule when a streaming filter can be used:\n- if an external filter is specified, don't use a stream filter.\n- if the worktree eol is CRLF and \"auto\" is active, don't use a stream filter.\n- Otherwise the stream filter can be used.\n\nAdd test cases in t0027.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c            | 19 +++++++------------\n t/t0027-auto-crlf.sh |  2 +-\n 2 files changed, 8 insertions(+), 13 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex f524b8d..b1614bf 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -1380,27 +1380,22 @@ static struct stream_filter *ident_filter(const unsigned char *sha1)\n struct stream_filter *get_stream_filter(const char *path, const unsigned char *sha1)\n {\n \tstruct conv_attrs ca;\n-\tenum crlf_action crlf_action;\n \tstruct stream_filter *filter = NULL;\n \n \tconvert_attrs(&ca, path);\n-\n \tif (ca.drv && (ca.drv->smudge || ca.drv->clean))\n-\t\treturn filter;\n+\t\treturn NULL;\n+\n+\tif (ca.crlf_action == CRLF_AUTO || ca.crlf_action == CRLF_AUTO_CRLF)\n+\t\treturn NULL;\n \n \tif (ca.ident)\n \t\tfilter = ident_filter(sha1);\n \n-\tcrlf_action = ca.crlf_action;\n-\n-\tif ((crlf_action == CRLF_BINARY) ||\n-\t\t\tcrlf_action == CRLF_AUTO_INPUT ||\n-\t\t\t(crlf_action == CRLF_TEXT_INPUT))\n-\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n-\n-\telse if (output_eol(crlf_action) == EOL_CRLF &&\n-\t\t !(crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_CRLF))\n+\tif (output_eol(ca.crlf_action) == EOL_CRLF)\n \t\tfilter = cascade_filter(filter, lf_to_crlf_filter());\n+\telse\n+\t\tfilter = cascade_filter(filter, &null_filter_singleton);\n \n \treturn filter;\n }\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex fd5e326..9372589 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -493,7 +493,7 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-for id in \"\"\n+for id in \"\" ident\n do\n \tfor ceol in lf crlf native\n \tdo\n-- \n2.7.0.992.g0c2c796\n"},{"id":"284936","messageId":"1461942120-16101-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v8 05/10] read-cache: factor out get_sha1_from_index() helper","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-29T15:02:00Z","receivedAt":"2016-04-29T15:02:00Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nFactor out the retrieval of the sha1 for a given path in\nread_blob_data_from_index() into the function get_sha1_from_index().\n\nThis will be used in the next commit, when convert.c can do the\nanalyze for \"text=auto\" without slurping the whole blob into memory\nat once.\n\nAdd a wrapper definition get_sha1_from_cache().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n cache.h      |  3 +++\n read-cache.c | 29 ++++++++++++++++++-----------\n 2 files changed, 21 insertions(+), 11 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex b829410..bd1210a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -379,6 +379,7 @@ extern void free_name_hash(struct index_state *istate);\n #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)\n #define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)\n #define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))\n+#define get_sha1_from_cache(path)  get_sha1_from_index (&the_index, (path))\n #endif\n \n enum object_type {\n@@ -1008,6 +1009,8 @@ static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *\n \treturn read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);\n }\n \n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path);\n+\n /*\n  * This internal function is only declared here for the benefit of\n  * lookup_replace_object().  Please do not call it directly.\ndiff --git a/read-cache.c b/read-cache.c\nindex d9fb78b..a3ef967 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -2263,13 +2263,27 @@ int index_name_is_other(const struct index_state *istate, const char *name,\n \n void *read_blob_data_from_index(struct index_state *istate, const char *path, unsigned long *size)\n {\n-\tint pos, len;\n+\tconst unsigned char *sha1;\n \tunsigned long sz;\n \tenum object_type type;\n \tvoid *data;\n \n-\tlen = strlen(path);\n-\tpos = index_name_pos(istate, path, len);\n+\tsha1 = get_sha1_from_index(istate, path);\n+\tif (!sha1)\n+\t\treturn NULL;\n+\tdata = read_sha1_file(sha1, &type, &sz);\n+\tif (!data || type != OBJ_BLOB) {\n+\t\tfree(data);\n+\t\treturn NULL;\n+\t}\n+\tif (size)\n+\t\t*size = sz;\n+\treturn data;\n+}\n+\n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path)\n+{\n+\tint pos = index_name_pos(istate, path, strlen(path));\n \tif (pos < 0) {\n \t\t/*\n \t\t * We might be in the middle of a merge, in which\n@@ -2285,14 +2299,7 @@ void *read_blob_data_from_index(struct index_state *istate, const char *path, un\n \t}\n \tif (pos < 0)\n \t\treturn NULL;\n-\tdata = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);\n-\tif (!data || type != OBJ_BLOB) {\n-\t\tfree(data);\n-\t\treturn NULL;\n-\t}\n-\tif (size)\n-\t\t*size = sz;\n-\treturn data;\n+\treturn (istate->cache[pos]->sha1);\n }\n \n void stat_validity_clear(struct stat_validity *sv)\n-- \n2.7.0.992.g0c2c796\n"},{"id":"284932","messageId":"1461942121-16140-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v8 06/10] convert.c: stream and early out","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-29T15:02:01Z","receivedAt":"2016-04-29T15:02:01Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen statistics are done for the autocrlf handling, the search in\nthe content can be stopped, if e.g\n- a search for binary is done, and a NUL character is found\n- a search for CRLF is done, and the first CRLF is found.\n\nSimilar when statistics for binary vs non-binary are gathered:\nWhenever a lone CR or NUL is found, the search can be aborted.\n\nWhen checking out files in \"auto\" mode, any file that has a \"lone CR\"\nor a CRLF will not be converted, so the search can be aborted early.\n\nAdd the new bit, CONVERT_STAT_BITS_ANY_CR,\nwhich is set for either lone CR or CRLF.\n\nMany binary files have a NUL very early (within the first few bytes,\nlatest within the first 1..2K).\nIt is often not necessary to load the whole content of a file or blob\ninto memory.\n\nUse a streaming handling for blobs and files in the worktree.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c | 159 ++++++++++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 103 insertions(+), 56 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex b1614bf..24ab095 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -3,6 +3,7 @@\n #include \"run-command.h\"\n #include \"quote.h\"\n #include \"sigchain.h\"\n+#include \"streaming.h\"\n \n /*\n  * convert.c - convert a file when checking it out and checking it in.\n@@ -13,10 +14,10 @@\n  * translation when the \"text\" attribute or \"auto_crlf\" option is set.\n  */\n \n-/* Stat bits: When BIN is set, the txt bits are unset */\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n+#define CONVERT_STAT_BITS_ANY_CR    0x8\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -31,30 +32,36 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned nul, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonecr, lonelf, crlf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n };\n \n-static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)\n+static void do_gather_stats(const char *buf, unsigned long size,\n+\t\t\t    struct text_stat *stats, unsigned earlyout)\n {\n \tunsigned long i;\n \n-\tmemset(stats, 0, sizeof(*stats));\n-\n+\tif (!buf || !size)\n+\t\treturn;\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n \t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n-\t\t\t} else\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\t} else {\n \t\t\t\tstats->lonecr++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+\t\t\t}\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == '\\n') {\n \t\t\tstats->lonelf++;\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_LF;\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == 127)\n@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t\t\tstats->printable++;\n \t\t\t\tbreak;\n \t\t\tcase 0:\n-\t\t\t\tstats->nul++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t\t/* fall through */\n \t\t\tdefault:\n \t\t\t\tstats->nonprintable++;\n@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t}\n \t\telse\n \t\t\tstats->printable++;\n+\t\tif (stats->stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n \t}\n \n \t/* If file ends with EOF then don't count this EOF as non-printable. */\n@@ -86,41 +95,62 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n  * The same heuristics as diff.c::mmfile_is_binary()\n  * We treat files with bare CR as binary\n  */\n-static int convert_is_binary(unsigned long size, const struct text_stat *stats)\n+static void convert_nonprintable(struct text_stat *stats)\n {\n-\tif (stats->lonecr)\n-\t\treturn 1;\n-\tif (stats->nul)\n-\t\treturn 1;\n \tif ((stats->printable >> 7) < stats->nonprintable)\n-\t\treturn 1;\n-\treturn 0;\n+\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+}\n+\n+static void gather_stats(const char *buf, unsigned long size,\n+\t\t\t struct text_stat *stats, unsigned earlyout)\n+{\n+\tmemset(stats, 0, sizeof(*stats));\n+\tdo_gather_stats(buf, size, stats, earlyout);\n+\tconvert_nonprintable(stats);\n }\n \n-static unsigned int gather_convert_stats(const char *data, unsigned long size)\n+\n+static unsigned get_convert_stats_sha1(unsigned const char *sha1,\n+\t\t\t\t       unsigned earlyout)\n {\n+\tstruct git_istream *st;\n \tstruct text_stat stats;\n-\tint ret = 0;\n-\tif (!data || !size)\n-\t\treturn 0;\n-\tgather_stats(data, size, &stats);\n-\tif (convert_is_binary(size, &stats))\n-\t\tret |= CONVERT_STAT_BITS_BIN;\n-\tif (stats.crlf)\n-\t\tret |= CONVERT_STAT_BITS_TXT_CRLF;\n-\tif (stats.lonelf)\n-\t\tret |=  CONVERT_STAT_BITS_TXT_LF;\n+\tenum object_type type;\n+\tunsigned long sz;\n \n-\treturn ret;\n+\tif (!sha1)\n+\t\treturn 0;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tst = open_istream(sha1, &type, &sz, NULL);\n+\tif (!st) {\n+\t\treturn 0;\n+\t}\n+\tif (type != OBJ_BLOB)\n+\t\tgoto close_and_exit_i;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read_istream(st, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+close_and_exit_i:\n+\tclose_istream(st);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n }\n \n-static const char *gather_convert_stats_ascii(const char *data, unsigned long size)\n+static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned int convert_stats = gather_convert_stats(data, size);\n-\n+\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n+\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats) {\n+\tswitch (convert_stats & mask) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -132,24 +162,45 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si\n \t}\n }\n \n+static unsigned get_convert_stats_wt(const char *path)\n+{\n+\tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tint fd;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tfd = open(path, O_RDONLY);\n+\tif (fd < 0)\n+\t\treturn 0;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read(fd, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+\tclose(fd);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n+}\n+\n const char *get_cached_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret;\n-\tunsigned long sz;\n-\tvoid *data = read_blob_data_from_cache(path, &sz);\n-\tret = gather_convert_stats_ascii(data, sz);\n-\tfree(data);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n const char *get_wt_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret = \"\";\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (strbuf_read_file(&sb, path, 0) >= 0)\n-\t\tret = gather_convert_stats_ascii(sb.buf, sb.len);\n-\tstrbuf_release(&sb);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_wt(path);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n static int text_eol_is_crlf(void)\n@@ -219,16 +270,10 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \n static int has_cr_in_index(const char *path)\n {\n-\tunsigned long sz;\n-\tvoid *data;\n-\tint has_cr;\n-\n-\tdata = read_blob_data_from_cache(path, &sz);\n-\tif (!data)\n-\t\treturn 0;\n-\thas_cr = memchr(data, '\\r', sz) != NULL;\n-\tfree(data);\n-\treturn has_cr;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n+\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -249,10 +294,10 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \n \t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n@@ -309,11 +354,13 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n+\n \n \tif (!len || output_eol(crlf_action) != EOL_CRLF)\n \t\treturn 0;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, earlyout);\n \n \t/* No \"naked\" LF? Nothing to convert, regardless. */\n \tif (!stats.lonelf)\n@@ -327,7 +374,7 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\t\t\treturn 0;\n \t\t}\n \n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \t}\n \n-- \n2.7.0.992.g0c2c796\n"},{"id":"284933","messageId":"1461942123-16179-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v8 07/10] convert: unify the \"auto\" handling of CRLF","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-29T15:02:03Z","receivedAt":"2016-04-29T15:02:03Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nBefore this change,\n$ echo \"* text=auto\" >.gitattributes\n$ echo \"* eol=crlf\" >>.gitattributes\n\nwould have the same effect as\n$ echo \"* text\" >.gitattributes\n$ git config core.eol crlf\n\nHaving an \"eol\" attribute is taken as a declaration that the\npath is text.  This may be logical (on a binary blob, you\nwouldn't be defining an \"eol\" attribute in the first place)\nbut is not very useful if you wanted to say \"I do not know\nif the path is text; inspect the contents to see if it is\ntext, and apply this 'eol' conversion only if it is\".\n\n\"text=auto\" attribute combined with an \"eol\" attribute ought\nto have meant that, but it didn't.  Make it so.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt        | 14 ++++++------\n Documentation/gitattributes.txt | 15 +++++++------\n convert.c                       | 47 ++++++++++++++++++++++-------------------\n convert.h                       |  3 ++-\n t/t0025-crlf-auto.sh            |  4 ++--\n t/t0027-auto-crlf.sh            | 32 ++++++++++++++--------------\n t/t6038-merge-text-auto.sh      | 23 +++++++++++++-------\n 7 files changed, 76 insertions(+), 62 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 4a27ad4..9caf6ae 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf`\n mechanism.\n \n core.autocrlf::\n-\tSetting this variable to \"true\" is almost the same as setting\n-\tthe `text` attribute to \"auto\" on all files except that text\n-\tfiles are not guaranteed to be normalized: files that contain\n-\t`CRLF` in the repository will not be touched.  Use this\n-\tsetting if you want to have `CRLF` line endings in your\n-\tworking directory even though the repository does not have\n-\tnormalized line endings.  This variable can be set to 'input',\n+\tSetting this variable to \"true\" is the same as setting\n+\tthe `text` attribute to \"auto\" on all files and core.eol to \"crlf\".\n+\tSet to true if you want to have `CRLF` line endings in your\n+\tworking directory and the repository has LF line endings.\n+\tText files are guaranteed not to be normalized: files that contain\n+\t`CRLF` in the repository will not be touched.\n+\tThis variable can be set to 'input',\n \tin which case no output conversion is performed.\n \n core.symlinks::\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex e3b1de8..d7a124b 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n `core.eol` configuration variable for all text files.\n+Note that `core.autocrlf` overrides `core.eol`\n \n Set::\n \n@@ -130,8 +131,9 @@ Unset::\n Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n-\tend-of-line normalization.  If Git decides that the content is\n-\ttext, its line endings are normalized to LF on checkin.\n+\tend-of-line conversion.  If Git decides that the content is\n+\ttext, its line endings are converted to LF on checkin.\n+\tWhen the file has been commited with CRLF, no conversion is done.\n \n Unspecified::\n \n@@ -146,7 +148,7 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It enables end-of-line normalization without any\n+working directory.  It enables end-of-line conversion without any\n content checks, effectively setting the `text` attribute.\n \n Set to string value \"crlf\"::\n@@ -186,9 +188,10 @@ the working directory, and prevent .jpg files from being normalized\n regardless of their content.\n \n ------------------------\n+*               text=auto\n *.txt\t\ttext\n-*.vcproj\teol=crlf\n-*.sh\t\teol=lf\n+*.vcproj\ttext eol=crlf\n+*.sh\t\ttext eol=lf\n *.jpg\t\t-text\n ------------------------\n \n@@ -198,7 +201,7 @@ normalization in Git.\n \n If you simply want to have CRLF line endings in your working directory\n regardless of the repository you are working with, you can set the\n-config variable \"core.autocrlf\" without changing any attributes.\n+config variable \"core.autocrlf\" without using any attributes.\n \n ------------------------\n [core]\ndiff --git a/convert.c b/convert.c\nindex 24ab095..495c85c 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -225,16 +225,19 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \t\treturn EOL_CRLF;\n \tcase CRLF_TEXT_INPUT:\n \t\treturn EOL_LF;\n-\tcase CRLF_UNDEFINED:\n \tcase CRLF_AUTO_CRLF:\n+\t\treturn EOL_CRLF;\n \tcase CRLF_AUTO_INPUT:\n+\t\treturn EOL_LF;\n \tcase CRLF_TEXT:\n \tcase CRLF_AUTO:\n \t\t/* fall through */\n \t\treturn text_eol_is_crlf() ? EOL_CRLF : EOL_LF;\n+\tdefault: /* the above should cover all valid cases */\n+\t\tbreak;\n \t}\n \twarning(\"Illegal crlf_action %d\\n\", (int)crlf_action);\n-\treturn core_eol;\n+\treturn EOL_UNSET;\n }\n \n static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n@@ -299,17 +302,15 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/*\n-\t\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t\t * This is the new safer autocrlf handling.\n-\t\t\t */\n-\t\t\tif (has_cr_in_index(path))\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/*\n+\t\t * If the file in the index has any CR in it, do not convert.\n+\t\t * This is the new safer autocrlf handling.\n+\t\t */\n+\t\tif (checksafe == SAFE_CRLF_RENORMALIZE)\n+\t\t\tchecksafe = SAFE_CRLF_FALSE;\n+\t\telse if (has_cr_in_index(path))\n+\t\t\treturn 0;\n \t}\n-\n \tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n \n \t/* Optimization: No CRLF? Nothing to convert, regardless. */\n@@ -367,12 +368,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\treturn 0;\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t\t/* This is the new safer autocrlf-handling */\n-\t\t\tif (stats.lonecr || stats.crlf )\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n+\t\t/* This is the new safer autocrlf-handling */\n+\t\tif (stats.lonecr || stats.crlf )\n+\t\t\treturn 0;\n \n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n@@ -833,7 +832,11 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tca->drv = git_path_check_convert(ccheck + 2);\n \t\tif (ca->crlf_action != CRLF_BINARY) {\n \t\t\tenum eol eol_attr = git_path_check_eol(ccheck + 3);\n-\t\t\tif (eol_attr == EOL_LF)\n+\t\t\tif (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_INPUT;\n+\t\t\telse if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_CRLF;\n+\t\t\telse if (eol_attr == EOL_LF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_INPUT;\n \t\t\telse if (eol_attr == EOL_CRLF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_CRLF;\n@@ -892,9 +895,9 @@ const char *get_convert_attr_ascii(const char *path)\n \tcase CRLF_AUTO:\n \t\treturn \"text=auto\";\n \tcase CRLF_AUTO_CRLF:\n-\t\treturn \"text=auto eol=crlf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=crlf\";\n \tcase CRLF_AUTO_INPUT:\n-\t\treturn \"text=auto eol=lf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=lf\";\n \t}\n \treturn \"\";\n }\n@@ -996,7 +999,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_FALSE);\n+\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n }\n \n /*****************************************************************\ndiff --git a/convert.h b/convert.h\nindex ccf436b..82871a1 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -7,7 +7,8 @@\n enum safe_crlf {\n \tSAFE_CRLF_FALSE = 0,\n \tSAFE_CRLF_FAIL = 1,\n-\tSAFE_CRLF_WARN = 2\n+\tSAFE_CRLF_WARN = 2,\n+\tSAFE_CRLF_RENORMALIZE = 3\n };\n \n extern enum safe_crlf safe_crlf;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex c164b46..d0bee08 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -114,7 +114,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n+test_expect_success 'text=auto, autocrlf=true does not normalize CRLF files' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \tgit config core.autocrlf true &&\n@@ -126,7 +126,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n \tLFonlydiff=$(git diff LFonly) &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n \tLFwithNULdiff=$(git diff LFwithNUL) &&\n-\ttest -z \"$LFonlydiff\" -a -n \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n+\ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 9372589..8367d0b 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -175,8 +175,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text eol=lf\" ;;\n-\tauto,crlf) echo \"text eol=crlf\" ;;\n+\tauto,lf)   echo \"text=auto eol=lf\" ;;\n+\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -397,10 +397,9 @@ commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n-\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n@@ -408,8 +407,8 @@ do\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n \tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n \tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n done\n@@ -454,9 +453,9 @@ do\n \tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n@@ -493,7 +492,8 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-for id in \"\" ident\n+#for id in \"\" ident\n+for id in \"\"\n do\n \tfor ceol in lf crlf native\n \tdo\n@@ -509,7 +509,7 @@ do\n \t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n \t\t\t# currently the same as text, eol=XXX\n \t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \n \t\t# core.autocrlf false, different core.eol\n@@ -517,7 +517,7 @@ do\n \t\t# core.autocrlf true\n \t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n \t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n@@ -531,8 +531,8 @@ do\n \tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 85c10b0..33b77ee 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -16,6 +16,13 @@ test_description='CRLF merge conflict across text=auto change\n \n test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b\n \n+compare_files () {\n+\ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n+\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n+\ttest_cmp \"$1\".expect \"$2\".actual &&\n+\trm \"$1\".expect \"$2\".actual\n+}\n+\n test_expect_success setup '\n \tgit config core.autocrlf false &&\n \n@@ -30,7 +37,7 @@ test_expect_success setup '\n \tgit branch side &&\n \n \techo \"* text=auto\" >.gitattributes &&\n-\ttouch file &&\n+\techo first line >file &&\n \tgit add .gitattributes file &&\n \ttest_tick &&\n \tgit commit -m \"normalize file\" &&\n@@ -81,7 +88,7 @@ test_expect_success 'Merge after setting text=auto' '\n \trm -f .gitattributes &&\n \tgit reset --hard a &&\n \tgit merge b &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_success 'Merge addition of text=auto' '\n@@ -99,7 +106,7 @@ test_expect_success 'Merge addition of text=auto' '\n \trm -f .gitattributes &&\n \tgit reset --hard b &&\n \tgit merge a &&\n-\ttest_cmp expected file\n+\tcompare_files  expected file\n '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n@@ -121,7 +128,7 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \tgit reset --hard a &&\n \ttest_must_fail git merge b &&\n \tfuzz_conflict file >file.fuzzy &&\n-\ttest_cmp expected file.fuzzy\n+\tcompare_files expected file.fuzzy\n '\n \n test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n@@ -143,7 +150,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \tgit reset --hard b &&\n \ttest_must_fail git merge a &&\n \tfuzz_conflict file >file.fuzzy &&\n-\ttest_cmp expected file.fuzzy\n+\tcompare_files expected file.fuzzy\n '\n \n test_expect_failure 'checkout -m after setting text=auto' '\n@@ -158,7 +165,7 @@ test_expect_failure 'checkout -m after setting text=auto' '\n \tgit reset --hard initial &&\n \tgit checkout a -- . &&\n \tgit checkout -m b &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_failure 'checkout -m addition of text=auto' '\n@@ -173,7 +180,7 @@ test_expect_failure 'checkout -m addition of text=auto' '\n \tgit reset --hard initial &&\n \tgit checkout b -- . &&\n \tgit checkout -m a &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_failure 'cherry-pick patch from after text=auto was added' '\n@@ -187,7 +194,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' '\n \tgit reset --hard b &&\n \ttest_must_fail git cherry-pick a >err 2>&1 &&\n \tgrep \"[Nn]othing added\" err &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_success 'Test delete/normalize conflict' '\n-- \n2.7.0.992.g0c2c796\n"},{"id":"284939","messageId":"1461942124-16218-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v8 08/10] convert.c: more safer crlf handling with text attribute","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-29T15:02:04Z","receivedAt":"2016-04-29T15:02:04Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nThis patch extends the work done in commit c480539:\n\"Make it work also for un-normalized repositories\". Make sure that CRLF\ncan be converted round trip, or don't convert them at all.\n\nThe old handling would treat a file as unchanged after checkout,\nas long as it is not touched in the work tree and mtime matches the value\nrecorded in the index.\nWhen the mtime is changed in the working tree, or the inode is changed,\nthe file is reported as modified.\n\nThe following sequence is now handled reproducable:\n$ git init\n$ printf \"line1\\r\\n\" >file.bat\n$ git add file.bat\n$ git commit -m \"Add file with CRLF\" file.bat\n$ echo \"*.bat text eol=crlf\" >.gitattributes\n$ git commit -m \"bat files should have CRLF\"\n$ git status\n # nothing to commit, working directory clean\n$ git push <upstream>\n$ printf \"newline\\r\\n\" >>file.bat\n$ mv file.bat file.sav\n$ git checkout file.bat\n$ git status\n #modified:   file.bat\n\nThe new handling makes sure that after running \"git reset --hard\".\n\"git status\" reports the working tree as clean regarding CRLF conversion.\nIt makes sure that the Git-internal eol conversion is\ndoing roundtrip. A user can still write an external smudge/clean filter\noutside Git, which doesn't do a roundtrip and the working directory is\nnot clean.\n\nThe functionality of has_cr_in_index() is turned into has_crlf_in_index(),\nand the function is integrated into would_convert_crlf_at_commit().\n\nCheck for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR\nis no longer used and removed, as well as \"lonecr\" in struct text_stat.\n\nRewrite check_safe_crlf() in convert.c to simulate checkin-checkout,\nto detect whether any line endings are converted.\n\nAdd a warning, similar to the CRLF-LF replacement, when a file is commited,\nand after the next checkout the line endings are not what they should be.\n\nModify the lf_to_crlf_filter:\nFiles with LF are converted into CRLF, file with CRLF are not changed.\nFiles with mixed line endings are not converted, the filter fails, and Git\nfalls back to the non-streaming handling, see write_entry().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/gitattributes.txt |  19 ++--\n convert.c                       | 235 +++++++++++++++++++++++++---------------\n t/t0025-crlf-auto.sh            |   8 +-\n t/t0027-auto-crlf.sh            |  92 ++++++++--------\n 4 files changed, 213 insertions(+), 141 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex d7a124b..836461d 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'.\n `text`\n ^^^^^^\n \n-This attribute enables and controls end-of-line normalization.  When a\n+This attribute enables and controls end-of-line conversion.  When a\n text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol`\n Set::\n \n \tSetting the `text` attribute on a path enables end-of-line\n-\tnormalization and marks the path as a text file.  End-of-line\n+\tconversion and marks the path as a text file.  End-of-line\n \tconversion takes place without guessing the content type.\n+\tFiles that have been commited with CRLF before the text attribute\n+\tis set and commited are not normalized. No end-of-line conversion\n+\tis done at checkout or checkin.\n \n Unset::\n \n@@ -131,9 +134,9 @@ Unset::\n Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n-\tend-of-line conversion.  If Git decides that the content is\n-\ttext, its line endings are converted to LF on checkin.\n-\tWhen the file has been commited with CRLF, no conversion is done.\n+\tend-of-line normalization.  If Git decides that the content is\n+\ttext, and the path has no CRLF in the index,\n+\tits line endings are converted to LF on checkin.\n \n Unspecified::\n \n@@ -148,8 +151,10 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It enables end-of-line conversion without any\n-content checks, effectively setting the `text` attribute.\n+working directory.  It sets the `text` attribute, unless `text=auto`\n+is specified.\n+When the file had been commited with CRLF in the index, no conversion\n+is done at checkout or commit.\n \n Set to string value \"crlf\"::\n \ndiff --git a/convert.c b/convert.c\nindex 495c85c..790563d 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -17,7 +17,8 @@\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n-#define CONVERT_STAT_BITS_ANY_CR    0x8\n+\n+#define CONVERT_STAT_BITS_MIXED (CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF)\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -32,7 +33,7 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned stat_bits, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonelf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n@@ -48,13 +49,10 @@ static void do_gather_stats(const char *buf, unsigned long size,\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n-\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n-\t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n \t\t\t} else {\n-\t\t\t\tstats->lonecr++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t}\n \t\t\tcontinue;\n@@ -135,7 +133,7 @@ static unsigned get_convert_stats_sha1(unsigned const char *sha1,\n \t\tif (!readlen)\n \t\t\tbreak;\n \t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n-\t\tif (stats.stat_bits & earlyout)\n+\t\tif ((stats.stat_bits & earlyout) == earlyout)\n \t\t\tbreak; /* We found what we have been searching for */\n \t}\n close_and_exit_i:\n@@ -146,11 +144,9 @@ close_and_exit_i:\n \n static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n-\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats & mask) {\n+\tswitch (convert_stats) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -162,7 +158,16 @@ static const char *convert_stats_ascii(unsigned convert_stats)\n \t}\n }\n \n-static unsigned get_convert_stats_wt(const char *path)\n+const char *get_cached_convert_stats_ascii(const char *path)\n+{\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n+}\n+\n+const char *get_wt_convert_stats_ascii(const char *path)\n {\n \tstruct text_stat stats;\n \tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n@@ -170,7 +175,7 @@ static unsigned get_convert_stats_wt(const char *path)\n \tmemset(&stats, 0, sizeof(stats));\n \tfd = open(path, O_RDONLY);\n \tif (fd < 0)\n-\t\treturn 0;\n+\t\treturn NULL;\n \tfor (;;) {\n \t\tchar buf[1024];\n \t\tssize_t readlen = read(fd, buf, sizeof(buf));\n@@ -184,23 +189,7 @@ static unsigned get_convert_stats_wt(const char *path)\n \t}\n \tclose(fd);\n \tconvert_nonprintable(&stats);\n-\treturn stats.stat_bits;\n-}\n-\n-const char *get_cached_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n-\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n-\t\t\t\t\t       earlyout);\n-\treturn convert_stats_ascii(convert_stats);\n-}\n-\n-const char *get_wt_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_wt(path);\n-\treturn convert_stats_ascii(convert_stats);\n+\treturn convert_stats_ascii(stats.stat_bits);\n }\n \n static int text_eol_is_crlf(void)\n@@ -240,43 +229,95 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \treturn EOL_UNSET;\n }\n \n+static int would_convert_lf_at_checkout(unsigned convert_stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tif (output_eol(crlf_action) != EOL_CRLF)\n+\t\treturn 0;\n+\n+\t/* No \"naked\" LF? Nothing to convert, regardless. */\n+\tif (!(convert_stats & CONVERT_STAT_BITS_TXT_LF))\n+\t\treturn 0;\n+\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\t/* auto: binary files are not converted */\n+\t\tif (convert_stats & CONVERT_STAT_BITS_BIN)\n+\t\t\treturn 0;\n+\t}\n+\t/* If we have any CRLF line endings, we do not touch it */\n+\t/* This is the new safer autocrlf-handling */\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+\n+}\n+\n+static int would_convert_crlf_at_commit(const char * path,\n+\t\t\t\t\tconst struct text_stat *stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tunsigned stat_bits_index;\n+\t/* No CRLF? Nothing to convert, regardless. */\n+\tif (!(stats->stat_bits & CONVERT_STAT_BITS_TXT_CRLF))\n+\t\treturn 0;\n+\t/*\n+\t * If the file in the index has any CRLF in it, do not convert.\n+\t * This is the new safer autocrlf handling.\n+\t */\n+\tstat_bits_index = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t\t CONVERT_STAT_BITS_TXT_CRLF);\n+\tif (stat_bits_index & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+}\n+\n static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n-                            struct text_stat *stats, enum safe_crlf checksafe)\n+\t\t\t    enum safe_crlf checksafe,\n+\t\t\t    unsigned convert_stats, unsigned new_convert_stats)\n {\n+\tenum eol new_eol = output_eol(crlf_action);\n+\tconst char *err_warn_msg = NULL;\n \tif (!checksafe)\n \t\treturn;\n-\n-\tif (output_eol(crlf_action) == EOL_LF) {\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n \t\t/*\n \t\t * CRLFs would not be restored by checkout:\n \t\t * check if we'd remove CRLFs\n \t\t */\n-\t\tif (stats->crlf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n-\t\t}\n-\t} else if (output_eol(crlf_action) == EOL_CRLF) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n+\t}\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_LF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_LF)) {\n \t\t/*\n \t\t * CRLFs would be added by checkout:\n \t\t * check if we have \"naked\" LFs\n \t\t */\n-\t\tif (stats->lonelf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n-\t\t}\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n+\t}\n+\tif ((new_convert_stats & CONVERT_STAT_BITS_MIXED) == CONVERT_STAT_BITS_MIXED)\n+\t\terr_warn_msg = \"mixed eol\";\n+\telse if (new_eol == EOL_LF && new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\terr_warn_msg = \"CRLF\";\n+\n+\tif (err_warn_msg) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"%s will be present after commit and checkout in %s.\",\n+\t\t\t\terr_warn_msg, path);\n+\t\telse\n+\t\t\tdie(\"%s will be present after commit and checkout in %s\",\n+\t\t\t    err_warn_msg, path);\n \t}\n-}\n-\n-static int has_cr_in_index(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n-\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n-\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -285,7 +326,7 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n {\n \tstruct text_stat stats;\n \tchar *dst;\n-\n+\tint convert_crlf;\n \tif (crlf_action == CRLF_BINARY ||\n \t    (src && !len))\n \t\treturn 0;\n@@ -297,24 +338,42 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n-\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\t\t/*\n-\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t * This is the new safer autocrlf handling.\n-\t\t */\n-\t\tif (checksafe == SAFE_CRLF_RENORMALIZE)\n-\t\t\tchecksafe = SAFE_CRLF_FALSE;\n-\t\telse if (has_cr_in_index(path))\n-\t\t\treturn 0;\n+\t} else {\n+\t\tgather_stats(src, len, &stats, 0);\n+\t}\n+\tif (checksafe == SAFE_CRLF_RENORMALIZE) {\n+\t\tconvert_crlf = 1;\n+\t\tchecksafe = SAFE_CRLF_FALSE;\n+\t} else {\n+\t\tconvert_crlf = would_convert_crlf_at_commit(path, &stats, len,\n+\t\t\t\t\t\t\t    crlf_action);\n \t}\n-\tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n \n-\t/* Optimization: No CRLF? Nothing to convert, regardless. */\n-\tif (!stats.crlf)\n+\tif (checksafe) {\n+\t\tunsigned convert_stats = stats.stat_bits;\n+\t\tunsigned new_convert_stats = convert_stats;\n+\t\t/* Simulate commit */\n+\t\tif (convert_crlf &&\n+\t\t    (new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_LF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t}\n+\t\t/* Simulate checkout */\n+\t\tif (would_convert_lf_at_checkout(new_convert_stats,\n+\t\t\t\t\t\t len, crlf_action)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_LF;\n+\t\t}\n+\t\tcheck_safe_crlf(path, crlf_action, checksafe,\n+\t\t\t\tconvert_stats, new_convert_stats);\n+\t}\n+\tif (!convert_crlf)\n \t\treturn 0;\n \n \t/*\n@@ -328,7 +387,9 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (strbuf_avail(buf) + buf->len < len)\n \t\tstrbuf_grow(buf, len - buf->len);\n \tdst = buf->buf;\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n \t\t/*\n \t\t * If we guessed, we already know we rejected a file with\n \t\t * lone CR, and we can strip a CR without looking at what\n@@ -355,28 +416,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n-\n-\n-\tif (!len || output_eol(crlf_action) != EOL_CRLF)\n+\tunsigned earlyout = 0; /* Need to count lonelf */\n+\tif (!len)\n \t\treturn 0;\n \n \tgather_stats(src, len, &stats, earlyout);\n-\n-\t/* No \"naked\" LF? Nothing to convert, regardless. */\n-\tif (!stats.lonelf)\n+\tif (!would_convert_lf_at_checkout(stats.stat_bits,\n+\t\t\t\t\t  len, crlf_action))\n \t\treturn 0;\n \n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t/* This is the new safer autocrlf-handling */\n-\t\tif (stats.lonecr || stats.crlf )\n-\t\t\treturn 0;\n-\n-\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n-\t\t\treturn 0;\n-\t}\n-\n \t/* are we \"faking\" in place editing ? */\n \tif (src == buf->buf)\n \t\tto_free = strbuf_detach(buf, NULL);\n@@ -1068,6 +1116,8 @@ int is_null_stream_filter(struct stream_filter *filter)\n struct lf_to_crlf_filter {\n \tstruct stream_filter filter;\n \tunsigned has_held:1;\n+\tunsigned expanded_loneLF:1;\n+\tunsigned had_CRLF:1;\n \tchar held;\n };\n \n@@ -1108,7 +1158,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \t\t\tchar ch = input[i];\n \n \t\t\tif (ch == '\\n') {\n-\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\tif (!lf_to_crlf->had_CRLF) {\n+\t\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\t\tlf_to_crlf->expanded_loneLF = 1;\n+\t\t\t\t}\n+\t\t\t\tif (was_cr)\n+\t\t\t\t\tlf_to_crlf->had_CRLF = 1;\n \t\t\t} else if (was_cr) {\n \t\t\t\t/*\n \t\t\t\t * Previous round saw CR and it is not followed\n@@ -1137,6 +1192,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \n \t\t\twas_cr = 0;\n \t\t\toutput[o++] = ch;\n+\t\t\tif (lf_to_crlf->expanded_loneLF &&\n+\t\t\t    lf_to_crlf->had_CRLF) {\n+\t\t\t\t/*\n+\t\t\t\t * Mixed EOL, round trip not possible.\n+\t\t\t\t */\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n \t\t}\n \n \t\t*osize_p -= o;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex d0bee08..b5f93e2 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n+test_expect_success 'crlf=true causes a CRLF file not to be normalized' '\n \n \t# Backwards compatibility check\n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n-test_expect_success 'text=true causes a CRLF file to be normalized' '\n+test_expect_success 'text=true causes a CRLF file not to be normalized' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \techo \"CRLFonly text\" > .gitattributes &&\n@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 8367d0b..a16e513 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -71,10 +71,14 @@ check_warning () {\n \tcase \"$1\" in\n \tLF_CRLF) echo \"warning: LF will be replaced by CRLF\" >\"$2\".expect ;;\n \tCRLF_LF) echo \"warning: CRLF will be replaced by LF\" >\"$2\".expect ;;\n+\tCRLF)    echo \"warning: CRLF will be present after commit and checkout\" >\"$2\".expect ;;\n+\tmixed)   echo \"warning: mixed eol will be present after commit and checkout\" >\"$2\".expect ;;\n \t'')\t                                                 >\"$2\".expect ;;\n \t*) echo >&2 \"Illegal 1\": \"$1\" ; return false ;;\n \tesac\n-\tgrep \"will be replaced by\" \"$2\" | sed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" | uniq  >\"$2\".actual\n+\tegrep \"will be replaced by|will be present after commit\" \"$2\" |\n+\t\tsed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" |\n+\t\tuniq  >\"$2\".actual\n \ttest_cmp \"$2\".expect \"$2\".actual\n }\n \n@@ -169,7 +173,7 @@ stats_ascii () {\n # Take none (=empty), one or two args\n # convert.c: eol=XX overrides text=auto\n attr_ascii () {\n-\tcase $1,$2 in\n+\tcase \"$1\",\"$2\" in\n \t-text,*)   echo \"-text\" ;;\n \ttext,)     echo \"text\" ;;\n \ttext,lf)   echo \"text eol=lf\" ;;\n@@ -349,10 +353,12 @@ then\n \tWILC=LF_CRLF\n \tWICL=\n \tWAMIX=LF_CRLF\n+\tPcrlf=\n else\n \tWILC=\n \tWICL=CRLF_LF\n \tWAMIX=CRLF_LF\n+\tPcrlf=CRLF\n fi\n \n #                         attr   LF        CRLF      CRLFmixLF LFmixCR   CRLFNUL\n@@ -392,31 +398,32 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+#                 attr    aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n+\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$Pcrlf\"  mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$Pcrlf\"  mixed       \"$WILC\"     \"$Pcrlf\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF      mixed       \"\"          CRLF\n+\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n-\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf      $crlf   \"\"        CRLF      mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf    $crlf   LF_CRLF   \"\"        mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO text  lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO text  crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n done\n \n-commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n-commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n-\n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n \tgit -c core.autocrlf=false reset --hard\n@@ -456,9 +463,9 @@ do\n \tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n@@ -479,12 +486,10 @@ done\n \n if test_have_prereq NATIVE_CRLF\n then\n-MIX_CRLF_LF=CRLF\n MIX_LF_CR=CRLF_mix_CR\n NL=CRLF\n LFNUL=CRLF_nul\n else\n-MIX_CRLF_LF=CRLF_mix_LF\n MIX_LF_CR=LF_mix_CR\n NL=LF\n LFNUL=LF_nul\n@@ -492,8 +497,7 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-#for id in \"\" ident\n-for id in \"\"\n+for id in \"\" ident\n do\n \tfor ceol in lf crlf native\n \tdo\n@@ -501,38 +505,38 @@ do\n \t\tdo\n \t\t\t# -text overrides core.autocrlf and core.eol\n \t\t\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n-\t\t\tcheckout_files -text \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files -text \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files -text \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\t# text\n-\t\t\tcheckout_files text  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files text    \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files text    \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t\t# currently the same as text, eol=XXX\n-\t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto    \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto    \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \n \t\t# core.autocrlf false, different core.eol\n-\t\tcheckout_files   \"\"    \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   \"\"      \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# core.autocrlf true\n-\t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   \"\"      \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tcheckout_files   auto    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   text    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n-\t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files   auto  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   text    \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto    \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text=auto + eol=XXX\n \tdone\n \t# text: core.autocrlf=false uses core.eol\n-\tcheckout_files     text  \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files     text  \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     text    \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n+\tcheckout_files     text    \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files     text    \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  \"$MIX_LF_CR\" \"$LFNUL\"\n+\tcheckout_files     text    \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  \"$MIX_LF_CR\" \"$LFNUL\"\n \t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto    \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto    \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.7.0.992.g0c2c796\n"},{"id":"284938","messageId":"1461942125-16257-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v8 09/10] t6038; use crlf on all platforms","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-29T15:02:05Z","receivedAt":"2016-04-29T15:02:05Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nt6038 uses different code, dependig if NATIVE_CRLF is set ot not. When\nthe native line endings are LF, merge.renormalize is not tested very well.\nChange the test to always use CRLF by setting core.eol=crlf.\nAfter doing so, the test fails:\n\nrm '.gitattributes'\nrm 'control_file'\nrm 'file'\nrm 'inert_file'\nHEAD is now at 0d9ffb6 add line from b\nerror: addinfo_cache failed for path 'file'\nfile: unmerged (cbd69ec7cd12dd0989e853923867d94c8519aa52)\nfile: unmerged (ad55e240aeb42e0d9a0e18d6d8b02dd82ee3e527)\nfile: unmerged (99b633103c15c20cebebf821133ab526b0ff90b2)\nfatal: git write-tree failed to write a tree\nMerging:\n0d9ffb6 add line from b\nvirtual a\nfound 1 common ancestor:\n1c56df1 Initial\nAuto-merging file\nnot ok 4 - Merge addition of text=auto\n\nThis will be addressed in the next commit.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n t/t6038-merge-text-auto.sh | 37 +++++++++++--------------------------\n 1 file changed, 11 insertions(+), 26 deletions(-)\n\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 33b77ee..0108ead 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -25,6 +25,7 @@ compare_files () {\n \n test_expect_success setup '\n \tgit config core.autocrlf false &&\n+\tgit config core.eol crlf &&\n \n \techo first line | append_cr >file &&\n \techo first line >control_file &&\n@@ -79,10 +80,8 @@ test_expect_success 'Merge after setting text=auto' '\n \tsame line\n \tEOF\n \n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\tappend_cr <expected >expected.temp &&\n-\t\tmv expected.temp expected\n-\tfi &&\n+\tappend_cr <expected >expected.temp &&\n+\tmv expected.temp expected &&\n \tgit config merge.renormalize true &&\n \tgit rm -fr . &&\n \trm -f .gitattributes &&\n@@ -97,10 +96,8 @@ test_expect_success 'Merge addition of text=auto' '\n \tsame line\n \tEOF\n \n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\tappend_cr <expected >expected.temp &&\n-\t\tmv expected.temp expected\n-\tfi &&\n+\tappend_cr <expected >expected.temp &&\n+\tmv expected.temp expected &&\n \tgit config merge.renormalize true &&\n \tgit rm -fr . &&\n \trm -f .gitattributes &&\n@@ -111,15 +108,9 @@ test_expect_success 'Merge addition of text=auto' '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \techo \"<<<<<<<\" >expected &&\n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\techo first line | append_cr >>expected &&\n-\t\techo same line | append_cr >>expected &&\n-\t\techo ======= | append_cr >>expected\n-\telse\n-\t\techo first line >>expected &&\n-\t\techo same line >>expected &&\n-\t\techo ======= >>expected\n-\tfi &&\n+\techo first line | append_cr >>expected &&\n+\techo same line | append_cr >>expected &&\n+\techo ======= | append_cr >>expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n@@ -135,15 +126,9 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \techo \"<<<<<<<\" >expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\techo ======= | append_cr >>expected &&\n-\t\techo first line | append_cr >>expected &&\n-\t\techo same line | append_cr >>expected\n-\telse\n-\t\techo ======= >>expected &&\n-\t\techo first line >>expected &&\n-\t\techo same line >>expected\n-\tfi &&\n+\techo ======= | append_cr >>expected &&\n+\techo first line | append_cr >>expected &&\n+\techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n \tgit config merge.renormalize false &&\n \trm -f .gitattributes &&\n-- \n2.7.0.992.g0c2c796\n"},{"id":"284937","messageId":"1461942126-16296-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-04-29T15:02:06Z","receivedAt":"2016-04-29T15:02:06Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWe define the working tree file is clean if either:\n\n  * the result of running convert_to_git() on the working tree\n    contents matches what is in the index (because that would mean\n    doing another \"git add\" on the path is a no-op); OR\n\n  * the result of running convert_to_working_tree() on the content\n    in the index matches what is in the working tree (because that\n    would mean doing another \"git checkout -f\" on the path is a\n    no-op).\n\nAdd an extra check in ce_compare_data() in read_cache.c.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n read-cache.c               | 61 ++++++++++++++++++++++++++++++++++++++++++++++\n t/t6038-merge-text-auto.sh | 14 +++++------\n 2 files changed, 68 insertions(+), 7 deletions(-)\n\ndiff --git a/read-cache.c b/read-cache.c\nindex a3ef967..48c4b31 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -156,17 +156,78 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)\n \t\tce_mark_uptodate(ce);\n }\n \n+/*\n+ * Compare the data in buf with the data in the file pointed by fd and\n+ * return 0 if they are identical, and non-zero if they differ.\n+ */\n+static int compare_with_fd(const char *input, ssize_t len, int fd)\n+{\n+\tfor (;;) {\n+\t\tchar buf[1024 * 16];\n+\t\tssize_t chunk_len, read_len;\n+\n+\t\tchunk_len = sizeof(buf) < len ? sizeof(buf) : len;\n+\t\tread_len = xread(fd, buf, chunk_len ? chunk_len : 1);\n+\n+\t\tif (!read_len)\n+\t\t\t/* EOF on the working tree file */\n+\t\t\treturn !len ? 0 : -1;\n+\n+\t\tif (!len)\n+\t\t\t/* we expected there is nothing left */\n+\t\t\treturn -1;\n+\n+\t\tif (memcmp(buf, input, read_len))\n+\t\t\treturn -1;\n+\t\tinput += read_len;\n+\t\tlen -= read_len;\n+\t}\n+}\n+\n static int ce_compare_data(const struct cache_entry *ce, struct stat *st)\n {\n \tint match = -1;\n \tint fd = open(ce->name, O_RDONLY);\n \n+\t/*\n+\t * Would another \"git add\" on the path change what is in the\n+\t * index for the path?\n+\t */\n \tif (fd >= 0) {\n \t\tunsigned char sha1[20];\n \t\tif (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, 0))\n \t\t\tmatch = hashcmp(sha1, ce->sha1);\n \t\t/* index_fd() closed the file descriptor already */\n \t}\n+\tif (!match)\n+\t\treturn match;\n+\n+\t/*\n+\t * Would another \"git checkout -f\" out of the index change\n+\t * what is in the working tree file?\n+\t */\n+\tfd = open(ce->name, O_RDONLY);\n+\tif (fd >= 0) {\n+\t\tenum object_type type;\n+\t\tunsigned long size_long;\n+\t\tvoid *data = read_sha1_file(ce->sha1, &type, &size_long);\n+\n+\t\tif (type == OBJ_BLOB) {\n+\t\t\tstruct strbuf worktree = STRBUF_INIT;\n+\t\t\tif (convert_to_working_tree(ce->name, data,\n+\t\t\t\t\t\t    size_long,\n+\t\t\t\t\t\t    &worktree)) {\n+\t\t\t\tsize_t size;\n+\t\t\t\tfree(data);\n+\t\t\t\tdata = strbuf_detach(&worktree, &size);\n+\t\t\t\tsize_long = size;\n+\t\t\t}\n+\t\t\tif (!compare_with_fd(data, size_long, fd))\n+\t\t\t\tmatch = 0;\n+\t\t}\n+\t\tfree(data);\n+\t\tclose(fd);\n+\t}\n \treturn match;\n }\n \ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 0108ead..565daf3 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -108,9 +108,9 @@ test_expect_success 'Merge addition of text=auto' '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \techo \"<<<<<<<\" >expected &&\n-\techo first line | append_cr >>expected &&\n-\techo same line | append_cr >>expected &&\n-\techo ======= | append_cr >>expected &&\n+\techo first line >>expected &&\n+\techo same line >>expected &&\n+\techo ======= >>expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n@@ -121,14 +121,13 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \tfuzz_conflict file >file.fuzzy &&\n \tcompare_files expected file.fuzzy\n '\n-\n test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \techo \"<<<<<<<\" >expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n-\techo ======= | append_cr >>expected &&\n-\techo first line | append_cr >>expected &&\n-\techo same line | append_cr >>expected &&\n+\techo =======  >>expected &&\n+\techo first line >>expected &&\n+\techo same line  >>expected &&\n \techo \">>>>>>>\" >>expected &&\n \tgit config merge.renormalize false &&\n \trm -f .gitattributes &&\n@@ -138,6 +137,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \tcompare_files expected file.fuzzy\n '\n \n+\n test_expect_failure 'checkout -m after setting text=auto' '\n \tcat <<-\\EOF >expected &&\n \tfirst line\n-- \n2.7.0.992.g0c2c796\n"},{"id":"284961","messageId":"xmqq37q4z38b.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1461942126-16296-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-29T18:20:20Z","receivedAt":"2016-04-29T18:20:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> We define the working tree file is clean if either:\n>\n>   * the result of running convert_to_git() on the working tree\n>     contents matches what is in the index (because that would mean\n>     doing another \"git add\" on the path is a no-op); OR\n>\n>   * the result of running convert_to_working_tree() on the content\n>     in the index matches what is in the working tree (because that\n>     would mean doing another \"git checkout -f\" on the path is a\n>     no-op).\n>\n> Add an extra check in ce_compare_data() in read_cache.c.\n>\n> Helped-by: Junio C Hamano <gitster@pobox.com>\n> Signed-off-by: Torsten Bögershausen <tboegi@web.de>\n> ---\n\nThanks, will re-queue.\n"},{"id":"284979","messageId":"xmqqvb30w29z.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1461942126-16296-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-29T21:09:12Z","receivedAt":"2016-04-29T21:09:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> We define the working tree file is clean if either:\n>\n>   * the result of running convert_to_git() on the working tree\n>     contents matches what is in the index (because that would mean\n>     doing another \"git add\" on the path is a no-op); OR\n>\n>   * the result of running convert_to_working_tree() on the content\n>     in the index matches what is in the working tree (because that\n>     would mean doing another \"git checkout -f\" on the path is a\n>     no-op).\n>\n> Add an extra check in ce_compare_data() in read_cache.c.\n>\n> Helped-by: Junio C Hamano <gitster@pobox.com>\n\nWell, didn't I do exactly the above much earlier and discarded it\nbecause that breaks the definition of \"diff\"?  Or is this doing\nsomething differently?\n"},{"id":"285117","messageId":"a571e222-68db-3dc1-1a94-d6b47feaf84d@web.de","threadId":"41391","inReplyTo":"xmqqvb30w29z.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-05-01T16:27:05Z","receivedAt":"2016-05-01T16:27:05Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 29.04.16 23:09, Junio C Hamano wrote:\n\n> Well, didn't I do exactly the above much earlier and discarded it\n> because that breaks the definition of \"diff\"?  Or is this doing\n> something differently?\n\nYes, and I try to sneak it in anyway ;-)\n\nI spend some time debugging how to get t6038 passed, and need\nsome more time.\n\nIf 10/10 is a no-go (and it probably should be),\ndoes it make sense to keep 1/10..4/10 and discard 5..10 for the moment ?\n"},{"id":"285182","messageId":"xmqqtwigtjfg.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"a571e222-68db-3dc1-1a94-d6b47feaf84d@web.de","subject":"Re: [PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-02T18:16:03Z","receivedAt":"2016-05-02T18:16:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n> On 29.04.16 23:09, Junio C Hamano wrote:\n>\n>> Well, didn't I do exactly the above much earlier and discarded it\n>> because that breaks the definition of \"diff\"?  Or is this doing\n>> something differently?\n>\n> Yes, and I try to sneak it in anyway ;-)\n>\n> I spend some time debugging how to get t6038 passed, and need\n> some more time.\n>\n> If 10/10 is a no-go (and it probably should be),\n> does it make sense to keep 1/10..4/10 and discard 5..10 for the moment ?\n\nEarlier patches in the series certainly felt alright.  I do not\nremember noticing where it went in a strange direction to be honest.\n"},{"id":"285197","messageId":"xmqqpot4s1ap.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"xmqqtwigtjfg.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-02T19:33:02Z","receivedAt":"2016-05-02T19:33:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Torsten Bögershausen <tboegi@web.de> writes:\n>\n>> On 29.04.16 23:09, Junio C Hamano wrote:\n>>\n>>> Well, didn't I do exactly the above much earlier and discarded it\n>>> because that breaks the definition of \"diff\"?  Or is this doing\n>>> something differently?\n>>\n>> Yes, and I try to sneak it in anyway ;-)\n>>\n>> I spend some time debugging how to get t6038 passed, and need\n>> some more time.\n>>\n>> If 10/10 is a no-go (and it probably should be),\n>> does it make sense to keep 1/10..4/10 and discard 5..10 for the moment ?\n>\n> Earlier patches in the series certainly felt alright.  I do not\n> remember noticing where it went in a strange direction to be honest.\n\nLet's step back a bit and make sure we are on the same page.  I\nthink this \"series\" conflates a bit too many things into a single\ntopic.\n\n * The comparison between the index and the working tree, i.e. \"git\n   diff\", should compare result of convert_to_git() with what is in\n   the index, and the world around it should be made consistent with\n   that.  Your separate \"git blame\" fix to add missing knowledge\n   that convert_to_git() would not do s/CRLF/LF/ for a path whose\n   index entry already is contaminated with CR falls into this\n   category and was a very good thing to do.  \n\n * A convert_to_git() and convert_to_working_tree() pair that do not\n   roundtrip would (by definition) leave contents in the working\n   tree, that, when passed through convert_to_git(), will be\n   different from the index, upon completion of \"reset --hard\".  We\n   _should_ fix it so that \"git diff\" _reports_ differences.\n   Currently, lstat(2) based optimization hides this in a racy way\n   (when racy Git kicks in to reinspect the index and the working\n   tree file actually matches, it finds out that they do not match),\n   it is a bug that needs to be fixed, not 10/10 where it tries to\n   hide the differences consistently and spreads the bug.  I haven't\n   studied 8/10 carefully yet, but it seems to attempt the same.\n\n * I think the \"text=auto eol=THIS\" that did not mean \"I do not care\n   to specify which ones are text files.  Please detect the file\n   type, and for those automatically detected, please make sure that\n   the contents follwo THIS eol convention.\" was a bug, and what\n   07/10 tries to do is a good thing.  \n\nBy the way, lack of the cover letter of this series made it more\npainful to write a reply like this than necessary.  A cover letter\nfor a trivial 3-patch series might be overkill, but for anything\nwith substance that spans more than 4-5 patches, a cover letter to\ndescribe the overall direction would really help.\n\nThanks.\n"},{"id":"285328","messageId":"55d60bb1-8626-4c97-630c-1a9f114c46b4@web.de","threadId":"41391","inReplyTo":"xmqqpot4s1ap.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-05-03T16:02:07Z","receivedAt":"2016-05-03T16:02:07Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 2016-05-02 21.33, Junio C Hamano wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n> Let's step back a bit and make sure we are on the same page.  I\n> think this \"series\" conflates a bit too many things into a single\n> topic.\n> \n>  * The comparison between the index and the working tree, i.e. \"git\n>    diff\", should compare result of convert_to_git() with what is in\n>    the index, and the world around it should be made consistent with\n>    that.  Your separate \"git blame\" fix to add missing knowledge\n>    that convert_to_git() would not do s/CRLF/LF/ for a path whose\n>    index entry already is contaminated with CR falls into this\n>    category and was a very good thing to do.  \n> \n>  * A convert_to_git() and convert_to_working_tree() pair that do not\n>    roundtrip would (by definition) leave contents in the working\n>    tree, that, when passed through convert_to_git(), will be\n>    different from the index, upon completion of \"reset --hard\".  We\n>    _should_ fix it so that \"git diff\" _reports_ differences.\n>    Currently, lstat(2) based optimization hides this in a racy way\n>    (when racy Git kicks in to reinspect the index and the working\n>    tree file actually matches, it finds out that they do not match),\n>    it is a bug that needs to be fixed, not 10/10 where it tries to\n>    hide the differences consistently and spreads the bug.  I haven't\n>    studied 8/10 carefully yet, but it seems to attempt the same.\n> \n>  * I think the \"text=auto eol=THIS\" that did not mean \"I do not care\n>    to specify which ones are text files.  Please detect the file\n>    type, and for those automatically detected, please make sure that\n>    the contents follwo THIS eol convention.\" was a bug, and what\n>    07/10 tries to do is a good thing.  \n> \n> By the way, lack of the cover letter of this series made it more\n> painful to write a reply like this than necessary.  A cover letter\n> for a trivial 3-patch series might be overkill, but for anything\n> with substance that spans more than 4-5 patches, a cover letter to\n> describe the overall direction would really help.\n\n\nThe 10/10 needs to be replaced with something different, and I start to\nget a better picture, why.\nread_cache.c/ce_compare_data() checks what \"git add\" will change in the index.\n\nsha1_file.c/index_fd() will read the file content from the working tree,\nrun convert_to_git() and calculate the sha1, which read_cache.c feeds into\nhashcmp().\n\nWhen convert_to_git() is run, 3 steps are taken:\n- apply the filter, if any\n- run crlf_to_git(), if attributes and core.autocrlf say so\n- run ident, if specified.\n\nNow the crlf_to_git() uses has_cr_in_index(const char *path) to find\nout if we should keep the CRLF or not.\n\nSide note: the suggested patches will use\nget_convert_stats_sha1(get_sha1_from_cache(path),)\n\nThis works pretty well under normal \"git add\", but fails in t6038,\nwhen we do a merge.\n\nThe new function get_sha1_from_index() can not find the sha1,\n\"read-cache.c/get_sha1_from_index:2392 path=file pos=-3\"\nand falls into the code path for\n\t\t/*\n\t\t * We might be in the middle of a merge, in which\n\t\t * case we would read stage #2 (ours).\n\t\t */\nread-cache.c/get_sha1_from_index:2408 path=file pos=3\nread-cache.c/get_sha1_from_index:2416 path=file sha1=ad55e2\n\n(The line number are with debug code)\n\nThe problem is, that ad55e2 is _not_ the sha1, which\nread_cache/ce_compare_data() had been asked to look at.\nInstead we should check the blob with 99b633.\n\nThe result is that convert/get_convert_stats_sha1() is called on the\nwrong blob (the one with CRLF instead the one without CRLF), and this\nmakes t6038 from 9/10 fail.\n10/10 rescues the situation, by using the correct blob :-)\n\nIn short, ce_compare_data() needs to forward ce->sha1 the whole way into\nconvert.c/crlf_to_git() and get_convert_stats_sha1().\n\nWhile at it, I realized that we call a convert_attrs(&ca, path) a couple\nof times (e.g. in would_convert_to_git(), to find out that we really don't have\nany attributes set.\n\nIt could be nice to do that only once.\n\nThe next step will be to add the improvements/fixes for the ce_compare_data()\nchain as described above, and then put 7/10..9/10 on top of that.\nThis will probably take some time, so that's why I asked if 1/10..4/10 could\nproceed as is ?\n(and the next version with cover letter, sorry for that)\n"},{"id":"285353","messageId":"xmqqbn4nngci.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"55d60bb1-8626-4c97-630c-1a9f114c46b4@web.de","subject":"Re: [PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-03T18:31:25Z","receivedAt":"2016-05-03T18:31:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n> This will probably take some time, so that's why I asked if 1/10..4/10 could\n> proceed as is ?\n\nSure, I wasn't saying 1-4 looked wrong at all.  I was wondering why\nthe ones in the middle, especially 7, shouldn't be moved forward\ntogether with them.\n"},{"id":"285408","messageId":"57297579.6060805@web.de","threadId":"41391","inReplyTo":"xmqqbn4nngci.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-05-04T04:07:21Z","receivedAt":"2016-05-04T04:07:21Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 05/03/2016 08:31 PM, Junio C Hamano wrote:\n> Torsten Bögershausen <tboegi@web.de> writes:\n>\n>> This will probably take some time, so that's why I asked if 1/10..4/10 could\n>> proceed as is ?\n> Sure, I wasn't saying 1-4 looked wrong at all.  I was wondering why\n> the ones in the middle, especially 7, shouldn't be moved forward\n> together with them.\nThe main reason is, that 7 breaks t6038 under Windows.\n(And I discovered that too late :-(\nAnd as Windows is the platform being most interested in CRLF handling,\nI need to re-do some work.\n"},{"id":"285425","messageId":"xmqqfutyjnhh.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"57297579.6060805@web.de","subject":"Re: [PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-04T07:23:06Z","receivedAt":"2016-05-04T07:23:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n>> Sure, I wasn't saying 1-4 looked wrong at all.  I was wondering why\n>> the ones in the middle, especially 7, shouldn't be moved forward\n>> together with them.\n> The main reason is, that 7 breaks t6038 under Windows.\n> (And I discovered that too late :-(\n> And as Windows is the platform being most interested in CRLF handling,\n> I need to re-do some work.\n\nOK.\n\nLet's separate 01-04/10 into a different topic and give it its own\nname; tb/convert-eol-autocrlf was the name I picked primarily for\n07/10 but 01-04/10 are not about that fix.  Both 02 and 04 are about\nautocrlf (the former is \"core.eol is irrelevant when core.autocrlf\nis there\", the latter is \"fix core.autocrlf used in conjunction with\nident conversion\"), so how about tb/autocrlf-fix or something?\n\nAnd then we can merge that to 'next' and to 'master' while we find\nsolution to 07/10 which is really the more important bit.\n\nAs to (the inverse of) 10/10, I am starting to suspect that the\ncorrect solution (which may not be the \"right\" one, though) would\ninvolve teaching write_entry() that not everything it writes out can\nbe marked up-to-date in the index.  A naive implemention would be to\npass what it writes out to the filesystem through convert_to_git()\nand see if the result matches the blob in the index, and if it does\nnot match, make sure ce_mark_uptodate() is not called, perhaps by\nnot calling fill_stat_cache_info(), or manually dropping CE_UPTODATE\nbit at the end of the function.\n\nA naive implementation however may turn out to be way too expensive\nto use as-is, I am afraid.  Possible ways to speed up would be to\nskip this \"refrain from marking up-to-date\" hackery when conversion\nis known to be well behaved.  For example, with the EOL handling\nupdated with your series, we may be able to say that the stock\nto-git and to-working-tree pair is guaranteed to roundtrip even with\nEOL conversion, ident conversion as long as there is no end-user\ndefined clean/smudge filters.  With such an optimization, the result\nmight perform with acceptable performance penalty in common cases.\n"},{"id":"285676","messageId":"e33e0b87-caa1-84a3-7c5c-8938e0c78a77@web.de","threadId":"41391","inReplyTo":"xmqqfutyjnhh.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-05-06T08:54:55Z","receivedAt":"2016-05-06T08:54:55Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"\n> Let's separate 01-04/10 into a different topic and give it its own\n> name; tb/convert-eol-autocrlf was the name I picked primarily for\n> 07/10 but 01-04/10 are not about that fix.  Both 02 and 04 are about\n> autocrlf (the former is \"core.eol is irrelevant when core.autocrlf\n> is there\", the latter is \"fix core.autocrlf used in conjunction with\n> ident conversion\"), so how about tb/autocrlf-fix or something?\ntb/core-eol-fix would be my suggestion, or core-eol-t0027-fix.\n\n> And then we can merge that to 'next' and to 'master' while we find\n> solution to 07/10 which is really the more important bit.\n>\n> As to (the inverse of) 10/10, I am starting to suspect that the\n> correct solution (which may not be the \"right\" one, though) would\n> involve teaching write_entry() that not everything it writes out can\n> be marked up-to-date in the index.  A naive implemention would be to\n> pass what it writes out to the filesystem through convert_to_git()\n> and see if the result matches the blob in the index, and if it does\n> not match, make sure ce_mark_uptodate() is not called, perhaps by\n> not calling fill_stat_cache_info(), or manually dropping CE_UPTODATE\n> bit at the end of the function.\n>\n> A naive implementation however may turn out to be way too expensive\n> to use as-is, I am afraid.  Possible ways to speed up would be to\n> skip this \"refrain from marking up-to-date\" hackery when conversion\n> is known to be well behaved.  For example, with the EOL handling\n> updated with your series, we may be able to say that the stock\n> to-git and to-working-tree pair is guaranteed to roundtrip even with\n> EOL conversion, ident conversion as long as there is no end-user\n> defined clean/smudge filters.  With such an optimization, the result\n> might perform with acceptable performance penalty in common cases.\n>\nThat makes sense and will remove the shakiness, right ?\nWe only need to pay extra attention when there is an\nexternal clean/smudge filter defined - otherwise we should be able to skip it -\nafter 10/10.\n"},{"id":"285756","messageId":"xmqq4mab5cwy.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"e33e0b87-caa1-84a3-7c5c-8938e0c78a77@web.de","subject":"Re: [PATCH v8 10/10] ce_compare_data() did not respect conversion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-06T17:11:57Z","receivedAt":"2016-05-06T17:11:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n> We only need to pay extra attention when there is an external\n> clean/smudge filter defined - otherwise we should be able to skip\n> it - after 10/10.\n\nThe last two words worries me.  The goal of the suggested fix was to\nmake sure that\n\n\t$ git reset --hard && git diff\n\nreports that there _are_ differences in the working tree files, if\nthe to-git and to-working-tree conversion do not round-trip.  It is\na total opposite of 10/10, which hides the fact that working tree\ncontents, if added to the index, would change the index.\n"},{"id":"285797","messageId":"1462601456-23439-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v9 0/6] convert-eol-autocrlf, old 5..10 now 1..6","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-05-07T06:10:56Z","receivedAt":"2016-05-07T06:10:56Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nChanges since v8:\n  As discussed earlier,  1..4 should be broken out into \n  tb/autocrlf-fix or so.\n  1..4 are not part of this series any more.\n\n  The old 10/10 is now 6/6.\n  It is replaced by \"ce_compare_data() checks for a sha1 of a path\"\n    It now checks for \"What would git add change in the index\",\n    and not \"is the working tree clean after checkout\" - \n    thats how it should be.\n    Basically an old limititation of \"has_crlf_in_index()\" has been found and\n    fixed.\n    The commit message may need some tweaking, and\n    even the implementation, so feedback is welcome.\n    Beside that, I haven't run the tests under Windows yet.\n\nTorsten Bögershausen (6):\n  read-cache: factor out get_sha1_from_index() helper\n  convert.c: stream and early out\n  convert: unify the \"auto\" handling of CRLF\n  convert.c: more safer crlf handling with text attribute\n  t6038; use crlf on all platforms\n  convert: ce_compare_data() checks for a sha1 of a path\n\n Documentation/config.txt        |  14 +-\n Documentation/gitattributes.txt |  24 ++-\n cache.h                         |   4 +\n convert.c                       | 362 +++++++++++++++++++++++++++-------------\n convert.h                       |  26 ++-\n read-cache.c                    |  33 ++--\n sha1_file.c                     |  17 +-\n t/t0025-crlf-auto.sh            |  12 +-\n t/t0027-auto-crlf.sh            |  98 +++++------\n t/t6038-merge-text-auto.sh      |  60 +++----\n 10 files changed, 407 insertions(+), 243 deletions(-)\n\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"285798","messageId":"1462601458-23498-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v9 1/6] read-cache: factor out get_sha1_from_index() helper","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-05-07T06:10:58Z","receivedAt":"2016-05-07T06:10:58Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nFactor out the retrieval of the sha1 for a given path in\nread_blob_data_from_index() into the function get_sha1_from_index().\n\nThis will be used in the next commit, when convert.c can do the\nanalyze for \"text=auto\" without slurping the whole blob into memory\nat once.\n\nAdd a wrapper definition get_sha1_from_cache().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n cache.h      |  3 +++\n read-cache.c | 29 ++++++++++++++++++-----------\n 2 files changed, 21 insertions(+), 11 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 1c60918..28f23d7 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -379,6 +379,7 @@ extern void free_name_hash(struct index_state *istate);\n #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)\n #define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)\n #define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))\n+#define get_sha1_from_cache(path)  get_sha1_from_index (&the_index, (path))\n #endif\n \n enum object_type {\n@@ -1019,6 +1020,8 @@ static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *\n \treturn read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);\n }\n \n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path);\n+\n /*\n  * This internal function is only declared here for the benefit of\n  * lookup_replace_object().  Please do not call it directly.\ndiff --git a/read-cache.c b/read-cache.c\nindex d9fb78b..a3ef967 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -2263,13 +2263,27 @@ int index_name_is_other(const struct index_state *istate, const char *name,\n \n void *read_blob_data_from_index(struct index_state *istate, const char *path, unsigned long *size)\n {\n-\tint pos, len;\n+\tconst unsigned char *sha1;\n \tunsigned long sz;\n \tenum object_type type;\n \tvoid *data;\n \n-\tlen = strlen(path);\n-\tpos = index_name_pos(istate, path, len);\n+\tsha1 = get_sha1_from_index(istate, path);\n+\tif (!sha1)\n+\t\treturn NULL;\n+\tdata = read_sha1_file(sha1, &type, &sz);\n+\tif (!data || type != OBJ_BLOB) {\n+\t\tfree(data);\n+\t\treturn NULL;\n+\t}\n+\tif (size)\n+\t\t*size = sz;\n+\treturn data;\n+}\n+\n+const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path)\n+{\n+\tint pos = index_name_pos(istate, path, strlen(path));\n \tif (pos < 0) {\n \t\t/*\n \t\t * We might be in the middle of a merge, in which\n@@ -2285,14 +2299,7 @@ void *read_blob_data_from_index(struct index_state *istate, const char *path, un\n \t}\n \tif (pos < 0)\n \t\treturn NULL;\n-\tdata = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);\n-\tif (!data || type != OBJ_BLOB) {\n-\t\tfree(data);\n-\t\treturn NULL;\n-\t}\n-\tif (size)\n-\t\t*size = sz;\n-\treturn data;\n+\treturn (istate->cache[pos]->sha1);\n }\n \n void stat_validity_clear(struct stat_validity *sv)\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"285803","messageId":"1462601460-23543-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v9 2/6] convert.c: stream and early out","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-05-07T06:11:00Z","receivedAt":"2016-05-07T06:11:00Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nWhen statistics are done for the autocrlf handling, the search in\nthe content can be stopped, if e.g\n- a search for binary is done, and a NUL character is found\n- a search for CRLF is done, and the first CRLF is found.\n\nSimilar when statistics for binary vs non-binary are gathered:\nWhenever a lone CR or NUL is found, the search can be aborted.\n\nWhen checking out files in \"auto\" mode, any file that has a \"lone CR\"\nor a CRLF will not be converted, so the search can be aborted early.\n\nAdd the new bit, CONVERT_STAT_BITS_ANY_CR,\nwhich is set for either lone CR or CRLF.\n\nMany binary files have a NUL very early (within the first few bytes,\nlatest within the first 1..2K).\nIt is often not necessary to load the whole content of a file or blob\ninto memory.\n\nUse a streaming handling for blobs and files in the worktree.\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n convert.c | 159 ++++++++++++++++++++++++++++++++++++++++----------------------\n 1 file changed, 103 insertions(+), 56 deletions(-)\n\ndiff --git a/convert.c b/convert.c\nindex b1614bf..24ab095 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -3,6 +3,7 @@\n #include \"run-command.h\"\n #include \"quote.h\"\n #include \"sigchain.h\"\n+#include \"streaming.h\"\n \n /*\n  * convert.c - convert a file when checking it out and checking it in.\n@@ -13,10 +14,10 @@\n  * translation when the \"text\" attribute or \"auto_crlf\" option is set.\n  */\n \n-/* Stat bits: When BIN is set, the txt bits are unset */\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n+#define CONVERT_STAT_BITS_ANY_CR    0x8\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -31,30 +32,36 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned nul, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonecr, lonelf, crlf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n };\n \n-static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)\n+static void do_gather_stats(const char *buf, unsigned long size,\n+\t\t\t    struct text_stat *stats, unsigned earlyout)\n {\n \tunsigned long i;\n \n-\tmemset(stats, 0, sizeof(*stats));\n-\n+\tif (!buf || !size)\n+\t\treturn;\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n \t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n-\t\t\t} else\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\t} else {\n \t\t\t\tstats->lonecr++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+\t\t\t}\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == '\\n') {\n \t\t\tstats->lonelf++;\n+\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_LF;\n \t\t\tcontinue;\n \t\t}\n \t\tif (c == 127)\n@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t\t\tstats->printable++;\n \t\t\t\tbreak;\n \t\t\tcase 0:\n-\t\t\t\tstats->nul++;\n+\t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t\t/* fall through */\n \t\t\tdefault:\n \t\t\t\tstats->nonprintable++;\n@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n \t\t}\n \t\telse\n \t\t\tstats->printable++;\n+\t\tif (stats->stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n \t}\n \n \t/* If file ends with EOF then don't count this EOF as non-printable. */\n@@ -86,41 +95,62 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *\n  * The same heuristics as diff.c::mmfile_is_binary()\n  * We treat files with bare CR as binary\n  */\n-static int convert_is_binary(unsigned long size, const struct text_stat *stats)\n+static void convert_nonprintable(struct text_stat *stats)\n {\n-\tif (stats->lonecr)\n-\t\treturn 1;\n-\tif (stats->nul)\n-\t\treturn 1;\n \tif ((stats->printable >> 7) < stats->nonprintable)\n-\t\treturn 1;\n-\treturn 0;\n+\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n+}\n+\n+static void gather_stats(const char *buf, unsigned long size,\n+\t\t\t struct text_stat *stats, unsigned earlyout)\n+{\n+\tmemset(stats, 0, sizeof(*stats));\n+\tdo_gather_stats(buf, size, stats, earlyout);\n+\tconvert_nonprintable(stats);\n }\n \n-static unsigned int gather_convert_stats(const char *data, unsigned long size)\n+\n+static unsigned get_convert_stats_sha1(unsigned const char *sha1,\n+\t\t\t\t       unsigned earlyout)\n {\n+\tstruct git_istream *st;\n \tstruct text_stat stats;\n-\tint ret = 0;\n-\tif (!data || !size)\n-\t\treturn 0;\n-\tgather_stats(data, size, &stats);\n-\tif (convert_is_binary(size, &stats))\n-\t\tret |= CONVERT_STAT_BITS_BIN;\n-\tif (stats.crlf)\n-\t\tret |= CONVERT_STAT_BITS_TXT_CRLF;\n-\tif (stats.lonelf)\n-\t\tret |=  CONVERT_STAT_BITS_TXT_LF;\n+\tenum object_type type;\n+\tunsigned long sz;\n \n-\treturn ret;\n+\tif (!sha1)\n+\t\treturn 0;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tst = open_istream(sha1, &type, &sz, NULL);\n+\tif (!st) {\n+\t\treturn 0;\n+\t}\n+\tif (type != OBJ_BLOB)\n+\t\tgoto close_and_exit_i;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read_istream(st, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+close_and_exit_i:\n+\tclose_istream(st);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n }\n \n-static const char *gather_convert_stats_ascii(const char *data, unsigned long size)\n+static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned int convert_stats = gather_convert_stats(data, size);\n-\n+\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n+\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats) {\n+\tswitch (convert_stats & mask) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -132,24 +162,45 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si\n \t}\n }\n \n+static unsigned get_convert_stats_wt(const char *path)\n+{\n+\tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tint fd;\n+\tmemset(&stats, 0, sizeof(stats));\n+\tfd = open(path, O_RDONLY);\n+\tif (fd < 0)\n+\t\treturn 0;\n+\tfor (;;) {\n+\t\tchar buf[1024];\n+\t\tssize_t readlen = read(fd, buf, sizeof(buf));\n+\t\tif (readlen < 0)\n+\t\t\tbreak;\n+\t\tif (!readlen)\n+\t\t\tbreak;\n+\t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n+\t\tif (stats.stat_bits & earlyout)\n+\t\t\tbreak; /* We found what we have been searching for */\n+\t}\n+\tclose(fd);\n+\tconvert_nonprintable(&stats);\n+\treturn stats.stat_bits;\n+}\n+\n const char *get_cached_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret;\n-\tunsigned long sz;\n-\tvoid *data = read_blob_data_from_cache(path, &sz);\n-\tret = gather_convert_stats_ascii(data, sz);\n-\tfree(data);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n const char *get_wt_convert_stats_ascii(const char *path)\n {\n-\tconst char *ret = \"\";\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tif (strbuf_read_file(&sb, path, 0) >= 0)\n-\t\tret = gather_convert_stats_ascii(sb.buf, sb.len);\n-\tstrbuf_release(&sb);\n-\treturn ret;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_wt(path);\n+\treturn convert_stats_ascii(convert_stats);\n }\n \n static int text_eol_is_crlf(void)\n@@ -219,16 +270,10 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \n static int has_cr_in_index(const char *path)\n {\n-\tunsigned long sz;\n-\tvoid *data;\n-\tint has_cr;\n-\n-\tdata = read_blob_data_from_cache(path, &sz);\n-\tif (!data)\n-\t\treturn 0;\n-\thas_cr = memchr(data, '\\r', sz) != NULL;\n-\tfree(data);\n-\treturn has_cr;\n+\tunsigned convert_stats;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n+\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -249,10 +294,10 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \n \t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n@@ -309,11 +354,13 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n+\n \n \tif (!len || output_eol(crlf_action) != EOL_CRLF)\n \t\treturn 0;\n \n-\tgather_stats(src, len, &stats);\n+\tgather_stats(src, len, &stats, earlyout);\n \n \t/* No \"naked\" LF? Nothing to convert, regardless. */\n \tif (!stats.lonelf)\n@@ -327,7 +374,7 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\t\t\treturn 0;\n \t\t}\n \n-\t\tif (convert_is_binary(len, &stats))\n+\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n \t}\n \n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"285802","messageId":"1462601462-23594-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v9 3/6] convert: unify the \"auto\" handling of CRLF","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-05-07T06:11:02Z","receivedAt":"2016-05-07T06:11:02Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nBefore this change,\n$ echo \"* text=auto\" >.gitattributes\n$ echo \"* eol=crlf\" >>.gitattributes\n\nwould have the same effect as\n$ echo \"* text\" >.gitattributes\n$ git config core.eol crlf\n\nSince the 'eol' attribute had higher priority than 'text=auto', this may\ncorrupt binary files and is not what most users expect to happen.\n\nMake the 'eol' attribute to obey 'text=auto', and now\n$ echo \"* text=auto\" >.gitattributes\n$ echo \"* eol=crlf\" >>.gitattributes\nbehaves the same as\n$ echo \"* text=auto\" >.gitattributes\n$ git config core.eol crlf\n\nIn other words,\n$ echo \"* text=auto eol=crlf\" >.gitattributes\nhas the same effect as\n$ git config core.autocrlf true\n\nand\n$ echo \"* text=auto eol=lf\" >.gitattributes\nhas the same effect as\n$ git config core.autocrlf input\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/config.txt        | 14 +++++++-------\n Documentation/gitattributes.txt | 15 +++++++++------\n convert.c                       | 42 +++++++++++++++++++++--------------------\n convert.h                       |  3 ++-\n t/t0025-crlf-auto.sh            |  4 ++--\n t/t0027-auto-crlf.sh            | 32 +++++++++++++++----------------\n t/t6038-merge-text-auto.sh      | 23 ++++++++++++++--------\n 7 files changed, 73 insertions(+), 60 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 988ea1e..4c47a25 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -397,13 +397,13 @@ file with mixed line endings would be reported by the `core.safecrlf`\n mechanism.\n \n core.autocrlf::\n-\tSetting this variable to \"true\" is almost the same as setting\n-\tthe `text` attribute to \"auto\" on all files except that text\n-\tfiles are not guaranteed to be normalized: files that contain\n-\t`CRLF` in the repository will not be touched.  Use this\n-\tsetting if you want to have `CRLF` line endings in your\n-\tworking directory even though the repository does not have\n-\tnormalized line endings.  This variable can be set to 'input',\n+\tSetting this variable to \"true\" is the same as setting\n+\tthe `text` attribute to \"auto\" on all files and core.eol to \"crlf\".\n+\tSet to true if you want to have `CRLF` line endings in your\n+\tworking directory and the repository has LF line endings.\n+\tText files are guaranteed not to be normalized: files that contain\n+\t`CRLF` in the repository will not be touched.\n+\tThis variable can be set to 'input',\n \tin which case no output conversion is performed.\n \n core.symlinks::\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex e3b1de8..d7a124b 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n `core.eol` configuration variable for all text files.\n+Note that `core.autocrlf` overrides `core.eol`\n \n Set::\n \n@@ -130,8 +131,9 @@ Unset::\n Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n-\tend-of-line normalization.  If Git decides that the content is\n-\ttext, its line endings are normalized to LF on checkin.\n+\tend-of-line conversion.  If Git decides that the content is\n+\ttext, its line endings are converted to LF on checkin.\n+\tWhen the file has been commited with CRLF, no conversion is done.\n \n Unspecified::\n \n@@ -146,7 +148,7 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It enables end-of-line normalization without any\n+working directory.  It enables end-of-line conversion without any\n content checks, effectively setting the `text` attribute.\n \n Set to string value \"crlf\"::\n@@ -186,9 +188,10 @@ the working directory, and prevent .jpg files from being normalized\n regardless of their content.\n \n ------------------------\n+*               text=auto\n *.txt\t\ttext\n-*.vcproj\teol=crlf\n-*.sh\t\teol=lf\n+*.vcproj\ttext eol=crlf\n+*.sh\t\ttext eol=lf\n *.jpg\t\t-text\n ------------------------\n \n@@ -198,7 +201,7 @@ normalization in Git.\n \n If you simply want to have CRLF line endings in your working directory\n regardless of the repository you are working with, you can set the\n-config variable \"core.autocrlf\" without changing any attributes.\n+config variable \"core.autocrlf\" without using any attributes.\n \n ------------------------\n [core]\ndiff --git a/convert.c b/convert.c\nindex 24ab095..3782172 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -227,7 +227,9 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \t\treturn EOL_LF;\n \tcase CRLF_UNDEFINED:\n \tcase CRLF_AUTO_CRLF:\n+\t\treturn EOL_CRLF;\n \tcase CRLF_AUTO_INPUT:\n+\t\treturn EOL_LF;\n \tcase CRLF_TEXT:\n \tcase CRLF_AUTO:\n \t\t/* fall through */\n@@ -299,17 +301,15 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/*\n-\t\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t\t * This is the new safer autocrlf handling.\n-\t\t\t */\n-\t\t\tif (has_cr_in_index(path))\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/*\n+\t\t * If the file in the index has any CR in it, do not convert.\n+\t\t * This is the new safer autocrlf handling.\n+\t\t */\n+\t\tif (checksafe == SAFE_CRLF_RENORMALIZE)\n+\t\t\tchecksafe = SAFE_CRLF_FALSE;\n+\t\telse if (has_cr_in_index(path))\n+\t\t\treturn 0;\n \t}\n-\n \tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n \n \t/* Optimization: No CRLF? Nothing to convert, regardless. */\n@@ -367,12 +367,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n \t\treturn 0;\n \n \tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\tif (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t\t/* This is the new safer autocrlf-handling */\n-\t\t\tif (stats.lonecr || stats.crlf )\n-\t\t\t\treturn 0;\n-\t\t}\n+\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n+\t\t/* This is the new safer autocrlf-handling */\n+\t\tif (stats.lonecr || stats.crlf )\n+\t\t\treturn 0;\n \n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n@@ -833,7 +831,11 @@ static void convert_attrs(struct conv_attrs *ca, const char *path)\n \t\tca->drv = git_path_check_convert(ccheck + 2);\n \t\tif (ca->crlf_action != CRLF_BINARY) {\n \t\t\tenum eol eol_attr = git_path_check_eol(ccheck + 3);\n-\t\t\tif (eol_attr == EOL_LF)\n+\t\t\tif (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_INPUT;\n+\t\t\telse if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)\n+\t\t\t\tca->crlf_action = CRLF_AUTO_CRLF;\n+\t\t\telse if (eol_attr == EOL_LF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_INPUT;\n \t\t\telse if (eol_attr == EOL_CRLF)\n \t\t\t\tca->crlf_action = CRLF_TEXT_CRLF;\n@@ -892,9 +894,9 @@ const char *get_convert_attr_ascii(const char *path)\n \tcase CRLF_AUTO:\n \t\treturn \"text=auto\";\n \tcase CRLF_AUTO_CRLF:\n-\t\treturn \"text=auto eol=crlf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=crlf\";\n \tcase CRLF_AUTO_INPUT:\n-\t\treturn \"text=auto eol=lf\"; /* This is not supported yet */\n+\t\treturn \"text=auto eol=lf\";\n \t}\n \treturn \"\";\n }\n@@ -996,7 +998,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_FALSE);\n+\treturn ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE);\n }\n \n /*****************************************************************\ndiff --git a/convert.h b/convert.h\nindex ccf436b..81b6cdf 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -7,7 +7,8 @@\n enum safe_crlf {\n \tSAFE_CRLF_FALSE = 0,\n \tSAFE_CRLF_FAIL = 1,\n-\tSAFE_CRLF_WARN = 2\n+\tSAFE_CRLF_WARN = 2,\n+\tSAFE_CRLF_RENORMALIZE = 4\n };\n \n extern enum safe_crlf safe_crlf;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex c164b46..d0bee08 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -114,7 +114,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n+test_expect_success 'text=auto, autocrlf=true does not normalize CRLF files' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \tgit config core.autocrlf true &&\n@@ -126,7 +126,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '\n \tLFonlydiff=$(git diff LFonly) &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n \tLFwithNULdiff=$(git diff LFwithNUL) &&\n-\ttest -z \"$LFonlydiff\" -a -n \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n+\ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex 5f6208a..e2be985 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -175,8 +175,8 @@ attr_ascii () {\n \ttext,lf)   echo \"text eol=lf\" ;;\n \ttext,crlf) echo \"text eol=crlf\" ;;\n \tauto,)     echo \"text=auto\" ;;\n-\tauto,lf)   echo \"text eol=lf\" ;;\n-\tauto,crlf) echo \"text eol=crlf\" ;;\n+\tauto,lf)   echo \"text=auto eol=lf\" ;;\n+\tauto,crlf) echo \"text=auto eol=crlf\" ;;\n \tlf,)       echo \"text eol=lf\" ;;\n \tcrlf,)     echo \"text eol=crlf\" ;;\n \t,) echo \"\" ;;\n@@ -397,10 +397,9 @@ commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          \"\"\n-\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n@@ -408,8 +407,8 @@ do\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n \tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n \tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n done\n@@ -454,9 +453,9 @@ do\n \tcheck_in_repo_NNO -text \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO -text crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  LF    LF           LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO auto  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO auto  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n \tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n@@ -493,7 +492,8 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-for id in \"\" ident\n+#for id in \"\" ident\n+for id in \"\"\n do\n \tfor ceol in lf crlf native\n \tdo\n@@ -509,7 +509,7 @@ do\n \t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n \t\t\t# currently the same as text, eol=XXX\n \t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \n \t\t# core.autocrlf false, different core.eol\n@@ -517,7 +517,7 @@ do\n \t\t# core.autocrlf true\n \t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n \t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n@@ -531,8 +531,8 @@ do\n \tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n \t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n-\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 85c10b0..33b77ee 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -16,6 +16,13 @@ test_description='CRLF merge conflict across text=auto change\n \n test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b\n \n+compare_files () {\n+\ttr '\\015\\000' QN <\"$1\" >\"$1\".expect &&\n+\ttr '\\015\\000' QN <\"$2\" >\"$2\".actual &&\n+\ttest_cmp \"$1\".expect \"$2\".actual &&\n+\trm \"$1\".expect \"$2\".actual\n+}\n+\n test_expect_success setup '\n \tgit config core.autocrlf false &&\n \n@@ -30,7 +37,7 @@ test_expect_success setup '\n \tgit branch side &&\n \n \techo \"* text=auto\" >.gitattributes &&\n-\ttouch file &&\n+\techo first line >file &&\n \tgit add .gitattributes file &&\n \ttest_tick &&\n \tgit commit -m \"normalize file\" &&\n@@ -81,7 +88,7 @@ test_expect_success 'Merge after setting text=auto' '\n \trm -f .gitattributes &&\n \tgit reset --hard a &&\n \tgit merge b &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_success 'Merge addition of text=auto' '\n@@ -99,7 +106,7 @@ test_expect_success 'Merge addition of text=auto' '\n \trm -f .gitattributes &&\n \tgit reset --hard b &&\n \tgit merge a &&\n-\ttest_cmp expected file\n+\tcompare_files  expected file\n '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n@@ -121,7 +128,7 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \tgit reset --hard a &&\n \ttest_must_fail git merge b &&\n \tfuzz_conflict file >file.fuzzy &&\n-\ttest_cmp expected file.fuzzy\n+\tcompare_files expected file.fuzzy\n '\n \n test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n@@ -143,7 +150,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \tgit reset --hard b &&\n \ttest_must_fail git merge a &&\n \tfuzz_conflict file >file.fuzzy &&\n-\ttest_cmp expected file.fuzzy\n+\tcompare_files expected file.fuzzy\n '\n \n test_expect_failure 'checkout -m after setting text=auto' '\n@@ -158,7 +165,7 @@ test_expect_failure 'checkout -m after setting text=auto' '\n \tgit reset --hard initial &&\n \tgit checkout a -- . &&\n \tgit checkout -m b &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_failure 'checkout -m addition of text=auto' '\n@@ -173,7 +180,7 @@ test_expect_failure 'checkout -m addition of text=auto' '\n \tgit reset --hard initial &&\n \tgit checkout b -- . &&\n \tgit checkout -m a &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_failure 'cherry-pick patch from after text=auto was added' '\n@@ -187,7 +194,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' '\n \tgit reset --hard b &&\n \ttest_must_fail git cherry-pick a >err 2>&1 &&\n \tgrep \"[Nn]othing added\" err &&\n-\ttest_cmp expected file\n+\tcompare_files expected file\n '\n \n test_expect_success 'Test delete/normalize conflict' '\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"285800","messageId":"1462601463-23645-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v9 4/6] convert.c: more safer crlf handling with text attribute","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-05-07T06:11:03Z","receivedAt":"2016-05-07T06:11:03Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nA follow-up after a discussion how to fix the flaky execution\nof t0025, gmane/$284352.\n\nThis patch extends the work done in commit c480539:\n\"Make it work also for un-normalized repositories\". Make sure that CRLF\ncan be converted round trip, or don't convert them at all.\n\nThe old handling would treat a file as unchanged after checkout,\nas long as it is not touched in the work tree and mtime matches the value\nrecorded in the index.\nWhen the mtime is changed in the working tree, or the inode is changed,\nthe file is reported as modified.\n\nThe following sequence is now handled reproducable:\n$ git init\n$ printf \"line1\\r\\n\" >file.bat\n$ git add file.bat\n$ git commit -m \"Add file with CRLF\" file.bat\n$ echo \"*.bat text eol=crlf\" >.gitattributes\n$ git commit -m \"bat files should have CRLF\"\n$ git status\n # nothing to commit, working directory clean\n$ git push <upstream>\n$ printf \"newline\\r\\n\" >>file.bat\n$ mv file.bat file.sav\n$ git checkout file.bat\n$ git status\n #modified:   file.bat\n\nThe new handling makes sure that after running \"git reset --hard\".\n\"git status\" reports the working tree as clean regarding CRLF conversion.\nIt makes sure that the Git-internal eol conversion is\ndoing roundtrip. A user can still write an external smudge/clean filter\noutside Git, which doesn't do a roundtrip and the working directory is\nnot clean.\n\nThe functionality of has_cr_in_index() is turned into has_crlf_in_index(),\nand the function is integrated into would_convert_crlf_at_commit().\n\nCheck for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR\nis no longer used and removed, as well as \"lonecr\" in struct text_stat.\n\nRewrite check_safe_crlf() in convert.c to simulate checkin-checkout,\nto detect whether any line endings are converted.\n\nAdd a warning, similar to the CRLF-LF replacement, when a file is commited,\nand after the next checkout the line endings are not they should be.\n\nModify the lf_to_crlf_filter:\nFiles with LF are converted into CRLF, file with CRLF are not changed.\nFiles with mixed line endings are not converted, the filter fails, and Git\nfalls back to the non-streaming handling, see write_entry().\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/gitattributes.txt |  19 ++--\n convert.c                       | 233 +++++++++++++++++++++++++---------------\n t/t0025-crlf-auto.sh            |   8 +-\n t/t0027-auto-crlf.sh            |  92 ++++++++--------\n 4 files changed, 212 insertions(+), 140 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex d7a124b..836461d 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'.\n `text`\n ^^^^^^\n \n-This attribute enables and controls end-of-line normalization.  When a\n+This attribute enables and controls end-of-line conversion.  When a\n text file is normalized, its line endings are converted to LF in the\n repository.  To control what line ending style is used in the working\n directory, use the `eol` attribute for a single file and the\n@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol`\n Set::\n \n \tSetting the `text` attribute on a path enables end-of-line\n-\tnormalization and marks the path as a text file.  End-of-line\n+\tconversion and marks the path as a text file.  End-of-line\n \tconversion takes place without guessing the content type.\n+\tFiles that have been commited with CRLF before the text attribute\n+\tis set and commited are not normalized. No end-of-line conversion\n+\tis done at checkout or checkin.\n \n Unset::\n \n@@ -131,9 +134,9 @@ Unset::\n Set to string value \"auto\"::\n \n \tWhen `text` is set to \"auto\", the path is marked for automatic\n-\tend-of-line conversion.  If Git decides that the content is\n-\ttext, its line endings are converted to LF on checkin.\n-\tWhen the file has been commited with CRLF, no conversion is done.\n+\tend-of-line normalization.  If Git decides that the content is\n+\ttext, and the path has no CRLF in the index,\n+\tits line endings are converted to LF on checkin.\n \n Unspecified::\n \n@@ -148,8 +151,10 @@ unspecified.\n ^^^^^\n \n This attribute sets a specific line-ending style to be used in the\n-working directory.  It enables end-of-line conversion without any\n-content checks, effectively setting the `text` attribute.\n+working directory.  It sets the `text` attribute, unless `text=auto`\n+is specified.\n+When the file had been commited with CRLF in the index, no conversion\n+is done at checkout or commit.\n \n Set to string value \"crlf\"::\n \ndiff --git a/convert.c b/convert.c\nindex 3782172..8d4c42a 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -17,7 +17,8 @@\n #define CONVERT_STAT_BITS_TXT_LF    0x1\n #define CONVERT_STAT_BITS_TXT_CRLF  0x2\n #define CONVERT_STAT_BITS_BIN       0x4\n-#define CONVERT_STAT_BITS_ANY_CR    0x8\n+\n+#define CONVERT_STAT_BITS_MIXED (CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF)\n \n enum crlf_action {\n \tCRLF_UNDEFINED,\n@@ -32,7 +33,7 @@ enum crlf_action {\n \n struct text_stat {\n \t/* NUL, CR, LF and CRLF counts */\n-\tunsigned stat_bits, lonecr, lonelf, crlf;\n+\tunsigned stat_bits, lonelf;\n \n \t/* These are just approximations! */\n \tunsigned printable, nonprintable;\n@@ -48,13 +49,10 @@ static void do_gather_stats(const char *buf, unsigned long size,\n \tfor (i = 0; i < size; i++) {\n \t\tunsigned char c = buf[i];\n \t\tif (c == '\\r') {\n-\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;\n \t\t\tif (i+1 < size && buf[i+1] == '\\n') {\n-\t\t\t\tstats->crlf++;\n \t\t\t\ti++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;\n \t\t\t} else {\n-\t\t\t\tstats->lonecr++;\n \t\t\t\tstats->stat_bits |= CONVERT_STAT_BITS_BIN;\n \t\t\t}\n \t\t\tcontinue;\n@@ -135,7 +133,7 @@ static unsigned get_convert_stats_sha1(unsigned const char *sha1,\n \t\tif (!readlen)\n \t\t\tbreak;\n \t\tdo_gather_stats(buf, (unsigned long)readlen, &stats, earlyout);\n-\t\tif (stats.stat_bits & earlyout)\n+\t\tif ((stats.stat_bits & earlyout) == earlyout)\n \t\t\tbreak; /* We found what we have been searching for */\n \t}\n close_and_exit_i:\n@@ -146,11 +144,9 @@ close_and_exit_i:\n \n static const char *convert_stats_ascii(unsigned convert_stats)\n {\n-\tunsigned mask = CONVERT_STAT_BITS_TXT_LF |\n-\t\tCONVERT_STAT_BITS_TXT_CRLF;\n \tif (convert_stats & CONVERT_STAT_BITS_BIN)\n \t\treturn \"-text\";\n-\tswitch (convert_stats & mask) {\n+\tswitch (convert_stats) {\n \tcase CONVERT_STAT_BITS_TXT_LF:\n \t\treturn \"lf\";\n \tcase CONVERT_STAT_BITS_TXT_CRLF:\n@@ -162,7 +158,16 @@ static const char *convert_stats_ascii(unsigned convert_stats)\n \t}\n }\n \n-static unsigned get_convert_stats_wt(const char *path)\n+const char *get_cached_convert_stats_ascii(const char *path)\n+{\n+\tunsigned convert_stats;\n+\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n+\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t       earlyout);\n+\treturn convert_stats_ascii(convert_stats);\n+}\n+\n+const char *get_wt_convert_stats_ascii(const char *path)\n {\n \tstruct text_stat stats;\n \tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n@@ -184,23 +189,7 @@ static unsigned get_convert_stats_wt(const char *path)\n \t}\n \tclose(fd);\n \tconvert_nonprintable(&stats);\n-\treturn stats.stat_bits;\n-}\n-\n-const char *get_cached_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_BIN;\n-\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n-\t\t\t\t\t       earlyout);\n-\treturn convert_stats_ascii(convert_stats);\n-}\n-\n-const char *get_wt_convert_stats_ascii(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_wt(path);\n-\treturn convert_stats_ascii(convert_stats);\n+\treturn convert_stats_ascii(stats.stat_bits);\n }\n \n static int text_eol_is_crlf(void)\n@@ -239,43 +228,95 @@ static enum eol output_eol(enum crlf_action crlf_action)\n \treturn core_eol;\n }\n \n+static int would_convert_lf_at_checkout(unsigned convert_stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tif (output_eol(crlf_action) != EOL_CRLF)\n+\t\treturn 0;\n+\n+\t/* No \"naked\" LF? Nothing to convert, regardless. */\n+\tif (!convert_stats & CONVERT_STAT_BITS_TXT_LF)\n+\t\treturn 0;\n+\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\t/* auto: binary files are not converted */\n+\t\tif (convert_stats & CONVERT_STAT_BITS_BIN)\n+\t\t\treturn 0;\n+\t}\n+\t/* If we have any CRLF line endings, we do not touch it */\n+\t/* This is the new safer autocrlf-handling */\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+\n+}\n+\n+static int would_convert_crlf_at_commit(const char * path,\n+\t\t\t\t\tconst struct text_stat *stats,\n+\t\t\t\t\tsize_t len,\n+\t\t\t\t\tenum crlf_action crlf_action)\n+{\n+\tunsigned stat_bits_index;\n+\t/* No CRLF? Nothing to convert, regardless. */\n+\tif (!(stats->stat_bits & CONVERT_STAT_BITS_TXT_CRLF))\n+\t\treturn 0;\n+\t/*\n+\t * If the file in the index has any CRLF in it, do not convert.\n+\t * This is the new safer autocrlf handling.\n+\t */\n+\tstat_bits_index = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\t\t\t\t\t\t CONVERT_STAT_BITS_TXT_CRLF);\n+\tif (stat_bits_index & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\treturn 0;\n+\treturn 1;\n+}\n+\n static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n-                            struct text_stat *stats, enum safe_crlf checksafe)\n+\t\t\t    enum safe_crlf checksafe,\n+\t\t\t    unsigned convert_stats, unsigned new_convert_stats)\n {\n+\tenum eol new_eol = output_eol(crlf_action);\n+\tconst char *err_warn_msg = NULL;\n \tif (!checksafe)\n \t\treturn;\n-\n-\tif (output_eol(crlf_action) == EOL_LF) {\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_CRLF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n \t\t/*\n \t\t * CRLFs would not be restored by checkout:\n \t\t * check if we'd remove CRLFs\n \t\t */\n-\t\tif (stats->crlf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n-\t\t}\n-\t} else if (output_eol(crlf_action) == EOL_CRLF) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"CRLF will be replaced by LF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"CRLF would be replaced by LF in %s.\", path);\n+\t}\n+\tif (convert_stats & CONVERT_STAT_BITS_TXT_LF &&\n+\t    !(new_convert_stats & CONVERT_STAT_BITS_TXT_LF)) {\n \t\t/*\n \t\t * CRLFs would be added by checkout:\n \t\t * check if we have \"naked\" LFs\n \t\t */\n-\t\tif (stats->lonelf) {\n-\t\t\tif (checksafe == SAFE_CRLF_WARN)\n-\t\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n-\t\t\telse /* i.e. SAFE_CRLF_FAIL */\n-\t\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n-\t\t}\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"LF will be replaced by CRLF in %s.\\nThe file will have its original line endings in your working directory.\", path);\n+\t\telse /* i.e. SAFE_CRLF_FAIL */\n+\t\t\tdie(\"LF would be replaced by CRLF in %s\", path);\n+\t}\n+\tif ((new_convert_stats & CONVERT_STAT_BITS_MIXED) == CONVERT_STAT_BITS_MIXED)\n+\t\terr_warn_msg = \"mixed eol\";\n+\telse if (new_eol == EOL_LF && new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)\n+\t\terr_warn_msg = \"CRLF\";\n+\n+\tif (err_warn_msg) {\n+\t\tif (checksafe == SAFE_CRLF_WARN)\n+\t\t\twarning(\"%s will be present after commit and checkout in %s.\",\n+\t\t\t\terr_warn_msg, path);\n+\t\telse\n+\t\t\tdie(\"%s will be present after commit and checkout in %s\",\n+\t\t\t    err_warn_msg, path);\n \t}\n-}\n-\n-static int has_cr_in_index(const char *path)\n-{\n-\tunsigned convert_stats;\n-\tconvert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),\n-\t\t\t\t\t       CONVERT_STAT_BITS_ANY_CR);\n-\treturn convert_stats & CONVERT_STAT_BITS_ANY_CR;\n }\n \n static int crlf_to_git(const char *path, const char *src, size_t len,\n@@ -284,7 +325,7 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n {\n \tstruct text_stat stats;\n \tchar *dst;\n-\n+\tint convert_crlf;\n \tif (crlf_action == CRLF_BINARY ||\n \t    (src && !len))\n \t\treturn 0;\n@@ -296,24 +337,42 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (!buf && !src)\n \t\treturn 1;\n \n-\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n-\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n+\t\tgather_stats(src, len, &stats, CONVERT_STAT_BITS_BIN);\n \t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n \t\t\treturn 0;\n-\t\t/*\n-\t\t * If the file in the index has any CR in it, do not convert.\n-\t\t * This is the new safer autocrlf handling.\n-\t\t */\n-\t\tif (checksafe == SAFE_CRLF_RENORMALIZE)\n-\t\t\tchecksafe = SAFE_CRLF_FALSE;\n-\t\telse if (has_cr_in_index(path))\n-\t\t\treturn 0;\n+\t} else {\n+\t\tgather_stats(src, len, &stats, 0);\n+\t}\n+\tif (checksafe == SAFE_CRLF_RENORMALIZE) {\n+\t\tconvert_crlf = 1;\n+\t\tchecksafe = SAFE_CRLF_FALSE;\n+\t} else {\n+\t\tconvert_crlf = would_convert_crlf_at_commit(path, &stats, len,\n+\t\t\t\t\t\t\t    crlf_action);\n \t}\n-\tcheck_safe_crlf(path, crlf_action, &stats, checksafe);\n \n-\t/* Optimization: No CRLF? Nothing to convert, regardless. */\n-\tif (!stats.crlf)\n+\tif (checksafe) {\n+\t\tunsigned convert_stats = stats.stat_bits;\n+\t\tunsigned new_convert_stats = convert_stats;\n+\t\t/* Simulate commit */\n+\t\tif (convert_crlf &&\n+\t\t    (new_convert_stats & CONVERT_STAT_BITS_TXT_CRLF)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_LF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t}\n+\t\t/* Simulate checkout */\n+\t\tif (would_convert_lf_at_checkout(new_convert_stats,\n+\t\t\t\t\t\t len, crlf_action)) {\n+\t\t\tnew_convert_stats |= CONVERT_STAT_BITS_TXT_CRLF;\n+\t\t\tnew_convert_stats &= ~CONVERT_STAT_BITS_TXT_LF;\n+\t\t}\n+\t\tcheck_safe_crlf(path, crlf_action, checksafe,\n+\t\t\t\tconvert_stats, new_convert_stats);\n+\t}\n+\tif (!convert_crlf)\n \t\treturn 0;\n \n \t/*\n@@ -327,7 +386,9 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \tif (strbuf_avail(buf) + buf->len < len)\n \t\tstrbuf_grow(buf, len - buf->len);\n \tdst = buf->buf;\n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n+\tif (crlf_action == CRLF_AUTO ||\n+\t    crlf_action == CRLF_AUTO_INPUT ||\n+\t    crlf_action == CRLF_AUTO_CRLF) {\n \t\t/*\n \t\t * If we guessed, we already know we rejected a file with\n \t\t * lone CR, and we can strip a CR without looking at what\n@@ -354,28 +415,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n {\n \tchar *to_free = NULL;\n \tstruct text_stat stats;\n-\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n-\n-\n-\tif (!len || output_eol(crlf_action) != EOL_CRLF)\n+\tunsigned earlyout = 0; /* Need to count lonelf */\n+\tif (!len)\n \t\treturn 0;\n \n \tgather_stats(src, len, &stats, earlyout);\n-\n-\t/* No \"naked\" LF? Nothing to convert, regardless. */\n-\tif (!stats.lonelf)\n+\tif (!would_convert_lf_at_checkout(stats.stat_bits,\n+\t\t\t\t\t  len, crlf_action))\n \t\treturn 0;\n \n-\tif (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {\n-\t\t/* If we have any CR or CRLF line endings, we do not touch it */\n-\t\t/* This is the new safer autocrlf-handling */\n-\t\tif (stats.lonecr || stats.crlf )\n-\t\t\treturn 0;\n-\n-\t\tif (stats.stat_bits & CONVERT_STAT_BITS_BIN)\n-\t\t\treturn 0;\n-\t}\n-\n \t/* are we \"faking\" in place editing ? */\n \tif (src == buf->buf)\n \t\tto_free = strbuf_detach(buf, NULL);\n@@ -1067,6 +1115,8 @@ int is_null_stream_filter(struct stream_filter *filter)\n struct lf_to_crlf_filter {\n \tstruct stream_filter filter;\n \tunsigned has_held:1;\n+\tunsigned expanded_loneLF:1;\n+\tunsigned had_CRLF:1;\n \tchar held;\n };\n \n@@ -1107,7 +1157,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \t\t\tchar ch = input[i];\n \n \t\t\tif (ch == '\\n') {\n-\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\tif (!lf_to_crlf->had_CRLF) {\n+\t\t\t\t\toutput[o++] = '\\r';\n+\t\t\t\t\tlf_to_crlf->expanded_loneLF = 1;\n+\t\t\t\t}\n+\t\t\t\tif (was_cr)\n+\t\t\t\t\tlf_to_crlf->had_CRLF = 1;\n \t\t\t} else if (was_cr) {\n \t\t\t\t/*\n \t\t\t\t * Previous round saw CR and it is not followed\n@@ -1136,6 +1191,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,\n \n \t\t\twas_cr = 0;\n \t\t\toutput[o++] = ch;\n+\t\t\tif (lf_to_crlf->expanded_loneLF &&\n+\t\t\t    lf_to_crlf->had_CRLF) {\n+\t\t\t\t/*\n+\t\t\t\t * Mixed EOL, round trip not possible.\n+\t\t\t\t */\n+\t\t\t\treturn 1;\n+\t\t\t}\n+\n \t\t}\n \n \t\t*osize_p -= o;\ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex d0bee08..b5f93e2 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' '\n \ttest -z \"$LFonlydiff\" -a -z \"$CRLFonlydiff\" -a -z \"$LFwithNULdiff\"\n '\n \n-test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n+test_expect_success 'crlf=true causes a CRLF file not to be normalized' '\n \n \t# Backwards compatibility check\n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n-test_expect_success 'text=true causes a CRLF file to be normalized' '\n+test_expect_success 'text=true causes a CRLF file not to be normalized' '\n \n \trm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&\n \techo \"CRLFonly text\" > .gitattributes &&\n@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '\n \t# Note, \"normalized\" means that git will normalize it if added\n \thas_cr CRLFonly &&\n \tCRLFonlydiff=$(git diff CRLFonly) &&\n-\ttest -n \"$CRLFonlydiff\"\n+\ttest -z \"$CRLFonlydiff\"\n '\n \n test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' '\ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex e2be985..1f08912 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -71,10 +71,14 @@ check_warning () {\n \tcase \"$1\" in\n \tLF_CRLF) echo \"warning: LF will be replaced by CRLF\" >\"$2\".expect ;;\n \tCRLF_LF) echo \"warning: CRLF will be replaced by LF\" >\"$2\".expect ;;\n+\tCRLF)    echo \"warning: CRLF will be present after commit and checkout\" >\"$2\".expect ;;\n+\tmixed)   echo \"warning: mixed eol will be present after commit and checkout\" >\"$2\".expect ;;\n \t'')\t                                                 >\"$2\".expect ;;\n \t*) echo >&2 \"Illegal 1\": \"$1\" ; return false ;;\n \tesac\n-\tgrep \"will be replaced by\" \"$2\" | sed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" | uniq  >\"$2\".actual\n+\tegrep \"will be replaced by|will be present after commit\" \"$2\" |\n+\t\tsed -e \"s/\\(.*\\) in [^ ]*$/\\1/\" |\n+\t\tuniq  >\"$2\".actual\n \ttest_cmp \"$2\".expect \"$2\".actual\n }\n \n@@ -169,7 +173,7 @@ stats_ascii () {\n # Take none (=empty), one or two args\n # convert.c: eol=XX overrides text=auto\n attr_ascii () {\n-\tcase $1,$2 in\n+\tcase \"$1\",\"$2\" in\n \t-text,*)   echo \"-text\" ;;\n \ttext,)     echo \"text\" ;;\n \ttext,lf)   echo \"text eol=lf\" ;;\n@@ -349,10 +353,12 @@ then\n \tWILC=LF_CRLF\n \tWICL=\n \tWAMIX=LF_CRLF\n+\tPcrlf=\n else\n \tWILC=\n \tWICL=CRLF_LF\n \tWAMIX=CRLF_LF\n+\tPcrlf=CRLF\n fi\n \n #                         attr   LF        CRLF      CRLFmixLF LFmixCR   CRLFNUL\n@@ -392,31 +398,32 @@ test_expect_success 'commit files attr=crlf' '\n \tcommit_check_warn input \"crlf\" \"LF_CRLF\" \"\"        \"LF_CRLF\" \"LF_CRLF\" \"\"\n '\n \n-#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n+#                 attr    aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL\n commit_chk_wrnNNO \"\"      \"\"      false   \"\"        \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"\"      \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"\"      \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n+\n+commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"$Pcrlf\"  mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        CRLF      mixed       \"\"          \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$Pcrlf\"  mixed       \"$WILC\"     \"$Pcrlf\"\n+commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF      mixed       \"\"          CRLF\n+\n \n-commit_chk_wrnNNO \"auto\"  \"\"      false   \"$WILC\"   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      true    LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-commit_chk_wrnNNO \"auto\"  \"\"      input   \"\"        \"\"        \"\"          \"\"          \"\"\n for crlf in true false input\n do\n \tcommit_chk_wrnNNO -text \"\"      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text lf      $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n \tcommit_chk_wrnNNO -text crlf    $crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"       CRLF_LF    CRLF_LF      \"\"         CRLF_LF\n-\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-\tcommit_chk_wrnNNO auto  lf    \t$crlf   \"\"        \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO auto  crlf  \t$crlf   LF_CRLF   \"\"        \"\"          \"\"          \"\"\n-\tcommit_chk_wrnNNO text  lf    \t$crlf   \"\"       CRLF_LF    CRLF_LF     \"\"          CRLF_LF\n-\tcommit_chk_wrnNNO text  crlf  \t$crlf   LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO \"\"    lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO \"\"    crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n+\tcommit_chk_wrnNNO auto  lf      $crlf   \"\"        CRLF      mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO auto  crlf    $crlf   LF_CRLF   \"\"        mixed       \"\"          \"\"\n+\tcommit_chk_wrnNNO text  lf      $crlf   \"\"        CRLF      mixed       \"\"          CRLF\n+\tcommit_chk_wrnNNO text  crlf    $crlf   LF_CRLF   \"\"        mixed       LF_CRLF     \"\"\n done\n \n-commit_chk_wrnNNO \"text\"  \"\"      false   \"$WILC\"   \"$WICL\"   \"$WAMIX\"    \"$WILC\"     \"$WICL\"\n-commit_chk_wrnNNO \"text\"  \"\"      true    LF_CRLF   \"\"        LF_CRLF     LF_CRLF     \"\"\n-commit_chk_wrnNNO \"text\"  \"\"      input   \"\"        CRLF_LF   CRLF_LF     \"\"          CRLF_LF\n-\n test_expect_success 'create files cleanup' '\n \trm -f *.txt &&\n \tgit -c core.autocrlf=false reset --hard\n@@ -456,9 +463,9 @@ do\n \tcheck_in_repo_NNO auto  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n \tcheck_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n-\tcheck_in_repo_NNO text  \"\"     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n-\tcheck_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul\n+\tcheck_in_repo_NNO text  \"\"     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n+\tcheck_in_repo_NNO text  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul\n done\n ################################################################################\n # Check how files in the repo are changed when they are checked out\n@@ -479,12 +486,10 @@ done\n \n if test_have_prereq NATIVE_CRLF\n then\n-MIX_CRLF_LF=CRLF\n MIX_LF_CR=CRLF_mix_CR\n NL=CRLF\n LFNUL=CRLF_nul\n else\n-MIX_CRLF_LF=CRLF_mix_LF\n MIX_LF_CR=LF_mix_CR\n NL=LF\n LFNUL=LF_nul\n@@ -492,8 +497,7 @@ fi\n export CRLF_MIX_LF_CR MIX NL\n \n # Same handling with and without ident\n-#for id in \"\" ident\n-for id in \"\"\n+for id in \"\" ident\n do\n \tfor ceol in lf crlf native\n \tdo\n@@ -501,38 +505,38 @@ do\n \t\tdo\n \t\t\t# -text overrides core.autocrlf and core.eol\n \t\t\t# text and eol=crlf or eol=lf override core.autocrlf and core.eol\n-\t\t\tcheckout_files -text \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files -text \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files -text \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"\"     \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files \"-text\" \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t\t# text\n-\t\t\tcheckout_files text  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files text  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\t\tcheckout_files text    \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files text    \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t\t# currently the same as text, eol=XXX\n-\t\t\tcheckout_files auto  \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\t\tcheckout_files auto  \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto    \"$id\" \"lf\"   \"$crlf\" \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\t\tcheckout_files auto    \"$id\" \"crlf\" \"$crlf\" \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\tdone\n \n \t\t# core.autocrlf false, different core.eol\n-\t\tcheckout_files   \"\"    \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   \"\"      \"$id\" \"\"     false   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# core.autocrlf true\n-\t\tcheckout_files   \"\"    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   \"\"      \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text: core.autocrlf = true overrides core.eol\n-\t\tcheckout_files   auto  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files   text  \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n+\t\tcheckout_files   auto    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   text    \"$id\" \"\"     true    \"$ceol\"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n \t\t# text: core.autocrlf = input overrides core.eol\n-\t\tcheckout_files   text  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\t\tcheckout_files   auto  \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   text    \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\t\tcheckout_files   auto    \"$id\" \"\"     input   \"$ceol\"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t\t# text=auto + eol=XXX\n \tdone\n \t# text: core.autocrlf=false uses core.eol\n-\tcheckout_files     text  \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul\n-\tcheckout_files     text  \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     text    \"$id\" \"\"     false   crlf     CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul\n+\tcheckout_files     text    \"$id\" \"\"     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n \t# text: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     text  \"$id\" \"\"     false   \"\"       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n-\tcheckout_files     text  \"$id\" \"\"     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL\n+\tcheckout_files     text    \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  \"$MIX_LF_CR\" \"$LFNUL\"\n+\tcheckout_files     text    \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  \"$MIX_LF_CR\" \"$LFNUL\"\n \t# auto: core.autocrlf=false and core.eol unset(or native) uses native eol\n-\tcheckout_files     auto  \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n-\tcheckout_files     auto  \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto    \"$id\" \"\"     false   \"\"       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n+\tcheckout_files     auto    \"$id\" \"\"     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul\n done\n \n # Should be the last test case: remove some files from the worktree\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"285801","messageId":"1462601465-23690-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v9 5/6] t6038; use crlf on all platforms","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-05-07T06:11:05Z","receivedAt":"2016-05-07T06:11:05Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nt6038 uses different code, dependig if NATIVE_CRLF is set ot not.\nWhen the native line endings are LF, merge.renormalize is not tested very well.\nChange the test to always use CRLF by setting core.eol=crlf.\nAfter doing so, the test fails:\n\nrm '.gitattributes'\nrm 'control_file'\nrm 'file'\nrm 'inert_file'\nHEAD is now at 0d9ffb6 add line from b\nerror: addinfo_cache failed for path 'file'\nfile: unmerged (cbd69ec7cd12dd0989e853923867d94c8519aa52)\nfile: unmerged (ad55e240aeb42e0d9a0e18d6d8b02dd82ee3e527)\nfile: unmerged (99b633103c15c20cebebf821133ab526b0ff90b2)\nfatal: git write-tree failed to write a tree\nMerging:\n0d9ffb6 add line from b\nvirtual a\nfound 1 common ancestor:\n1c56df1 Initial\nAuto-merging file\nnot ok 4 - Merge addition of text=auto\n\nThis will be addressed in the next commit.\n---\n t/t6038-merge-text-auto.sh | 37 +++++++++++--------------------------\n 1 file changed, 11 insertions(+), 26 deletions(-)\n\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 33b77ee..0108ead 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -25,6 +25,7 @@ compare_files () {\n \n test_expect_success setup '\n \tgit config core.autocrlf false &&\n+\tgit config core.eol crlf &&\n \n \techo first line | append_cr >file &&\n \techo first line >control_file &&\n@@ -79,10 +80,8 @@ test_expect_success 'Merge after setting text=auto' '\n \tsame line\n \tEOF\n \n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\tappend_cr <expected >expected.temp &&\n-\t\tmv expected.temp expected\n-\tfi &&\n+\tappend_cr <expected >expected.temp &&\n+\tmv expected.temp expected &&\n \tgit config merge.renormalize true &&\n \tgit rm -fr . &&\n \trm -f .gitattributes &&\n@@ -97,10 +96,8 @@ test_expect_success 'Merge addition of text=auto' '\n \tsame line\n \tEOF\n \n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\tappend_cr <expected >expected.temp &&\n-\t\tmv expected.temp expected\n-\tfi &&\n+\tappend_cr <expected >expected.temp &&\n+\tmv expected.temp expected &&\n \tgit config merge.renormalize true &&\n \tgit rm -fr . &&\n \trm -f .gitattributes &&\n@@ -111,15 +108,9 @@ test_expect_success 'Merge addition of text=auto' '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \techo \"<<<<<<<\" >expected &&\n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\techo first line | append_cr >>expected &&\n-\t\techo same line | append_cr >>expected &&\n-\t\techo ======= | append_cr >>expected\n-\telse\n-\t\techo first line >>expected &&\n-\t\techo same line >>expected &&\n-\t\techo ======= >>expected\n-\tfi &&\n+\techo first line | append_cr >>expected &&\n+\techo same line | append_cr >>expected &&\n+\techo ======= | append_cr >>expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n@@ -135,15 +126,9 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \techo \"<<<<<<<\" >expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n-\tif test_have_prereq NATIVE_CRLF; then\n-\t\techo ======= | append_cr >>expected &&\n-\t\techo first line | append_cr >>expected &&\n-\t\techo same line | append_cr >>expected\n-\telse\n-\t\techo ======= >>expected &&\n-\t\techo first line >>expected &&\n-\t\techo same line >>expected\n-\tfi &&\n+\techo ======= | append_cr >>expected &&\n+\techo first line | append_cr >>expected &&\n+\techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n \tgit config merge.renormalize false &&\n \trm -f .gitattributes &&\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"285799","messageId":"1462601467-23741-1-git-send-email-tboegi@web.de","threadId":"41391","inReplyTo":"xmqqegblor2l.fsf@gitster.mtv.corp.google.com","subject":"[PATCH v9 6/6] convert: ce_compare_data() checks for a sha1 of a path","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-05-07T06:11:07Z","receivedAt":"2016-05-07T06:11:07Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nTo compare a file in working tree with the index, convert_to_git() is used,\nthe the result is hashed and the hash value compared with ce->sha1.\n\nDeep down would_convert_crlf_at_commit() is invoked, to check if CRLF\nare converted or not: When a CRLF had been in the index before, CRLF in\nthe working tree are not converted.\n\nWhile in a merge, a file name in the working tree has different blobs\nin the index with different hash values.\nForwarding ce->sha1 from ce_compare_data() into crlf_to_git() makes sure\nthe would_convert_crlf_at_commit() looks at the appropriate blob.\n---\n cache.h                    |  1 +\n convert.c                  | 30 ++++++++++++++++++++----------\n convert.h                  | 23 +++++++++++++++++++----\n read-cache.c               |  4 +++-\n sha1_file.c                | 17 +++++++++++++----\n t/t6038-merge-text-auto.sh | 12 ++++++------\n 6 files changed, 62 insertions(+), 25 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 28f23d7..43a4fd6 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -605,6 +605,7 @@ extern int ie_modified(const struct index_state *, const struct cache_entry *, s\n \n #define HASH_WRITE_OBJECT 1\n #define HASH_FORMAT_CHECK 2\n+#define HASH_CE_HAS_SHA1  4\n extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);\n extern int index_path(unsigned char *sha1, const char *path, struct stat *st, unsigned flags);\n \ndiff --git a/convert.c b/convert.c\nindex 8d4c42a..ccbd2e9 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -254,9 +254,8 @@ static int would_convert_lf_at_checkout(unsigned convert_stats,\n \n }\n \n-static int would_convert_crlf_at_commit(const char * path,\n+static int would_convert_crlf_at_commit(const unsigned char *sha1,\n \t\t\t\t\tconst struct text_stat *stats,\n-\t\t\t\t\tsize_t len,\n \t\t\t\t\tenum crlf_action crlf_action)\n {\n \tunsigned stat_bits_index;\n@@ -267,7 +266,7 @@ static int would_convert_crlf_at_commit(const char * path,\n \t * If the file in the index has any CRLF in it, do not convert.\n \t * This is the new safer autocrlf handling.\n \t */\n-\tstat_bits_index = get_convert_stats_sha1(get_sha1_from_cache(path),\n+\tstat_bits_index = get_convert_stats_sha1(sha1,\n \t\t\t\t\t\t CONVERT_STAT_BITS_TXT_CRLF);\n \tif (stat_bits_index & CONVERT_STAT_BITS_TXT_CRLF)\n \t\treturn 0;\n@@ -319,7 +318,8 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,\n \t}\n }\n \n-static int crlf_to_git(const char *path, const char *src, size_t len,\n+static int crlf_to_git(const char *path, const unsigned char *sha1,\n+\t\t       const char *src, size_t len,\n \t\t       struct strbuf *buf,\n \t\t       enum crlf_action crlf_action, enum safe_crlf checksafe)\n {\n@@ -350,7 +350,14 @@ static int crlf_to_git(const char *path, const char *src, size_t len,\n \t\tconvert_crlf = 1;\n \t\tchecksafe = SAFE_CRLF_FALSE;\n \t} else {\n-\t\tconvert_crlf = would_convert_crlf_at_commit(path, &stats, len,\n+\t\t/*\n+\t\t * If ce_compare_data() wants to check a specic blob,\n+\t\t * then sha1 != NULL and should be used\n+\t\t */\n+\t\tif (!sha1)\n+\t\t\tsha1 = get_sha1_from_cache(path);\n+\n+\t\tconvert_crlf = would_convert_crlf_at_commit(sha1, &stats,\n \t\t\t\t\t\t\t    crlf_action);\n \t}\n \n@@ -949,8 +956,9 @@ const char *get_convert_attr_ascii(const char *path)\n \treturn \"\";\n }\n \n-int convert_to_git(const char *path, const char *src, size_t len,\n-                   struct strbuf *dst, enum safe_crlf checksafe)\n+int convert_to_git_ce_sha1(const char *path, const unsigned char *sha1,\n+\t\t\t   const char *src, size_t len,\n+\t\t\t   struct strbuf *dst, enum safe_crlf checksafe)\n {\n \tint ret = 0;\n \tconst char *filter = NULL;\n@@ -971,7 +979,7 @@ int convert_to_git(const char *path, const char *src, size_t len,\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n \t}\n-\tret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe);\n+\tret |= crlf_to_git(path, sha1, src, len, dst, ca.crlf_action, checksafe);\n \tif (ret && dst) {\n \t\tsrc = dst->buf;\n \t\tlen = dst->len;\n@@ -979,7 +987,9 @@ int convert_to_git(const char *path, const char *src, size_t len,\n \treturn ret | ident_to_git(path, src, len, dst, ca.ident);\n }\n \n-void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n+void convert_to_git_filter_fd(const char *path,\n+\t\t\t      const unsigned char *sha1,\n+\t\t\t      int fd, struct strbuf *dst,\n \t\t\t      enum safe_crlf checksafe)\n {\n \tstruct conv_attrs ca;\n@@ -991,7 +1001,7 @@ void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,\n \tif (!apply_filter(path, NULL, 0, fd, dst, ca.drv->clean))\n \t\tdie(\"%s: clean filter '%s' failed\", path, ca.drv->name);\n \n-\tcrlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n+\tcrlf_to_git(path, sha1, dst->buf, dst->len, dst, ca.crlf_action, checksafe);\n \tident_to_git(path, dst->buf, dst->len, dst, ca.ident);\n }\n \ndiff --git a/convert.h b/convert.h\nindex 81b6cdf..769e9c9 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -38,8 +38,16 @@ extern const char *get_wt_convert_stats_ascii(const char *path);\n extern const char *get_convert_attr_ascii(const char *path);\n \n /* returns 1 if *dst was used */\n-extern int convert_to_git(const char *path, const char *src, size_t len,\n-\t\t\t  struct strbuf *dst, enum safe_crlf checksafe);\n+extern int convert_to_git_ce_sha1(const char *path, const unsigned char *sha1,\n+\t\t\t\t  const char *src, size_t len,\n+\t\t\t\t  struct strbuf *dst, enum safe_crlf checksafe);\n+\n+static inline int convert_to_git(const char *path, const char *src, size_t len,\n+\t\t\t\t struct strbuf *dst, enum safe_crlf checksafe)\n+{\n+\treturn convert_to_git_ce_sha1(path, NULL, src, len, dst, checksafe);\n+}\n+\n extern int convert_to_working_tree(const char *path, const char *src,\n \t\t\t\t   size_t len, struct strbuf *dst);\n extern int renormalize_buffer(const char *path, const char *src, size_t len,\n@@ -48,9 +56,16 @@ static inline int would_convert_to_git(const char *path)\n {\n \treturn convert_to_git(path, NULL, 0, NULL, 0);\n }\n+static inline int would_convert_to_git_ce_sha1(const char *path,\n+\t\t\t\t\t       const unsigned char *sha1)\n+{\n+\treturn convert_to_git_ce_sha1(path, sha1, NULL, 0, NULL, 0);\n+}\n+\n /* Precondition: would_convert_to_git_filter_fd(path) == true */\n-extern void convert_to_git_filter_fd(const char *path, int fd,\n-\t\t\t\t     struct strbuf *dst,\n+extern void convert_to_git_filter_fd(const char *path,\n+\t\t\t\t     const unsigned char *sha1,\n+\t\t\t\t     int fd, struct strbuf *dst,\n \t\t\t\t     enum safe_crlf checksafe);\n extern int would_convert_to_git_filter_fd(const char *path);\n \ndiff --git a/read-cache.c b/read-cache.c\nindex a3ef967..0ebc237 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -163,7 +163,9 @@ static int ce_compare_data(const struct cache_entry *ce, struct stat *st)\n \n \tif (fd >= 0) {\n \t\tunsigned char sha1[20];\n-\t\tif (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, 0))\n+\t\tunsigned flags = HASH_CE_HAS_SHA1;\n+\t\tmemcpy(sha1, ce->sha1, sizeof(sha1));\n+\t\tif (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, flags))\n \t\t\tmatch = hashcmp(sha1, ce->sha1);\n \t\t/* index_fd() closed the file descriptor already */\n \t}\ndiff --git a/sha1_file.c b/sha1_file.c\nindex d0f2aa0..dd013d5 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -3275,6 +3275,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,\n {\n \tint ret, re_allocated = 0;\n \tint write_object = flags & HASH_WRITE_OBJECT;\n+\tconst int valid_sha1 = flags & HASH_CE_HAS_SHA1;\n \n \tif (!type)\n \t\ttype = OBJ_BLOB;\n@@ -3284,8 +3285,11 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,\n \t */\n \tif ((type == OBJ_BLOB) && path) {\n \t\tstruct strbuf nbuf = STRBUF_INIT;\n-\t\tif (convert_to_git(path, buf, size, &nbuf,\n-\t\t\t\t   write_object ? safe_crlf : SAFE_CRLF_FALSE)) {\n+\t\tif (convert_to_git_ce_sha1(path,\n+\t\t\t\t\t   valid_sha1 ? sha1 : NULL,\n+\t\t\t\t\t   buf, size, &nbuf,\n+\t\t\t\t\t   write_object ? safe_crlf : SAFE_CRLF_FALSE)){\n+\n \t\t\tbuf = strbuf_detach(&nbuf, &size);\n \t\t\tre_allocated = 1;\n \t\t}\n@@ -3313,12 +3317,15 @@ static int index_stream_convert_blob(unsigned char *sha1, int fd,\n {\n \tint ret;\n \tconst int write_object = flags & HASH_WRITE_OBJECT;\n+\tconst int valid_sha1 = flags & HASH_CE_HAS_SHA1;\n \tstruct strbuf sbuf = STRBUF_INIT;\n \n \tassert(path);\n \tassert(would_convert_to_git_filter_fd(path));\n \n-\tconvert_to_git_filter_fd(path, fd, &sbuf,\n+\tconvert_to_git_filter_fd(path,\n+\t\t\t\t valid_sha1 ? sha1 : NULL,\n+\t\t\t\t fd, &sbuf,\n \t\t\t\t write_object ? safe_crlf : SAFE_CRLF_FALSE);\n \n \tif (write_object)\n@@ -3396,6 +3403,8 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st,\n \t     enum object_type type, const char *path, unsigned flags)\n {\n \tint ret;\n+\tconst unsigned char *sha1_ce;\n+\tsha1_ce = flags & HASH_CE_HAS_SHA1 ? sha1 : NULL;\n \n \t/*\n \t * Call xsize_t() only when needed to avoid potentially unnecessary\n@@ -3406,7 +3415,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st,\n \telse if (!S_ISREG(st->st_mode))\n \t\tret = index_pipe(sha1, fd, type, path, flags);\n \telse if (st->st_size <= big_file_threshold || type != OBJ_BLOB ||\n-\t\t (path && would_convert_to_git(path)))\n+\t\t (path && would_convert_to_git_ce_sha1(path,sha1_ce)))\n \t\tret = index_core(sha1, fd, xsize_t(st->st_size), type, path,\n \t\t\t\t flags);\n \telse\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 0108ead..5450cba 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -108,9 +108,9 @@ test_expect_success 'Merge addition of text=auto' '\n \n test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '\n \techo \"<<<<<<<\" >expected &&\n-\techo first line | append_cr >>expected &&\n-\techo same line | append_cr >>expected &&\n-\techo ======= | append_cr >>expected &&\n+\techo first line >>expected &&\n+\techo same line >>expected &&\n+\techo ======= >>expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n \techo \">>>>>>>\" >>expected &&\n@@ -126,9 +126,9 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '\n \techo \"<<<<<<<\" >expected &&\n \techo first line | append_cr >>expected &&\n \techo same line | append_cr >>expected &&\n-\techo ======= | append_cr >>expected &&\n-\techo first line | append_cr >>expected &&\n-\techo same line | append_cr >>expected &&\n+\techo =======  >>expected &&\n+\techo first line >>expected &&\n+\techo same line  >>expected &&\n \techo \">>>>>>>\" >>expected &&\n \tgit config merge.renormalize false &&\n \trm -f .gitattributes &&\n-- \n2.0.0.rc1.6318.g0c2c796\n"},{"id":"285966","messageId":"xmqqy47jt3b6.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1462601458-23498-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v9 1/6] read-cache: factor out get_sha1_from_index() helper","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-09T19:54:37Z","receivedAt":"2016-05-09T19:54:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> +#define get_sha1_from_cache(path)  get_sha1_from_index (&the_index, (path))\n>  #endif\n\nMicronit: lose the extra SP; i.e. \"get_sha1_from_index(&the_index, (path))\".\n\n> diff --git a/read-cache.c b/read-cache.c\n> index d9fb78b..a3ef967 100644\n> --- a/read-cache.c\n> +++ b/read-cache.c\n> @@ -2263,13 +2263,27 @@ int index_name_is_other(const struct index_state *istate, const char *name,\n>  \n>  void *read_blob_data_from_index(struct index_state *istate, const char *path, unsigned long *size)\n>  {\n> -\tint pos, len;\n> +\tconst unsigned char *sha1;\n>  \tunsigned long sz;\n>  \tenum object_type type;\n>  \tvoid *data;\n>  \n> -\tlen = strlen(path);\n> -\tpos = index_name_pos(istate, path, len);\n> +\tsha1 = get_sha1_from_index(istate, path);\n> +\tif (!sha1)\n> +\t\treturn NULL;\n> +\tdata = read_sha1_file(sha1, &type, &sz);\n> +\tif (!data || type != OBJ_BLOB) {\n> +\t\tfree(data);\n> +\t\treturn NULL;\n> +\t}\n> +\tif (size)\n> +\t\t*size = sz;\n> +\treturn data;\n> +}\n> +\n> +const unsigned char *get_sha1_from_index(struct index_state *istate, const char *path)\n> +{\n> +\tint pos = index_name_pos(istate, path, strlen(path));\n>  \tif (pos < 0) {\n>  \t\t/*\n>  \t\t * We might be in the middle of a merge, in which\n> @@ -2285,14 +2299,7 @@ void *read_blob_data_from_index(struct index_state *istate, const char *path, un\n>  \t}\n>  \tif (pos < 0)\n>  \t\treturn NULL;\n> +\treturn (istate->cache[pos]->sha1);\n\nMicronit: lose the extra () pair around what is returned.\n\nI wondered if we can share more code with this helper and\nget_sha1_with_context_1(), which is the canonical copy of this logic\nused to parse \":$path\" and get the object name at $path in the\nindex, but this is sufficiently low-level and such a refactoring\nof small code would not be of great benefit, so this patch is OK.\n\nThanks.\n\n>  }\n>  \n>  void stat_validity_clear(struct stat_validity *sv)\n"},{"id":"285970","messageId":"xmqqtwi7t1of.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"1462601460-23543-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v9 2/6] convert.c: stream and early out","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-05-09T20:29:52Z","receivedAt":"2016-05-09T20:29:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> +\t\tif (stats->stat_bits & earlyout)\n> +\t\t\tbreak; /* We found what we have been searching for */\n\nAre we sure if our callers are only interested in just one bit at a\ntime?  Otherwise, if we want to ensure all of the given bits are\nset,\n\n\tif ((stats->stat_bits & earlyout) == earlyout)\n        \tbreak;\n\nwould be necessary.  Otherwise, the \"only one bit\" assumption on the\n\"earlyout\" parameter somehow needs to be documented in the code.\n\n> +\t\tssize_t readlen = read(fd, buf, sizeof(buf));\n\nxread() to automatically retry an interrupted read?\n\n> @@ -309,11 +354,13 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,\n>  {\n>  \tchar *to_free = NULL;\n>  \tstruct text_stat stats;\n> +\tunsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;\n> +\n>  \n>  \tif (!len || output_eol(crlf_action) != EOL_CRLF)\n>  \t\treturn 0;\n>  \n> -\tgather_stats(src, len, &stats);\n> +\tgather_stats(src, len, &stats, earlyout);\n\nOops, this answers my earlier question, no?\n"},{"id":"286147","messageId":"eaf7b2e2-59d3-7b12-e9dd-d63203b05384@web.de","threadId":"41391","inReplyTo":"xmqqtwi7t1of.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v9 2/6] convert.c: stream and early out","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-05-11T04:30:51Z","receivedAt":"2016-05-11T04:30:51Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 09.05.16 22:29, Junio C Hamano wrote:\n> tboegi@web.de writes:\n> \n>> +\t\tif (stats->stat_bits & earlyout)\n>> +\t\t\tbreak; /* We found what we have been searching for */\n> \n> Are we sure if our callers are only interested in just one bit at a\n> time?  Otherwise, if we want to ensure all of the given bits are\n> set,\n> \n> \tif ((stats->stat_bits & earlyout) == earlyout)\n>         \tbreak;\n> \n> would be necessary.  Otherwise, the \"only one bit\" assumption on the\n> \"earlyout\" parameter somehow needs to be documented in the code.\nThanks for pointing that out.\nI have changed the code a couple of times, forth and back.\nI want to re-roll the series anyway (probably in the next weeks),\nso something like \"search_only_flags\" may be a better name.\n"},{"id":"306427","messageId":"5502e894-bb22-e8b9-ab7a-49346d238283@web.de","threadId":"41391","inReplyTo":"1461942123-16179-1-git-send-email-tboegi@web.de","subject":"Re: [PATCH v8 07/10] convert: unify the \"auto\" handling of CRLF","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2016-11-25T15:48:38Z","receivedAt":"2016-11-25T15:49:39Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"RFH, the normalization as descrived in Documentation/gitattributes.txt\ndoes not work anymore:\n\n\nFrom a clean working directory:\n\n-------------------------------------------------\n$ echo \"* text=auto\" >.gitattributes\n$ rm .git/index     # Remove the index to force Git to\n$ git reset         # re-scan the working directory\n$ git status        # Show files that will be normalized\n$ git add -u\n$ git add .gitattributes\n$ git commit -m \"Introduce end-of-line normalization\"\n-------------------------------------------------\n\n\nI have different ideas, how a a normalizatio  can be done:\n\nA) \n-------------------------------------------------\n$ echo \"* text=auto\" >.gitattributes\n$ rm .git/index\n$ git add .\n$ git status        # Show files that will be normalized\n$ git commit -m \"Introduce end-of-line normalization\"\n-------------------------------------------------\n\nB)\n$ echo \"* text=auto\" >.gitattributes &&\n$ git add .gitattributes &&\n$ git ls-files --eol | egrep '^i/(crlf|mixed).*attr/(text|auto)' | ( TAB=$(printf \"\\t\") ; sed -e \"s/.*$TAB/dos2unix /\" ) >/tmp/$$ &&\n$ /bin/sh /tmp/$$ &&\n$ rm -f /tmp/$$ &&\n$ git add -u &&\n$ git commit -m \"Introduce end-of-line normalization\"\n\nC) \nTeach \"git add\" to learn --renormalize and then\n-------------------------------------------------\n$ echo \"* text=auto\" >.gitattributes\n$ git add -u --renormalize\n$ git add .gitattributes\n$ git commit -m \"Introduce end-of-line normalization\"\n-------------------------------------------------\n\n(None of them is really tested)\n\nA) may loose the execute bit\nB) dos2unix is not installed everywhere (like Mac OS)\nC) seems to most attractive, but I couldn't find out how to forward\n   options from \"git add\" into convert.c\n\n\nAny help is appreciated.\n\n\n\n\n\n\n"},{"id":"306464","messageId":"20161127162245.11757-1-tboegi@web.de","threadId":"41391","inReplyTo":"5502e894-bb22-e8b9-ab7a-49346d238283@web.de","subject":"[PATCH/RFC v1 1/1] New way to normalize the line endings","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2016-11-27T16:22:45Z","receivedAt":"2016-11-27T16:23:00Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nSincec commit 6523728499e7 'convert: unify the \"auto\" handling of CRLF'\nthe normalization instruction in Documentation/gitattributes.txt\ndoesn't work any more.\n\nUpdate the documentation and add a test case.\n\nReported by Kristian Adrup\nhttps://github.com/git-for-windows/git/issues/954\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/gitattributes.txt |  7 +++----\n t/t0025-crlf-auto.sh            | 29 +++++++++++++++++++++++++++++\n 2 files changed, 32 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex 976243a..1f7529a 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -227,11 +227,10 @@ From a clean working directory:\n \n -------------------------------------------------\n $ echo \"* text=auto\" >.gitattributes\n-$ rm .git/index     # Remove the index to force Git to\n-$ git reset         # re-scan the working directory\n+$ git ls-files --eol | egrep \"i/(crlf|mixed)\" # find not normalized files\n+$ rm .git/index     # Remove the index to re-scan the working directory\n+$ git add .\n $ git status        # Show files that will be normalized\n-$ git add -u\n-$ git add .gitattributes\n $ git commit -m \"Introduce end-of-line normalization\"\n -------------------------------------------------\n \ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex d0bee08..4ad4d02 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -152,4 +152,33 @@ test_expect_success 'eol=crlf _does_ normalize binary files' '\n \ttest -z \"$LFwithNULdiff\"\n '\n \n+test_expect_success 'prepare unnormalized' '\n+\n+\t> .gitattributes &&\n+\tgit config core.autocrlf false &&\n+\tprintf \"LINEONE\\nLINETWO\\r\\n\"     >mixed &&\n+\tgit add mixed .gitattributes &&\n+\tgit commit -m \"Add mixed\" &&\n+\tgit ls-files --eol | egrep \"i/crlf\" &&\n+\tgit ls-files --eol | egrep \"i/mixed\"\n+\n+'\n+\n+test_expect_success 'normalize unnormalized' '\n+\techo \"* text=auto\" >.gitattributes &&\n+\trm .git/index &&\n+\tgit add . &&\n+\tgit commit -m \"Introduce end-of-line normalization\" &&\n+\tgit ls-files --eol | tr \"\\\\t\" \" \" | sort >act &&\n+cat >exp <<EOF &&\n+i/-text w/-text attr/text=auto         LFwithNUL\n+i/lf    w/crlf  attr/text=auto         CRLFonly\n+i/lf    w/crlf  attr/text=auto         LFonly\n+i/lf    w/lf    attr/text=auto         .gitattributes\n+i/lf    w/mixed attr/text=auto         mixed\n+EOF\n+\ttest_cmp exp act\n+\n+'\n+\n test_done\n-- \n2.10.0\n\n"},{"id":"306558","messageId":"xmqqshqaf67c.fsf@gitster.mtv.corp.google.com","threadId":"41391","inReplyTo":"20161127162245.11757-1-tboegi@web.de","subject":"Re: [PATCH/RFC v1 1/1] New way to normalize the line endings","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-11-29T19:15:35Z","receivedAt":"2016-11-29T19:15:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"tboegi@web.de writes:\n\n> From: Torsten Bögershausen <tboegi@web.de>\n>\n> Sincec commit 6523728499e7 'convert: unify the \"auto\" handling of CRLF'\n> the normalization instruction in Documentation/gitattributes.txt\n> doesn't work any more.\n\nAside from s/Sincec/Since/, the above made it sound as if the named\ncommit was a regression that wants to be reverted, at least to my\nfirst reading.  I think you want to be a bit more clear that we\nupdated the world order and made it a better place with that commit,\nand examples in the doc need to be updated.  To convince readers\nthat, I think you would need to explain things like why the old way\nillustrated in the example was bad, and why the new way is better.\n\n> Update the documentation and add a test case.\n>\n> Reported by Kristian Adrup\n> https://github.com/git-for-windows/git/issues/954\n>\n> Signed-off-by: Torsten Bögershausen <tboegi@web.de>\n> ---\n>  Documentation/gitattributes.txt |  7 +++----\n>  t/t0025-crlf-auto.sh            | 29 +++++++++++++++++++++++++++++\n>  2 files changed, 32 insertions(+), 4 deletions(-)\n>\n> diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\n> index 976243a..1f7529a 100644\n> --- a/Documentation/gitattributes.txt\n> +++ b/Documentation/gitattributes.txt\n> @@ -227,11 +227,10 @@ From a clean working directory:\n>  \n>  -------------------------------------------------\n>  $ echo \"* text=auto\" >.gitattributes\n> -$ rm .git/index     # Remove the index to force Git to\n> -$ git reset         # re-scan the working directory\n> +$ git ls-files --eol | egrep \"i/(crlf|mixed)\" # find not normalized files\n\nDoes this step help anything?  I do not see anything in the later\nsteps that the user uses the finding from the output of this step to\naffect the end result.\n\n> +$ rm .git/index     # Remove the index to re-scan the working directory\n> +$ git add .\n\n\"A clean working directory\" usually means all paths in the index\nmatch what's in the working tree but this requires a bit more than\nthat, as this step ends up adding untracked and unignored paths.\n\n>  $ git status        # Show files that will be normalized\n> -$ git add -u\n> -$ git add .gitattributes\n>  $ git commit -m \"Introduce end-of-line normalization\"\n>  -------------------------------------------------\n>  \n> diff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\n> index d0bee08..4ad4d02 100755\n> --- a/t/t0025-crlf-auto.sh\n> +++ b/t/t0025-crlf-auto.sh\n> @@ -152,4 +152,33 @@ test_expect_success 'eol=crlf _does_ normalize binary files' '\n>  \ttest -z \"$LFwithNULdiff\"\n>  '\n>  \n> +test_expect_success 'prepare unnormalized' '\n> +\n> +\t> .gitattributes &&\n\nLose SP before \".gitattributes\".\n\n> +\tgit config core.autocrlf false &&\n> +\tprintf \"LINEONE\\nLINETWO\\r\\n\"     >mixed &&\n> +\tgit add mixed .gitattributes &&\n> +\tgit commit -m \"Add mixed\" &&\n> +\tgit ls-files --eol | egrep \"i/crlf\" &&\n> +\tgit ls-files --eol | egrep \"i/mixed\"\n> +\n> +'\n\nAny particular reason why we must use egrep not grep here?\n\n> +\n> +test_expect_success 'normalize unnormalized' '\n> +\techo \"* text=auto\" >.gitattributes &&\n> +\trm .git/index &&\n> +\tgit add . &&\n> +\tgit commit -m \"Introduce end-of-line normalization\" &&\n> +\tgit ls-files --eol | tr \"\\\\t\" \" \" | sort >act &&\n> +cat >exp <<EOF &&\n> +i/-text w/-text attr/text=auto         LFwithNUL\n> +i/lf    w/crlf  attr/text=auto         CRLFonly\n> +i/lf    w/crlf  attr/text=auto         LFonly\n> +i/lf    w/lf    attr/text=auto         .gitattributes\n> +i/lf    w/mixed attr/text=auto         mixed\n> +EOF\n\nUse <<-EOF to indent the above 7 lines?\n\n> +\ttest_cmp exp act\n> +\n> +'\n> +\n>  test_done\n"},{"id":"316679","messageId":"20170412114809.31852-1-tboegi@web.de","threadId":"41391","inReplyTo":"5502e894-bb22-e8b9-ab7a-49346d238283@web.de","subject":"[PATCH v2 1/1] Document how to normalize the line endings","fromName":"","fromEmail":"tboegi@web.de","sentAt":"2017-04-12T11:48:09Z","receivedAt":"2017-04-12T11:48:19Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"From: Torsten Bögershausen <tboegi@web.de>\n\nThe instructions how to normalize the line endings should have been updated\nas part of commit 6523728499e 'convert: unify the \"auto\" handling of CRLF',\n(but that part never made it into the commit).\n\nUpdate the documentation in Documentation/gitattributes.txt\nand add a test case in t0025.\n\nReported by Kristian Adrup\nhttps://github.com/git-for-windows/git/issues/954\n\nSigned-off-by: Torsten Bögershausen <tboegi@web.de>\n---\n Documentation/gitattributes.txt |  6 ++----\n t/t0025-crlf-auto.sh            | 26 ++++++++++++++++++++++++++\n 2 files changed, 28 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex 976243a..3b76687 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -227,11 +227,9 @@ From a clean working directory:\n \n -------------------------------------------------\n $ echo \"* text=auto\" >.gitattributes\n-$ rm .git/index     # Remove the index to force Git to\n-$ git reset         # re-scan the working directory\n+$ rm .git/index     # Remove the index to re-scan the working directory\n+$ git add .\n $ git status        # Show files that will be normalized\n-$ git add -u\n-$ git add .gitattributes\n $ git commit -m \"Introduce end-of-line normalization\"\n -------------------------------------------------\n \ndiff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh\nindex d0bee08..89826c5 100755\n--- a/t/t0025-crlf-auto.sh\n+++ b/t/t0025-crlf-auto.sh\n@@ -152,4 +152,30 @@ test_expect_success 'eol=crlf _does_ normalize binary files' '\n \ttest -z \"$LFwithNULdiff\"\n '\n \n+test_expect_success 'prepare unnormalized' '\n+\t> .gitattributes &&\n+\tgit config core.autocrlf false &&\n+\tprintf \"LINEONE\\nLINETWO\\r\\n\"     >mixed &&\n+\tgit add mixed .gitattributes &&\n+\tgit commit -m \"Add mixed\" &&\n+\tgit ls-files --eol | egrep \"i/crlf\" &&\n+\tgit ls-files --eol | egrep \"i/mixed\"\n+'\n+\n+test_expect_success 'normalize unnormalized' '\n+\techo \"* text=auto\" >.gitattributes &&\n+\trm .git/index &&\n+\tgit add . &&\n+\tgit commit -m \"Introduce end-of-line normalization\" &&\n+\tgit ls-files --eol | tr \"\\\\t\" \" \" | sort >act &&\n+cat >exp <<EOF &&\n+i/-text w/-text attr/text=auto         LFwithNUL\n+i/lf    w/crlf  attr/text=auto         CRLFonly\n+i/lf    w/crlf  attr/text=auto         LFonly\n+i/lf    w/lf    attr/text=auto         .gitattributes\n+i/lf    w/mixed attr/text=auto         mixed\n+EOF\n+\ttest_cmp exp act\n+'\n+\n test_done\n-- \n2.10.0\n\n"}]}