From: Junio C Hamano <hidden> Date: 2016-06-15 23:08:39
Torsten Bögershausen [off-list ref] writes:
The major question, at least on my side, is where to hook in
"can_clobber()" ?
There are different ways the existing commands ensure that they do
not lose local modifications.
* Some (like unpack-trees code that is used by "merge") do
refresh_cache() upfront and then ask ce_uptodate() if the
contents in the working tree match the indexed contents.
unpack-trees.c::verify_uptodate_1() has a call to ce_uptodate()
and returns early when true (i.e. if "git add" would result in
the same index entry), but then does a double-check with
ie_match_stat(), which essentially asks the "does an add result
in the same index entry?" again.
* Others (like apply) do not do the tree-wide refresh_cache(), but
asks "does an add result in the same index entry" by calling
ce_match_stat(), which is a thin wrapper to ie_match_stat(), in
builtin/apply.c::verify_index_match().
These places need to learn that there is a case where
ie_match_stat() says "'git add' would change the index, i.e. working
tree file is different" but the working tree file can still be
clobbered because 'checkout' would produce the same contents in the
working tree.
But stepping back a bit, I no longer am sure if such a loosening is
desirable. Imagine that you implemented such loosening and allowed
a patch to be applied to the index (and the result checked out to
the working tree). What would the result of "diff --cached" be
after doing so? Would it contain only the change described in the
patch you just accepted? If that is the case, it would be OK, but
if the change from the patch gets mixed with the "fix incorrectly
recorded data in the index" change that you would have recorded if
you did "git add" from the working tree without applying the patch,
then that would not be a desirable outcome, I would suspect. You
would rather want to first commit the "fix incorrectly recorded data
in the index" as a separate preparatory step and then want to apply
the patch. So...
From: Torsten Bögershausen <redacted>
Factor out the retrival of the sha1 for a given path in
read_blob_data_from_index() into the function get_sha1_from_index().
This will be used in the next commit, when convert.c can do the analyze
for "text=auto" without slurping the whole blob into memory at once.
Add a wrapper definition get_sha1_from_cache().
Signed-off-by: Torsten Bögershausen <redacted>
---
cache.h | 3 +++
read-cache.c | 29 ++++++++++++++++++-----------
2 files changed, 21 insertions(+), 11 deletions(-)
From: Torsten Bögershausen <redacted>
When statistics are done for the autocrlf handling, the search in
the content can be stopped, if e.g
- a search for binary is done, and a NUL character is found
- a search for CRLF is done, and the first CRLF is found.
Similar when statistics for binary vs non-binary are gathered:
Whenever a lone CR or NUL is found, the search can be aborted.
When checking out files in "auto" mode, any file that has a "lone CR"
or a CRLF will not be converted, so the search can be aborted early.
Add the new bit, CONVERT_STAT_BITS_ANY_CR,
which is set for either lone CR or CRLF.
Many binary files have a NUL very early (within the first few bytes,
latest within the first 1..2K).
It is often not necessary to load the whole content of a file or blob
into memory.
Use a streaming handling for blobs and files in the worktree.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 162 ++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 106 insertions(+), 56 deletions(-)
@@ -13,10 +14,10 @@*translationwhenthe"text"attributeor"auto_crlf"optionisset.*/-/* Stat bits: When BIN is set, the txt bits are unset */#define CONVERT_STAT_BITS_TXT_LF 0x1#define CONVERT_STAT_BITS_TXT_CRLF 0x2#define CONVERT_STAT_BITS_BIN 0x4+#define CONVERT_STAT_BITS_ANY_CR 0x8enumcrlf_action{CRLF_UNDEFINED,
@@ -31,30 +32,36 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignednul,lonecr,lonelf,crlf;+unsignedstat_bits,lonecr,lonelf,crlf;/* These are just approximations! */unsignedprintable,nonprintable;};-staticvoidgather_stats(constchar*buf,unsignedlongsize,structtext_stat*stats)+staticvoiddo_gather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout){unsignedlongi;-memset(stats,0,sizeof(*stats));-+if(!buf||!size)+return;for(i=0;i<size;i++){unsignedcharc=buf[i];if(c=='\r'){+stats->stat_bits|=CONVERT_STAT_BITS_ANY_CR;if(i+1<size&&buf[i+1]=='\n'){stats->crlf++;i++;-}else+stats->stat_bits|=CONVERT_STAT_BITS_TXT_CRLF;+}else{stats->lonecr++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}continue;}if(c=='\n'){stats->lonelf++;+stats->stat_bits|=CONVERT_STAT_BITS_TXT_LF;continue;}if(c==127)
@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats->printable++;break;case0:-stats->nul++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;/* fall through */default:stats->nonprintable++;
@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *}elsestats->printable++;+if(stats->stat_bits&earlyout)+break;/* We found what we have been searching for */}/* If file ends with EOF then don't count this EOF as non-printable. */
@@ -86,41 +95,63 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat **Thesameheuristicsasdiff.c::mmfile_is_binary()*WetreatfileswithbareCRasbinary*/-staticintconvert_is_binary(unsignedlongsize,conststructtext_stat*stats)+staticvoidconvert_nonprintable(structtext_stat*stats){-if(stats->lonecr)-return1;-if(stats->nul)-return1;if((stats->printable>>7)<stats->nonprintable)-return1;-return0;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}++staticvoidgather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout)+{+memset(stats,0,sizeof(*stats));+do_gather_stats(buf,size,stats,earlyout);+convert_nonprintable(stats);}-staticunsignedintgather_convert_stats(constchar*data,unsignedlongsize)++staticunsignedget_convert_stats_sha1(constchar*path,+unsignedconstchar*sha1,+unsignedearlyout){+structgit_istream*st;structtext_statstats;-intret=0;-if(!data||!size)-return0;-gather_stats(data,size,&stats);-if(convert_is_binary(size,&stats))-ret|=CONVERT_STAT_BITS_BIN;-if(stats.crlf)-ret|=CONVERT_STAT_BITS_TXT_CRLF;-if(stats.lonelf)-ret|=CONVERT_STAT_BITS_TXT_LF;+enumobject_typetype;+unsignedlongsz;-returnret;+if(!sha1)+return0;+memset(&stats,0,sizeof(stats));+st=open_istream(sha1,&type,&sz,NULL);+if(!st){+return0;+}+if(type!=OBJ_BLOB)+gotoclose_and_exit_i;+for(;;){+charbuf[1024];+ssize_treadlen=read_istream(st,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close_and_exit_i:+close_istream(st);+convert_nonprintable(&stats);+returnstats.stat_bits;}-staticconstchar*gather_convert_stats_ascii(constchar*data,unsignedlongsize)+staticconstchar*convert_stats_ascii(unsignedconvert_stats){-unsignedintconvert_stats=gather_convert_stats(data,size);-+unsignedmask=CONVERT_STAT_BITS_TXT_LF|+CONVERT_STAT_BITS_TXT_CRLF;if(convert_stats&CONVERT_STAT_BITS_BIN)return"-text";-switch(convert_stats){+switch(convert_stats&mask){caseCONVERT_STAT_BITS_TXT_LF:return"lf";caseCONVERT_STAT_BITS_TXT_CRLF:
@@ -132,24 +163,46 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si}}+staticunsignedget_convert_stats_wt(constchar*path)+{+structtext_statstats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+intfd;+memset(&stats,0,sizeof(stats));+fd=open(path,O_RDONLY);+if(fd<0)+return0;+for(;;){+charbuf[1024];+ssize_treadlen=read(fd,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close(fd);+convert_nonprintable(&stats);+returnstats.stat_bits;+}+constchar*get_cached_convert_stats_ascii(constchar*path){-constchar*ret;-unsignedlongsz;-void*data=read_blob_data_from_cache(path,&sz);-ret=gather_convert_stats_ascii(data,sz);-free(data);-returnret;+unsignedconvert_stats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+convert_stats=get_convert_stats_sha1(path,+get_sha1_from_cache(path),+earlyout);+returnconvert_stats_ascii(convert_stats);}constchar*get_wt_convert_stats_ascii(constchar*path){-constchar*ret="";-structstrbufsb=STRBUF_INIT;-if(strbuf_read_file(&sb,path,0)>=0)-ret=gather_convert_stats_ascii(sb.buf,sb.len);-strbuf_release(&sb);-returnret;+unsignedconvert_stats;+convert_stats=get_convert_stats_wt(path);+returnconvert_stats_ascii(convert_stats);}staticinttext_eol_is_crlf(void)
From: Torsten Bögershausen <redacted>
Commit 942e77 "Add "core.eol" config variable" adds a condition to
the config parser: core.autocrlf=input is not allowed together with
core.eol=crlf.
This may lead to unnecessary problems, when config files are parsed:
A global config file sets core.autocrlf=input,
the repo local config file sets is own configuration: core.eol=crlf
There is no need to prevent combinations in config.c, in any case
core.autocrlf overrides core.eol.
Allow all combinations of core.crlf and core.eol and document
that core.autocrlf overrides core.eol.
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 6 +++---
config.c | 4 ----
2 files changed, 3 insertions(+), 7 deletions(-)
@@ -337,9 +337,9 @@ core.quotePath:: core.eol:: Sets the line ending type to use in the working directory for- files that have the `text` property set. Alternatives are- 'lf', 'crlf' and 'native', which uses the platform's native- line ending. The default value is `native`. See+ files that have the `text` property set when core.autocrlf is false.+ Alternatives are 'lf', 'crlf' and 'native', which uses the platform's+ native line ending. The default value is `native`. See linkgit:gitattributes[5] for more information on end-of-line conversion.
From: Torsten Bögershausen <redacted>
Add more test cases for the not normalized files ("NNO").
The "text" attribute is most important, use it as the first parameter.
"ident", if set, is the second paramater followed by the eol attribute.
The eol attribute overrides core.autocrlf, which overrides core.eol.
Use loops to test more combinations of attributes, like
"* text eol=crlf" or especially "*text=auto eol=crlf".
Currently "* text=auto eol=lf" does the same as "* text eol=lf", as the
eol attribute overrides "text=auto", this will change in future.
Signed-off-by: Torsten Bögershausen <redacted>
---
t/t0027-auto-crlf.sh | 321 +++++++++++++++++++++++++--------------------------
1 file changed, 158 insertions(+), 163 deletions(-)
@@ -100,16 +103,17 @@ commit_check_warn () {} commit_chk_wrnNNO(){-crlf=$1-attr=$2-lfwarn=$3-crlfwarn=$4-lfmixcrlf=$5-lfmixcr=$6-crlfnul=$7-pfx=NNO_${crlf}_attr_${attr}+attr=$1;shift+aeol=$1;shift+crlf=$1;shift+lfwarn=$1;shift+crlfwarn=$1;shift+lfmixcrlf=$1;shift+lfmixcr=$1;shift+crlfnul=$1;shift+pfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}#Commit files on top of existing file-create_gitattributes"$attr"&&+create_gitattributes"$attr"$aeol&&forfinLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldofname=${pfx}_$f.txt&&
@@ -162,6 +166,7 @@ stats_ascii () {# contruct the attr/ returned by git ls-files --eol# Take none (=empty), one or two args+# convert.c: eol=XX overrides text=auto attr_ascii(){case$1,$2in-text,*)echo"-text";;
@@ -440,24 +446,20 @@ test_expect_success 'commit -text' 'check_files_in_repoinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul'-# attr LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL-check_in_repo_NNOfalse""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"auto"LFLFLFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtrue"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOinput"text"LFLFLFLF_mix_CRLF_nul--check_in_repo_NNOfalse"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--+forcrlfintruefalseinput;+do+# attr aeol LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL+check_in_repo_NNO""""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-text""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOauto""$crlfLFLFLFLF_mix_CRCRLF_nul+check_in_repo_NNOautolf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOautocrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+done################################################################################# Check how files in the repo are changed when they are checked out# How to read the table below:
@@ -489,89 +491,82 @@ LFNUL=LF_nulfiexportCRLF_MIX_LF_CRMIXNL-checkout_files""""""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""true""CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truecrlfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truelfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truenativeCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""true""CRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truelfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truenativeCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-+# Same handling with and without identforidin""ident;do-checkout_files"crlf""$id"""false""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falselfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""input""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""inputlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"lf""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"-text""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# -text overrides core.autocrlf and core.eol+# text and eol=crlf or eol=lf override core.autocrlf and core.eol+forcrlfintruefalseinput;+do+forceolin""lfcrlfnative;+do+checkout_files"-text""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"text""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"text""$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+done+done+# text: core.autocrlf=false uses core.eol+checkout_files"text""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_files"text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_files"text""$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_files"text""$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_files"auto""$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_files"auto""$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL++forceolin""lfcrlfnative;+do+# text: core.autocrlf = true overrides core.eol+checkout_files"text""$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# text: core.autocrlf = input overrides core.eol+checkout_files"text""$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+done+# No text attr+forceolin""lfcrlfnative;+do+# core.autocrlf!=true gives LF (or mixed) at checkout+forcrlfinfalseinput;+do+checkout_files"""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+done+done+done++#Handling without ident+foridin"";+do+forceolin""lfcrlfnative;+do+# core.autocrlf=true+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""true"$ceol"CRLFCRLFCRLFLF_mix_CRLF_nul+# text=auto + eol=XXX+# currently the same as text, eol=XXX+checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+done+done++#Handling with ident+foridinident;+do+forcrlfin""truefalseinput;+do+forceolin""lfcrlfnative;+do+# ident does not react on core.autocrlf=true+checkout_files"""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# ident does not react on text=auto+checkout_files"auto""$id"""true"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text=auto + eol=XXX+# currently the same as text, eol=XXX+checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+done+donedone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
A follow-up after a discussion how to fix the flaky execution
of t0025, gmane/$284352.
This patch extends the work done in commit c480539:
"Make it work also for un-normalized repositories". Make sure that CRLF
can be converted round trip, or don't convert them at all.
The old handling would treat a file as unchanged after checkout,
as long as it is not touched in the work tree and mtime matches the value
recorded in the index.
When the mtime is changed in the working tree, or the inode is changed,
the file is reported as modified.
The following sequence is now handled reproducable:
$ git init
$ printf "line1\r\n" >file.bat
$ git add file.bat
$ git commit -m "Add file with CRLF" file.bat
$ echo "*.bat text eol=crlf" >.gitattributes
$ git commit -m "bat files should have CRLF"
$ git status
# nothing to commit, working directory clean
$ git push <upstream>
$ printf "newline\r\n" >>file.bat
$ mv file.bat file.sav
$ git checkout file.bat
$ git status
#modified: file.bat
The new handling makes sure that after running "git reset --hard".
"git status" reports the working tree as clean regarding CRLF conversion.
It makes sure that the Git-internal eol conversion is
doing roundtrip. A user can still write an external smudge/clean filter
outside Git, which doesn't do a roundtrip and the working directory is
not clean.
The functionality of has_cr_in_index() is turned into has_crlf_in_index(),
and the function is integrated into would_convert_crlf_at_commit().
Check for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR
is no longer used and removed, as well as "lonecr" in struct text_stat.
Rewrite check_safe_crlf() in convert.c to simulate checkin-checkout,
to detect whether any line endings are converted.
Modify the lf_to_crlf_filter:
Files with LF are converted into CRLF, file with CRLF are not changed.
Files with mixed line endings are not converted, the filter fails, and Git
falls back to the non-streaming handling, see write_entry().
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/gitattributes.txt | 10 +-
convert.c | 215 ++++++++++++++++++++++++----------------
t/t0025-crlf-auto.sh | 8 +-
t/t0027-auto-crlf.sh | 38 +++----
4 files changed, 158 insertions(+), 113 deletions(-)
@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'. `text` ^^^^^^-This attribute enables and controls end-of-line normalization. When a+This attribute enables and controls end-of-line conversion. When a text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the
@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol` Set:: Setting the `text` attribute on a path enables end-of-line- normalization and marks the path as a text file. End-of-line+ conversion and marks the path as a text file. End-of-line conversion takes place without guessing the content type.+ Files that have been commited with CRLF before the text attribute+ is set and commited are not normalized. No end-of-line conversion+ is done at checkout or checkin. Unset::
@@ -132,7 +135,8 @@ Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic end-of-line normalization. If Git decides that the content is- text, its line endings are normalized to LF on checkin.+ text, and the path has no CRLF in the index,+ its line endings are converted to LF on checkin. Unspecified::
@@ -32,7 +31,7 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignedstat_bits,lonecr,lonelf,crlf;+unsignedstat_bits,lonelf;/* These are just approximations! */unsignedprintable,nonprintable;
@@ -136,7 +132,7 @@ static unsigned get_convert_stats_sha1(const char *path,if(!readlen)break;do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);-if(stats.stat_bits&earlyout)+if((stats.stat_bits&earlyout)==earlyout)break;/* We found what we have been searching for */}close_and_exit_i:
@@ -241,53 +228,90 @@ static enum eol output_eol(enum crlf_action crlf_action)returncore_eol;}+staticintwould_convert_lf_at_checkout(unsignedconvert_stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+if(output_eol(crlf_action)!=EOL_CRLF)+return0;++/* No "naked" LF? Nothing to convert, regardless. */+if(!convert_stats&CONVERT_STAT_BITS_TXT_LF)+return0;++if(crlf_action==CRLF_AUTO||+crlf_action==CRLF_AUTO_INPUT||+crlf_action==CRLF_AUTO_CRLF){+/* auto: binary files are not converted */+if(convert_stats&CONVERT_STAT_BITS_BIN)+return0;+}+/* If we have any CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;++}++staticintwould_convert_crlf_at_commit(constchar*path,+conststructtext_stat*stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+unsignedstat_bits_index;+/* No CRLF? Nothing to convert, regardless. */+if(!(stats->stat_bits&CONVERT_STAT_BITS_TXT_CRLF))+return0;+/*+*IfthefileintheindexhasanyCRLFinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+stat_bits_index=get_convert_stats_sha1(path,+get_sha1_from_cache(path),+CONVERT_STAT_BITS_TXT_CRLF);+if(stat_bits_index&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;+}+staticvoidcheck_safe_crlf(constchar*path,enumcrlf_actioncrlf_action,-structtext_stat*stats,enumsafe_crlfchecksafe)+enumsafe_crlfchecksafe,+unsignedconvert_stats,unsignednew_convert_stats){if(!checksafe)return;--if(output_eol(crlf_action)==EOL_LF){+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)){/**CRLFswouldnotberestoredbycheckout:*checkifwe'dremoveCRLFs*/-if(stats->crlf){-if(checksafe==SAFE_CRLF_WARN)-warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("CRLF would be replaced by LF in %s.",path);-}-}elseif(output_eol(crlf_action)==EOL_CRLF){+if(checksafe==SAFE_CRLF_WARN)+warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("CRLF would be replaced by LF in %s.",path);+}+if(convert_stats&CONVERT_STAT_BITS_TXT_LF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_LF)){/**CRLFswouldbeaddedbycheckout:*checkifwehave"naked"LFs*/-if(stats->lonelf){-if(checksafe==SAFE_CRLF_WARN)-warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("LF would be replaced by CRLF in %s",path);-}+if(checksafe==SAFE_CRLF_WARN)+warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("LF would be replaced by CRLF in %s",path);}}-staticinthas_cr_in_index(constchar*path)-{-unsignedconvert_stats;-convert_stats=get_convert_stats_sha1(path,-get_sha1_from_cache(path),-CONVERT_STAT_BITS_ANY_CR);-returnconvert_stats&CONVERT_STAT_BITS_ANY_CR;-}-staticintcrlf_to_git(constchar*path,constchar*src,size_tlen,structstrbuf*buf,enumcrlf_actioncrlf_action,enumsafe_crlfchecksafe){structtext_statstats;char*dst;-+intconvert_crlf;if(crlf_action==CRLF_BINARY||(src&&!len))return0;
@@ -299,23 +323,36 @@ static int crlf_to_git(const char *path, const char *src, size_t len,if(!buf&&!src)return1;-gather_stats(src,len,&stats,CONVERT_STAT_BITS_BIN);--if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){+if(crlf_action==CRLF_AUTO||+crlf_action==CRLF_AUTO_INPUT||+crlf_action==CRLF_AUTO_CRLF){+gather_stats(src,len,&stats,CONVERT_STAT_BITS_BIN);if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;-/*-*IfthefileintheindexhasanyCRinit,donotconvert.-*Thisisthenewsaferautocrlfhandling.-*/-if(has_cr_in_index(path))-return0;+}else{+gather_stats(src,len,&stats,0);}--check_safe_crlf(path,crlf_action,&stats,checksafe);--/* Optimization: No CRLF? Nothing to convert, regardless. */-if(!stats.crlf)+convert_crlf=would_convert_crlf_at_commit(path,&stats,len,+crlf_action);+if(checksafe){+unsignedconvert_stats=stats.stat_bits;+unsignednew_convert_stats=convert_stats;+/* Simulate commit */+if(convert_crlf&&+(new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)){+new_convert_stats|=CONVERT_STAT_BITS_TXT_LF;+new_convert_stats&=~CONVERT_STAT_BITS_TXT_CRLF;+}+/* Simulate checkout */+if(would_convert_lf_at_checkout(new_convert_stats,+len,crlf_action)){+new_convert_stats|=CONVERT_STAT_BITS_TXT_CRLF;+new_convert_stats&=~CONVERT_STAT_BITS_TXT_LF;+}+check_safe_crlf(path,crlf_action,checksafe,+convert_stats,new_convert_stats);+}+if(!convert_crlf)return0;/*
@@ -356,28 +395,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,{char*to_free=NULL;structtext_statstats;-unsignedearlyout=CONVERT_STAT_BITS_TXT_CRLF|CONVERT_STAT_BITS_BIN;---if(!len||output_eol(crlf_action)!=EOL_CRLF)+unsignedearlyout=0;/* Need to count lonelf */+if(!len)return0;gather_stats(src,len,&stats,earlyout);--/* No "naked" LF? Nothing to convert, regardless. */-if(!stats.lonelf)+if(!would_convert_lf_at_checkout(stats.stat_bits,+len,crlf_action))return0;-if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;--if(stats.stat_bits&CONVERT_STAT_BITS_BIN)-return0;-}-/* are we "faking" in place editing ? */if(src==buf->buf)to_free=strbuf_detach(buf,NULL);
@@ -1079,6 +1105,8 @@ int is_null_stream_filter(struct stream_filter *filter)structlf_to_crlf_filter{structstream_filterfilter;unsignedhas_held:1;+unsignedexpanded_loneLF:1;+unsignedhad_CRLF:1;charheld;};
@@ -1119,7 +1147,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,charch=input[i];if(ch=='\n'){-output[o++]='\r';+if(!lf_to_crlf->had_CRLF){+output[o++]='\r';+lf_to_crlf->expanded_loneLF=1;+}+if(was_cr)+lf_to_crlf->had_CRLF=1;}elseif(was_cr){/**PreviousroundsawCRanditisnotfollowed
@@ -1148,6 +1181,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,was_cr=0;output[o++]=ch;+if(lf_to_crlf->expanded_loneLF&&+lf_to_crlf->had_CRLF){+/*+*MixedEOL,roundtripnotpossible.+*/+return1;+}+}*osize_p-=o;
@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' 'test-z"$LFonlydiff"-a-z"$CRLFonlydiff"-a-z"$LFwithNULdiff"'-test_expect_success'crlf=true causes a CRLF file to be normalized''+test_expect_success'crlf=true causes a CRLF file not to be normalized''# Backwards compatibility checkrm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&
@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"'-test_expect_success'text=true causes a CRLF file to be normalized''+test_expect_success'text=true causes a CRLF file not to be normalized''rm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&echo"CRLFonly text">.gitattributes&&
@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"' test_expect_success'eol=crlf gives a normalized file CRLFs with autocrlf=false''
@@ -455,9 +457,9 @@ docheck_in_repo_NNOauto""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautolf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautocrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldone################################################################################# Check how files in the repo are changed when they are checked out
From: Torsten Bögershausen <redacted>
git blame reports lines as not "Not Committed Yet" when they have
CRLF in the index, CRLF in the worktree and e.g. core.autocrlf is true.
Since commit c48053 "new safer autocrlf handling", files that have CRLF
in the index are not normalized at commit when e.g. core.autocrl is set.
Whenever a CLRF conversion is needed (or any filter us set), load the
index temporally, before calling convert_to_git()
Signed-off-by: Torsten Bögershausen <redacted>
---
builtin/blame.c | 6 +++++-
convert.c | 10 ++++++++++
convert.h | 1 +
t/t8003-blame-corner-cases.sh | 14 ++++++++++++++
4 files changed, 30 insertions(+), 1 deletion(-)
@@ -35,6 +35,7 @@ extern enum eol core_eol;externconstchar*get_cached_convert_stats_ascii(constchar*path);externconstchar*get_wt_convert_stats_ascii(constchar*path);externconstchar*get_convert_attr_ascii(constchar*path);+intconvert_needs_conversion(constchar*path);/* returns 1 if *dst was used */externintconvert_to_git(constchar*path,constchar*src,size_tlen,
@@ -389,14 +389,15 @@ file with mixed line endings would be reported by the `core.safecrlf` mechanism. core.autocrlf::- Setting this variable to "true" is almost the same as setting- the `text` attribute to "auto" on all files except that text- files are not guaranteed to be normalized: files that contain+ Setting this variable to "true" is the same as setting+ the attributes to "auto eol=crlf" on all files.+ Files are not guaranteed to be normalized: files that contain `CRLF` in the repository will not be touched. Use this setting if you want to have `CRLF` line endings in your- working directory even though the repository does not have- normalized line endings. This variable can be set to 'input',+ working directory and he repository has normalized line endings.+ This variable can be set to 'input', in which case no output conversion is performed.+ Note: older versions of Git behave different. core.symlinks:: If false, symbolic links are checked out as small plain files that
@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the `core.eol` configuration variable for all text files.+Note that `core.autocrlf` overrides `core.eol` Set::
@@ -187,8 +188,8 @@ regardless of their content. ------------------------ *.txt text-*.vcproj eol=crlf-*.sh eol=lf+*.vcproj text eol=crlf+*.sh text eol=lf *.jpg -text ------------------------
@@ -198,7 +199,7 @@ normalization in Git. If you simply want to have CRLF line endings in your working directory regardless of the repository you are working with, you can set the-config variable "core.autocrlf" without changing any attributes.+config variable "core.autocrlf" without using any attributes. ------------------------ [core]
@@ -370,12 +369,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,return0;if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;-}+/* If we have any CR or CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(stats.lonecr||stats.crlf)+return0;if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;
@@ -895,9 +896,9 @@ const char *get_convert_attr_ascii(const char *path)caseCRLF_AUTO:return"text=auto";caseCRLF_AUTO_CRLF:-return"text=auto eol=crlf";/* This is not supported yet */+return"text=auto eol=crlf";caseCRLF_AUTO_INPUT:-return"text=auto eol=lf";/* This is not supported yet */+return"text=auto eol=lf";}return"";}
@@ -541,30 +538,30 @@ doforceolin""lfcrlfnative;do# core.autocrlf=true-checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto""$id"""true"$ceol"CRLFCRLFCRLFLF_mix_CRLF_nul+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul# text=auto + eol=XXX-# currently the same as text, eol=XXX-checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto""$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldonedone#Handling with identforidinident;do-forcrlfin""truefalseinput;+forcrlfintruefalseinput;doforceolin""lfcrlfnative;do# ident does not react on core.autocrlf=true-checkout_files"""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# ident does not react on text=auto-checkout_files"auto""$id"""true"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""true"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text=auto + eol=XXX-# currently the same as text, eol=XXX-checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto""$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nuldonedonedone
On Tue, Mar 29, 2016 at 8:25 PM, [off-list ref] wrote:
From: Torsten Bögershausen <redacted>
Factor out the retrival of the sha1 for a given path in
read_blob_data_from_index() into the function get_sha1_from_index().
Getting _sha1_ from index is one function call and a memory
dereference or two. I think you mean get sha1 _file_ (or data) from
index. Maybe put either word in the function name.
This will be used in the next commit, when convert.c can do the analyze
for "text=auto" without slurping the whole blob into memory at once.
On Tue, Mar 29, 2016 at 8:28 PM, Duy Nguyen [off-list ref] wrote:
On Tue, Mar 29, 2016 at 8:25 PM, [off-list ref] wrote:
quoted
From: Torsten Bögershausen <redacted>
Factor out the retrival of the sha1 for a given path in
read_blob_data_from_index() into the function get_sha1_from_index().
Getting _sha1_ from index is one function call and a memory
dereference or two. I think you mean get sha1 _file_ (or data) from
index. Maybe put either word in the function name.
Oops, shouldn't have trusted that function name in the @@ line. No
what you write in the commit message matches the patch. Sorry for the
noise.
--
Duy
On Tue, Mar 29, 2016 at 8:28 PM, Duy Nguyen [off-list ref] wrote:
quoted
On Tue, Mar 29, 2016 at 8:25 PM, [off-list ref] wrote:
quoted
From: Torsten Bögershausen <redacted>
Factor out the retrival of the sha1 for a given path in
read_blob_data_from_index() into the function get_sha1_from_index().
Getting _sha1_ from index is one function call and a memory
dereference or two. I think you mean get sha1 _file_ (or data) from
index. Maybe put either word in the function name.
Oops, shouldn't have trusted that function name in the @@ line. No
what you write in the commit message matches the patch. Sorry for the
noise.
Thanks for the review.
It feels that the naming isn't ideal, let's see if we can find a better
function name.
From: Eric Sunshine <hidden> Date: 2016-06-15 23:09:06
On Tue, Mar 29, 2016 at 9:25 AM, [off-list ref] wrote:
Factor out the retrival of the sha1 for a given path in
s/retrival/retrieval/
read_blob_data_from_index() into the function get_sha1_from_index().
This will be used in the next commit, when convert.c can do the analyze
for "text=auto" without slurping the whole blob into memory at once.
Add a wrapper definition get_sha1_from_cache().
Signed-off-by: Torsten Bögershausen <redacted>
From: Eric Sunshine <hidden> Date: 2016-06-15 23:09:06
On Tue, Mar 29, 2016 at 9:25 AM, [off-list ref] wrote:
quoted hunk
Make .gitattributes "* text=auto eol=crlf" to do the same as
setting core.autocrlf=true and "* text=auto eol=crlf" the same
as core.autocrlf=input
Signed-off-by: Torsten Bögershausen <redacted>
---
@@ -389,14 +389,15 @@ file with mixed line endings would be reported by the `core.safecrlf` core.autocrlf::- Setting this variable to "true" is almost the same as setting- the `text` attribute to "auto" on all files except that text- files are not guaranteed to be normalized: files that contain+ Setting this variable to "true" is the same as setting+ the attributes to "auto eol=crlf" on all files.+ Files are not guaranteed to be normalized: files that contain `CRLF` in the repository will not be touched. Use this setting if you want to have `CRLF` line endings in your- working directory even though the repository does not have- normalized line endings. This variable can be set to 'input',+ working directory and he repository has normalized line endings.
s/he/the/
+ This variable can be set to 'input',
in which case no output conversion is performed.
+ Note: older versions of Git behave different.
Would it make sense to spell out what "different" means since new
readers won't know what the old behavior was?
quoted hunk
diff --git a/convert.c b/convert.c
@@ -370,12 +369,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len, if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {- if (crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {- /* If we have any CR or CRLF line endings, we do not touch it */- /* This is the new safer autocrlf-handling */- if (stats.lonecr || stats.crlf )- return 0;- }+ /* If we have any CR or CRLF line endings, we do not touch it */+ /* This is the new safer autocrlf-handling */
The comment style violation could have been fixed while outdenting,
but perhaps it's not worth the churn.
From: Torsten Bögershausen <redacted>
Factor out the retrieval of the sha1 for a given path in
read_blob_data_from_index() into the function get_sha1_from_index().
This will be used in the next commit, when convert.c can do the analyze
for "text=auto" without slurping the whole blob into memory at once.
Add a wrapper definition get_sha1_from_cache().
Signed-off-by: Torsten Bögershausen <redacted>
- Changes against v1:
Fixed typos, thanks Eric
Corrected gitattributes.txt, "auto" will no longer normalize
Rework of 7/7: Show the eol mismatch to the user when committing
---
cache.h | 3 +++
read-cache.c | 29 ++++++++++++++++++-----------
2 files changed, 21 insertions(+), 11 deletions(-)
From: Torsten Bögershausen <redacted>
When statistics are done for the autocrlf handling, the search in
the content can be stopped, if e.g
- a search for binary is done, and a NUL character is found
- a search for CRLF is done, and the first CRLF is found.
Similar when statistics for binary vs non-binary are gathered:
Whenever a lone CR or NUL is found, the search can be aborted.
When checking out files in "auto" mode, any file that has a "lone CR"
or a CRLF will not be converted, so the search can be aborted early.
Add the new bit, CONVERT_STAT_BITS_ANY_CR,
which is set for either lone CR or CRLF.
Many binary files have a NUL very early (within the first few bytes,
latest within the first 1..2K).
It is often not necessary to load the whole content of a file or blob
into memory.
Use a streaming handling for blobs and files in the worktree.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 162 ++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 106 insertions(+), 56 deletions(-)
@@ -13,10 +14,10 @@*translationwhenthe"text"attributeor"auto_crlf"optionisset.*/-/* Stat bits: When BIN is set, the txt bits are unset */#define CONVERT_STAT_BITS_TXT_LF 0x1#define CONVERT_STAT_BITS_TXT_CRLF 0x2#define CONVERT_STAT_BITS_BIN 0x4+#define CONVERT_STAT_BITS_ANY_CR 0x8enumcrlf_action{CRLF_UNDEFINED,
@@ -31,30 +32,36 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignednul,lonecr,lonelf,crlf;+unsignedstat_bits,lonecr,lonelf,crlf;/* These are just approximations! */unsignedprintable,nonprintable;};-staticvoidgather_stats(constchar*buf,unsignedlongsize,structtext_stat*stats)+staticvoiddo_gather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout){unsignedlongi;-memset(stats,0,sizeof(*stats));-+if(!buf||!size)+return;for(i=0;i<size;i++){unsignedcharc=buf[i];if(c=='\r'){+stats->stat_bits|=CONVERT_STAT_BITS_ANY_CR;if(i+1<size&&buf[i+1]=='\n'){stats->crlf++;i++;-}else+stats->stat_bits|=CONVERT_STAT_BITS_TXT_CRLF;+}else{stats->lonecr++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}continue;}if(c=='\n'){stats->lonelf++;+stats->stat_bits|=CONVERT_STAT_BITS_TXT_LF;continue;}if(c==127)
@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats->printable++;break;case0:-stats->nul++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;/* fall through */default:stats->nonprintable++;
@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *}elsestats->printable++;+if(stats->stat_bits&earlyout)+break;/* We found what we have been searching for */}/* If file ends with EOF then don't count this EOF as non-printable. */
@@ -86,41 +95,63 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat **Thesameheuristicsasdiff.c::mmfile_is_binary()*WetreatfileswithbareCRasbinary*/-staticintconvert_is_binary(unsignedlongsize,conststructtext_stat*stats)+staticvoidconvert_nonprintable(structtext_stat*stats){-if(stats->lonecr)-return1;-if(stats->nul)-return1;if((stats->printable>>7)<stats->nonprintable)-return1;-return0;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}++staticvoidgather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout)+{+memset(stats,0,sizeof(*stats));+do_gather_stats(buf,size,stats,earlyout);+convert_nonprintable(stats);}-staticunsignedintgather_convert_stats(constchar*data,unsignedlongsize)++staticunsignedget_convert_stats_sha1(constchar*path,+unsignedconstchar*sha1,+unsignedearlyout){+structgit_istream*st;structtext_statstats;-intret=0;-if(!data||!size)-return0;-gather_stats(data,size,&stats);-if(convert_is_binary(size,&stats))-ret|=CONVERT_STAT_BITS_BIN;-if(stats.crlf)-ret|=CONVERT_STAT_BITS_TXT_CRLF;-if(stats.lonelf)-ret|=CONVERT_STAT_BITS_TXT_LF;+enumobject_typetype;+unsignedlongsz;-returnret;+if(!sha1)+return0;+memset(&stats,0,sizeof(stats));+st=open_istream(sha1,&type,&sz,NULL);+if(!st){+return0;+}+if(type!=OBJ_BLOB)+gotoclose_and_exit_i;+for(;;){+charbuf[1024];+ssize_treadlen=read_istream(st,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close_and_exit_i:+close_istream(st);+convert_nonprintable(&stats);+returnstats.stat_bits;}-staticconstchar*gather_convert_stats_ascii(constchar*data,unsignedlongsize)+staticconstchar*convert_stats_ascii(unsignedconvert_stats){-unsignedintconvert_stats=gather_convert_stats(data,size);-+unsignedmask=CONVERT_STAT_BITS_TXT_LF|+CONVERT_STAT_BITS_TXT_CRLF;if(convert_stats&CONVERT_STAT_BITS_BIN)return"-text";-switch(convert_stats){+switch(convert_stats&mask){caseCONVERT_STAT_BITS_TXT_LF:return"lf";caseCONVERT_STAT_BITS_TXT_CRLF:
@@ -132,24 +163,46 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si}}+staticunsignedget_convert_stats_wt(constchar*path)+{+structtext_statstats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+intfd;+memset(&stats,0,sizeof(stats));+fd=open(path,O_RDONLY);+if(fd<0)+return0;+for(;;){+charbuf[1024];+ssize_treadlen=read(fd,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close(fd);+convert_nonprintable(&stats);+returnstats.stat_bits;+}+constchar*get_cached_convert_stats_ascii(constchar*path){-constchar*ret;-unsignedlongsz;-void*data=read_blob_data_from_cache(path,&sz);-ret=gather_convert_stats_ascii(data,sz);-free(data);-returnret;+unsignedconvert_stats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+convert_stats=get_convert_stats_sha1(path,+get_sha1_from_cache(path),+earlyout);+returnconvert_stats_ascii(convert_stats);}constchar*get_wt_convert_stats_ascii(constchar*path){-constchar*ret="";-structstrbufsb=STRBUF_INIT;-if(strbuf_read_file(&sb,path,0)>=0)-ret=gather_convert_stats_ascii(sb.buf,sb.len);-strbuf_release(&sb);-returnret;+unsignedconvert_stats;+convert_stats=get_convert_stats_wt(path);+returnconvert_stats_ascii(convert_stats);}staticinttext_eol_is_crlf(void)
From: Torsten Bögershausen <redacted>
Commit 942e77 "Add "core.eol" config variable" adds a condition to
the config parser: core.autocrlf=input is not allowed together with
core.eol=crlf.
This may lead to unnecessary problems, when config files are parsed:
A global config file sets core.autocrlf=input,
the repo local config file sets is own configuration: core.eol=crlf
There is no need to prevent combinations in config.c, in any case
core.autocrlf overrides core.eol.
Allow all combinations of core.crlf and core.eol and document
that core.autocrlf overrides core.eol.
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 6 +++---
config.c | 4 ----
2 files changed, 3 insertions(+), 7 deletions(-)
@@ -337,9 +337,9 @@ core.quotePath:: core.eol:: Sets the line ending type to use in the working directory for- files that have the `text` property set. Alternatives are- 'lf', 'crlf' and 'native', which uses the platform's native- line ending. The default value is `native`. See+ files that have the `text` property set when core.autocrlf is false.+ Alternatives are 'lf', 'crlf' and 'native', which uses the platform's+ native line ending. The default value is `native`. See linkgit:gitattributes[5] for more information on end-of-line conversion.
@@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf` mechanism. core.autocrlf::- Setting this variable to "true" is almost the same as setting- the `text` attribute to "auto" on all files except that text- files are not guaranteed to be normalized: files that contain+ Setting this variable to "true" is the same as setting+ the attributes to "auto eol=crlf" on all files.+ Files are not guaranteed to be normalized: files that contain `CRLF` in the repository will not be touched. Use this setting if you want to have `CRLF` line endings in your- working directory even though the repository does not have- normalized line endings. This variable can be set to 'input',+ working directory and the repository has normalized line endings.+ This variable can be set to 'input', in which case no output conversion is performed. core.symlinks::
@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the `core.eol` configuration variable for all text files.+Note that `core.autocrlf` overrides `core.eol` Set::
@@ -146,8 +147,8 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It enables end-of-line normalization without any-content checks, effectively setting the `text` attribute.+working directory. It sets the `text` attribute,+unless `text=auto` is specified. Set to string value "crlf"::
@@ -187,8 +188,8 @@ regardless of their content. ------------------------ *.txt text-*.vcproj eol=crlf-*.sh eol=lf+*.vcproj text eol=crlf+*.sh text eol=lf *.jpg -text ------------------------
@@ -198,7 +199,7 @@ normalization in Git. If you simply want to have CRLF line endings in your working directory regardless of the repository you are working with, you can set the-config variable "core.autocrlf" without changing any attributes.+config variable "core.autocrlf" without using any attributes. ------------------------ [core]
@@ -370,12 +369,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,return0;if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;-}+/* If we have any CR or CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(stats.lonecr||stats.crlf)+return0;if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;
@@ -895,9 +896,9 @@ const char *get_convert_attr_ascii(const char *path)caseCRLF_AUTO:return"text=auto";caseCRLF_AUTO_CRLF:-return"text=auto eol=crlf";/* This is not supported yet */+return"text=auto eol=crlf";caseCRLF_AUTO_INPUT:-return"text=auto eol=lf";/* This is not supported yet */+return"text=auto eol=lf";}return"";}
@@ -541,30 +538,30 @@ doforceolin""lfcrlfnative;do# core.autocrlf=true-checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto""$id"""true"$ceol"CRLFCRLFCRLFLF_mix_CRLF_nul+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul# text=auto + eol=XXX-# currently the same as text, eol=XXX-checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto""$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldonedone#Handling with identforidinident;do-forcrlfin""truefalseinput;+forcrlfintruefalseinput;doforceolin""lfcrlfnative;do# ident does not react on core.autocrlf=true-checkout_files"""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# ident does not react on text=auto-checkout_files"auto""$id"""true"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""true"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text=auto + eol=XXX-# currently the same as text, eol=XXX-checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto""$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nuldonedonedone
From: Torsten Bögershausen <redacted>
Add more test cases for the not normalized files ("NNO").
The "text" attribute is most important, use it as the first parameter.
"ident", if set, is the second paramater followed by the eol attribute.
The eol attribute overrides core.autocrlf, which overrides core.eol.
Use loops to test more combinations of attributes, like
"* text eol=crlf" or especially "*text=auto eol=crlf".
Currently "* text=auto eol=lf" does the same as "* text eol=lf", as the
eol attribute overrides "text=auto", this will change in future.
Signed-off-by: Torsten Bögershausen <redacted>
---
t/t0027-auto-crlf.sh | 321 +++++++++++++++++++++++++--------------------------
1 file changed, 158 insertions(+), 163 deletions(-)
@@ -100,16 +103,17 @@ commit_check_warn () {} commit_chk_wrnNNO(){-crlf=$1-attr=$2-lfwarn=$3-crlfwarn=$4-lfmixcrlf=$5-lfmixcr=$6-crlfnul=$7-pfx=NNO_${crlf}_attr_${attr}+attr=$1;shift+aeol=$1;shift+crlf=$1;shift+lfwarn=$1;shift+crlfwarn=$1;shift+lfmixcrlf=$1;shift+lfmixcr=$1;shift+crlfnul=$1;shift+pfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}#Commit files on top of existing file-create_gitattributes"$attr"&&+create_gitattributes"$attr"$aeol&&forfinLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldofname=${pfx}_$f.txt&&
@@ -162,6 +166,7 @@ stats_ascii () {# contruct the attr/ returned by git ls-files --eol# Take none (=empty), one or two args+# convert.c: eol=XX overrides text=auto attr_ascii(){case$1,$2in-text,*)echo"-text";;
@@ -440,24 +446,20 @@ test_expect_success 'commit -text' 'check_files_in_repoinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul'-# attr LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL-check_in_repo_NNOfalse""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"auto"LFLFLFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtrue"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOinput"text"LFLFLFLF_mix_CRLF_nul--check_in_repo_NNOfalse"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--+forcrlfintruefalseinput;+do+# attr aeol LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL+check_in_repo_NNO""""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-text""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOauto""$crlfLFLFLFLF_mix_CRCRLF_nul+check_in_repo_NNOautolf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOautocrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+done################################################################################# Check how files in the repo are changed when they are checked out# How to read the table below:
@@ -489,89 +491,82 @@ LFNUL=LF_nulfiexportCRLF_MIX_LF_CRMIXNL-checkout_files""""""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""true""CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truecrlfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truelfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truenativeCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""true""CRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truelfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truenativeCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-+# Same handling with and without identforidin""ident;do-checkout_files"crlf""$id"""false""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falselfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""input""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""inputlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"lf""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"-text""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# -text overrides core.autocrlf and core.eol+# text and eol=crlf or eol=lf override core.autocrlf and core.eol+forcrlfintruefalseinput;+do+forceolin""lfcrlfnative;+do+checkout_files"-text""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"text""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"text""$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+done+done+# text: core.autocrlf=false uses core.eol+checkout_files"text""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_files"text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_files"text""$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_files"text""$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_files"auto""$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_files"auto""$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL++forceolin""lfcrlfnative;+do+# text: core.autocrlf = true overrides core.eol+checkout_files"text""$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# text: core.autocrlf = input overrides core.eol+checkout_files"text""$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+done+# No text attr+forceolin""lfcrlfnative;+do+# core.autocrlf!=true gives LF (or mixed) at checkout+forcrlfinfalseinput;+do+checkout_files"""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+done+done+done++#Handling without ident+foridin"";+do+forceolin""lfcrlfnative;+do+# core.autocrlf=true+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id"""true"$ceol"CRLFCRLFCRLFLF_mix_CRLF_nul+# text=auto + eol=XXX+# currently the same as text, eol=XXX+checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+done+done++#Handling with ident+foridinident;+do+forcrlfin""truefalseinput;+do+forceolin""lfcrlfnative;+do+# ident does not react on core.autocrlf=true+checkout_files"""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# ident does not react on text=auto+checkout_files"auto""$id"""true"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text=auto + eol=XXX+# currently the same as text, eol=XXX+checkout_files"auto""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"auto""$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+done+donedone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
git blame reports lines as not "Not Committed Yet" when they have
CRLF in the index, CRLF in the worktree and e.g. core.autocrlf is true.
Since commit c48053 "new safer autocrlf handling", files that have CRLF
in the index are not normalized at commit when e.g. core.autocrl is set.
Whenever a CLRF conversion is needed (or any filter us set), load the
index temporally, before calling convert_to_git()
Signed-off-by: Torsten Bögershausen <redacted>
---
builtin/blame.c | 6 +++++-
convert.c | 10 ++++++++++
convert.h | 1 +
t/t8003-blame-corner-cases.sh | 14 ++++++++++++++
4 files changed, 30 insertions(+), 1 deletion(-)
@@ -35,6 +35,7 @@ extern enum eol core_eol;externconstchar*get_cached_convert_stats_ascii(constchar*path);externconstchar*get_wt_convert_stats_ascii(constchar*path);externconstchar*get_convert_attr_ascii(constchar*path);+intconvert_needs_conversion(constchar*path);/* returns 1 if *dst was used */externintconvert_to_git(constchar*path,constchar*src,size_tlen,
From: Torsten Bögershausen <redacted>
A follow-up after a discussion how to fix the flaky execution
of t0025, gmane/$284352.
This patch extends the work done in commit c480539:
"Make it work also for un-normalized repositories". Make sure that CRLF
can be converted round trip, or don't convert them at all.
The old handling would treat a file as unchanged after checkout,
as long as it is not touched in the work tree and mtime matches the value
recorded in the index.
When the mtime is changed in the working tree, or the inode is changed,
the file is reported as modified.
The following sequence is now handled reproducable:
$ git init
$ printf "line1\r\n" >file.bat
$ git add file.bat
$ git commit -m "Add file with CRLF" file.bat
$ echo "*.bat text eol=crlf" >.gitattributes
$ git commit -m "bat files should have CRLF"
$ git status
# nothing to commit, working directory clean
$ git push <upstream>
$ printf "newline\r\n" >>file.bat
$ mv file.bat file.sav
$ git checkout file.bat
$ git status
#modified: file.bat
The new handling makes sure that after running "git reset --hard".
"git status" reports the working tree as clean regarding CRLF conversion.
It makes sure that the Git-internal eol conversion is
doing roundtrip. A user can still write an external smudge/clean filter
outside Git, which doesn't do a roundtrip and the working directory is
not clean.
The functionality of has_cr_in_index() is turned into has_crlf_in_index(),
and the function is integrated into would_convert_crlf_at_commit().
Check for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR
is no longer used and removed, as well as "lonecr" in struct text_stat.
Rewrite check_safe_crlf() in convert.c to simulate checkin-checkout,
to detect whether any line endings are converted.
Add a warning, similar to the CRLF-LF replacement, when a file is commited,
and after the next checkout the line endings are not they should be.
Modify the lf_to_crlf_filter:
Files with LF are converted into CRLF, file with CRLF are not changed.
Files with mixed line endings are not converted, the filter fails, and Git
falls back to the non-streaming handling, see write_entry().
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/gitattributes.txt | 16 ++-
convert.c | 232 +++++++++++++++++++++++++---------------
t/t0025-crlf-auto.sh | 8 +-
t/t0027-auto-crlf.sh | 58 +++++-----
4 files changed, 191 insertions(+), 123 deletions(-)
@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'. `text` ^^^^^^-This attribute enables and controls end-of-line normalization. When a+This attribute enables and controls end-of-line conversion. When a text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the
@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol` Set:: Setting the `text` attribute on a path enables end-of-line- normalization and marks the path as a text file. End-of-line+ conversion and marks the path as a text file. End-of-line conversion takes place without guessing the content type.+ Files that have been commited with CRLF before the text attribute+ is set and commited are not normalized. No end-of-line conversion+ is done at checkout or checkin. Unset::
@@ -132,7 +135,8 @@ Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic end-of-line normalization. If Git decides that the content is- text, its line endings are normalized to LF on checkin.+ text, and the path has no CRLF in the index,+ its line endings are converted to LF on checkin. Unspecified::
@@ -147,8 +151,10 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It sets the `text` attribute,-unless `text=auto` is specified.+working directory. It sets the `text` attribute, unless `text=auto`+is specified.+When the file had been commited with CRLF in the index, no conversion+is done at checkout or commit. Set to string value "crlf"::
@@ -32,7 +33,7 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignedstat_bits,lonecr,lonelf,crlf;+unsignedstat_bits,lonelf;/* These are just approximations! */unsignedprintable,nonprintable;
@@ -136,7 +134,7 @@ static unsigned get_convert_stats_sha1(const char *path,if(!readlen)break;do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);-if(stats.stat_bits&earlyout)+if((stats.stat_bits&earlyout)==earlyout)break;/* We found what we have been searching for */}close_and_exit_i:
@@ -241,44 +230,96 @@ static enum eol output_eol(enum crlf_action crlf_action)returncore_eol;}+staticintwould_convert_lf_at_checkout(unsignedconvert_stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+if(output_eol(crlf_action)!=EOL_CRLF)+return0;++/* No "naked" LF? Nothing to convert, regardless. */+if(!convert_stats&CONVERT_STAT_BITS_TXT_LF)+return0;++if(crlf_action==CRLF_AUTO||+crlf_action==CRLF_AUTO_INPUT||+crlf_action==CRLF_AUTO_CRLF){+/* auto: binary files are not converted */+if(convert_stats&CONVERT_STAT_BITS_BIN)+return0;+}+/* If we have any CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;++}++staticintwould_convert_crlf_at_commit(constchar*path,+conststructtext_stat*stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+unsignedstat_bits_index;+/* No CRLF? Nothing to convert, regardless. */+if(!(stats->stat_bits&CONVERT_STAT_BITS_TXT_CRLF))+return0;+/*+*IfthefileintheindexhasanyCRLFinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+stat_bits_index=get_convert_stats_sha1(path,+get_sha1_from_cache(path),+CONVERT_STAT_BITS_TXT_CRLF);+if(stat_bits_index&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;+}+staticvoidcheck_safe_crlf(constchar*path,enumcrlf_actioncrlf_action,-structtext_stat*stats,enumsafe_crlfchecksafe)+enumsafe_crlfchecksafe,+unsignedconvert_stats,unsignednew_convert_stats){+enumeolnew_eol=output_eol(crlf_action);+constchar*err_warn_msg=NULL;if(!checksafe)return;--if(output_eol(crlf_action)==EOL_LF){+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)){/**CRLFswouldnotberestoredbycheckout:*checkifwe'dremoveCRLFs*/-if(stats->crlf){-if(checksafe==SAFE_CRLF_WARN)-warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("CRLF would be replaced by LF in %s.",path);-}-}elseif(output_eol(crlf_action)==EOL_CRLF){+if(checksafe==SAFE_CRLF_WARN)+warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("CRLF would be replaced by LF in %s.",path);+}+if(convert_stats&CONVERT_STAT_BITS_TXT_LF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_LF)){/**CRLFswouldbeaddedbycheckout:*checkifwehave"naked"LFs*/-if(stats->lonelf){-if(checksafe==SAFE_CRLF_WARN)-warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("LF would be replaced by CRLF in %s",path);-}+if(checksafe==SAFE_CRLF_WARN)+warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("LF would be replaced by CRLF in %s",path);+}+if((new_convert_stats&CONVERT_STAT_BITS_MIXED)==CONVERT_STAT_BITS_MIXED)+err_warn_msg="mixed eol";+elseif(new_eol==EOL_LF&&new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+err_warn_msg="CRLF";++if(err_warn_msg){+if(checksafe==SAFE_CRLF_WARN)+warning("%s will be present after commit and checkout in %s.",+err_warn_msg,path);+else+die("%s will be present after commit and checkout in %s",+err_warn_msg,path);}-}--staticinthas_cr_in_index(constchar*path)-{-unsignedconvert_stats;-convert_stats=get_convert_stats_sha1(path,-get_sha1_from_cache(path),-CONVERT_STAT_BITS_ANY_CR);-returnconvert_stats&CONVERT_STAT_BITS_ANY_CR;}staticintcrlf_to_git(constchar*path,constchar*src,size_tlen,
@@ -356,28 +412,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,{char*to_free=NULL;structtext_statstats;-unsignedearlyout=CONVERT_STAT_BITS_TXT_CRLF|CONVERT_STAT_BITS_BIN;---if(!len||output_eol(crlf_action)!=EOL_CRLF)+unsignedearlyout=0;/* Need to count lonelf */+if(!len)return0;gather_stats(src,len,&stats,earlyout);--/* No "naked" LF? Nothing to convert, regardless. */-if(!stats.lonelf)+if(!would_convert_lf_at_checkout(stats.stat_bits,+len,crlf_action))return0;-if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;--if(stats.stat_bits&CONVERT_STAT_BITS_BIN)-return0;-}-/* are we "faking" in place editing ? */if(src==buf->buf)to_free=strbuf_detach(buf,NULL);
@@ -1079,6 +1122,8 @@ int is_null_stream_filter(struct stream_filter *filter)structlf_to_crlf_filter{structstream_filterfilter;unsignedhas_held:1;+unsignedexpanded_loneLF:1;+unsignedhad_CRLF:1;charheld;};
@@ -1119,7 +1164,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,charch=input[i];if(ch=='\n'){-output[o++]='\r';+if(!lf_to_crlf->had_CRLF){+output[o++]='\r';+lf_to_crlf->expanded_loneLF=1;+}+if(was_cr)+lf_to_crlf->had_CRLF=1;}elseif(was_cr){/**PreviousroundsawCRanditisnotfollowed
@@ -1148,6 +1198,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,was_cr=0;output[o++]=ch;+if(lf_to_crlf->expanded_loneLF&&+lf_to_crlf->had_CRLF){+/*+*MixedEOL,roundtripnotpossible.+*/+return1;+}+}*osize_p-=o;
@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' 'test-z"$LFonlydiff"-a-z"$CRLFonlydiff"-a-z"$LFwithNULdiff"'-test_expect_success'crlf=true causes a CRLF file to be normalized''+test_expect_success'crlf=true causes a CRLF file not to be normalized''# Backwards compatibility checkrm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&
@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"'-test_expect_success'text=true causes a CRLF file to be normalized''+test_expect_success'text=true causes a CRLF file not to be normalized''rm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&echo"CRLFonly text">.gitattributes&&
@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"' test_expect_success'eol=crlf gives a normalized file CRLFs with autocrlf=false''
@@ -71,10 +71,14 @@ check_warning () {case"$1"inLF_CRLF)echo"warning: LF will be replaced by CRLF">"$2".expect;;CRLF_LF)echo"warning: CRLF will be replaced by LF">"$2".expect;;+CRLF)echo"warning: CRLF will be present after commit and checkout">"$2".expect;;+mixed)echo"warning: mixed eol will be present after commit and checkout">"$2".expect;;'')>"$2".expect;;*)echo>&2"Illegal 1":"$1";returnfalse;;esac-grep"will be replaced by""$2"|sed-e"s/\(.*\) in [^ ]*$/\1/"|uniq>"$2".actual+egrep"will be replaced by|will be present after commit""$2"|+sed-e"s/\(.*\) in [^ ]*$/\1/"|+uniq>"$2".actualtest_cmp"$2".expect"$2".actual}
@@ -455,9 +461,9 @@ docheck_in_repo_NNOauto""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautolf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautocrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldone################################################################################# Check how files in the repo are changed when they are checked out
From: Torsten Bögershausen <redacted>
git blame reports lines as not "Not Committed Yet" when they have
CRLF in the index, CRLF in the worktree and core.autocrlf is true.
Since commit c48053 "new safer autocrlf handling", files that have CRLF
in the index are not normalized at commit when core.autocrl is set.
Add a call to read_cache() early in fake_working_tree_commit(),
before calling convert_to_git().
Signed-off-by: Torsten Bögershausen <redacted>
---
This fix is completely independent of the rest of the series,
so break out 6/7 from tb/safe-crlf-output.
The rest of the series will be send in a couple of days, some
rework is needed.
builtin/blame.c | 1 +
t/t8003-blame-corner-cases.sh | 14 ++++++++++++++
2 files changed, 15 insertions(+)
From: Torsten Bögershausen <redacted>
Add more test cases for the not normalized files ("NNO"). The
"text" attribute is most important, use it as the first parameter.
"ident", if set, is the second paramater followed by the eol
attribute. The eol attribute overrides core.autocrlf, which
overrides core.eol.
indent is not yet uses, this will be done in the next commit.
Use loops to test more combinations of attributes, like
"* text eol=crlf" or especially "*text=auto eol=crlf".
Currently "* text=auto eol=lf" does the same as "* text eol=lf",
as the eol attribute overrides "text=auto", this will change in
future.
Signed-off-by: Torsten Bögershausen <redacted>
---
t/t0027-auto-crlf.sh | 298 ++++++++++++++++++++++-----------------------------
1 file changed, 129 insertions(+), 169 deletions(-)
@@ -100,16 +103,17 @@ commit_check_warn () {} commit_chk_wrnNNO(){-crlf=$1-attr=$2-lfwarn=$3-crlfwarn=$4-lfmixcrlf=$5-lfmixcr=$6-crlfnul=$7-pfx=NNO_${crlf}_attr_${attr}+attr=$1;shift+aeol=$1;shift+crlf=$1;shift+lfwarn=$1;shift+crlfwarn=$1;shift+lfmixcrlf=$1;shift+lfmixcr=$1;shift+crlfnul=$1;shift+pfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}#Commit files on top of existing file-create_gitattributes"$attr"&&+create_gitattributes"$attr"$aeol&&forfinLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldofname=${pfx}_$f.txt&&
@@ -163,6 +167,7 @@ stats_ascii () {# contruct the attr/ returned by git ls-files --eol# Take none (=empty), one or two args+# convert.c: eol=XX overrides text=auto attr_ascii(){case$1,$2in-text,*)echo"-text";;
@@ -441,24 +447,20 @@ test_expect_success 'commit -text' 'check_files_in_repoinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul'-# attr LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL-check_in_repo_NNOfalse""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"auto"LFLFLFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtrue"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOinput"text"LFLFLFLF_mix_CRLF_nul--check_in_repo_NNOfalse"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--+forcrlfintruefalseinput+do+# attr aeol LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL+check_in_repo_NNO""""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-text""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOauto""$crlfLFLFLFLF_mix_CRCRLF_nul+check_in_repo_NNOautolf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOautocrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+done################################################################################# Check how files in the repo are changed when they are checked out# How to read the table below:
@@ -490,89 +492,47 @@ LFNUL=LF_nulfiexportCRLF_MIX_LF_CRMIXNL-checkout_files""""""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""true""CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truecrlfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truelfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truenativeCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""true""CRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truelfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truenativeCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul--foridin""ident;+# Same handling with and without ident+foridin""do-checkout_files"crlf""$id"""false""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falselfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""input""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""inputlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"lf""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"-text""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+forceolinlfcrlfnative+do+forcrlfintruefalseinput+do+# -text overrides core.autocrlf and core.eol+# text and eol=crlf or eol=lf override core.autocrlf and core.eol+checkout_files-text"$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files-text"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files-text"$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text+checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# currently the same as text, eol=XXX+checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+done++# core.autocrlf false, different core.eol+checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# core.autocrlf true+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf = true overrides core.eol+checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLFLF_mix_CRLF_nul+checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# text: core.autocrlf = input overrides core.eol+checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text=auto + eol=XXX+done+# text: core.autocrlf=false uses core.eol+checkout_filestext"$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+# auto: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_filesauto"$id"""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
When the ident attributes is set, get_stream_filter() did not obey
core.autocrlf=true, and the file was checked out with LF.
Change the rule when a streaming filter can be used:
- if an external filter is specified, don't use a stream filter.
- if the worktree eol is CRLF and "auto" is active, don't use a stream filter.
- Otherwise the stream filter can be used.
Add test cases in t0027.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 18 ++++++------------
t/t0027-auto-crlf.sh | 2 +-
2 files changed, 7 insertions(+), 13 deletions(-)
From: Torsten Bögershausen <redacted>
Make the commit_chk_wrnNNO test in t0027 more reliable:
When the attributes of a commited file are changed and the file is otherwise
unchanged, Git may not detect that the next commit may need to treat the
file as changed.
This happens when lstat() doesn't detect a change, since neither inode,
mtime nor size are changed.
Add a singe "Z" character to change the file size.
Ignore it when comparing the files later.
Signed-off-by: Torsten Bögershausen <redacted>
---
Changes against the last round:
- Add this commit, since t0027 become shaky
- Add bugfix in 4/4
- Remove the non-normalizing changes, they will be part of a different
series. Mainly because t6038 needs improvements, and ce_compare_data()
in read_cache.c needs to learn to run convert_to_git()
t/t0027-auto-crlf.sh | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Torsten Bögershausen <redacted>
Even though the configuration parser errors out when core.autocrlf
is set to 'input' when core.eol is set to 'crlf', there is no need
to do so, because the core.autocrlf setting trumps core.eol.
Allow all combinations of core.crlf and core.eol and document
that core.autocrlf overrides core.eol.
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 6 +++---
config.c | 4 ----
2 files changed, 3 insertions(+), 7 deletions(-)
@@ -337,9 +337,9 @@ core.quotePath:: core.eol:: Sets the line ending type to use in the working directory for- files that have the `text` property set. Alternatives are- 'lf', 'crlf' and 'native', which uses the platform's native- line ending. The default value is `native`. See+ files that have the `text` property set when core.autocrlf is false.+ Alternatives are 'lf', 'crlf' and 'native', which uses the platform's+ native line ending. The default value is `native`. See linkgit:gitattributes[5] for more information on end-of-line conversion.
From: Torsten Bögershausen <redacted>
Even though the configuration parser errors out when core.autocrlf
is set to 'input' when core.eol is set to 'crlf', there is no need
to do so, because the core.autocrlf setting trumps core.eol.
Allow all combinations of core.crlf and core.eol and document
that core.autocrlf overrides core.eol.
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 6 +++---
config.c | 4 ----
2 files changed, 3 insertions(+), 7 deletions(-)
@@ -337,9 +337,9 @@ core.quotePath:: core.eol:: Sets the line ending type to use in the working directory for- files that have the `text` property set. Alternatives are- 'lf', 'crlf' and 'native', which uses the platform's native- line ending. The default value is `native`. See+ files that have the `text` property set when core.autocrlf is false.+ Alternatives are 'lf', 'crlf' and 'native', which uses the platform's+ native line ending. The default value is `native`. See linkgit:gitattributes[5] for more information on end-of-line conversion.
From: Torsten Bögershausen <redacted>
Make the commit_chk_wrnNNO test in t0027 more reliable:
When the attributes of a commited file are changed and the file is otherwise
unchanged, Git may not detect that the next commit may need to treat the
file as changed.
This happens when lstat() doesn't detect a change, since neither inode,
mtime nor size are changed.
Add a singe "Z" character to change the file size.
Ignore it when comparing the files later.
Signed-off-by: Torsten Bögershausen <redacted>
---
Changes since v5:
- send the whole series, now 10/10
- Removed the "will change in future" in one commit msg
- Don't leak the filer in 4/10
t/t0027-auto-crlf.sh | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Torsten Bögershausen <redacted>
Add more test cases for the not normalized files ("NNO"). The
"text" attribute is most important, use it as the first parameter.
"ident", if set, is the second paramater followed by the eol
attribute. The eol attribute overrides core.autocrlf, which
overrides core.eol.
indent is not yet uses, this will be done in the next commit.
Use loops to test more combinations of attributes, like
"* text eol=crlf" or especially "*text=auto eol=crlf".
Signed-off-by: Torsten Bögershausen <redacted>
---
t/t0027-auto-crlf.sh | 298 ++++++++++++++++++++++-----------------------------
1 file changed, 129 insertions(+), 169 deletions(-)
@@ -100,16 +103,17 @@ commit_check_warn () {} commit_chk_wrnNNO(){-crlf=$1-attr=$2-lfwarn=$3-crlfwarn=$4-lfmixcrlf=$5-lfmixcr=$6-crlfnul=$7-pfx=NNO_${crlf}_attr_${attr}+attr=$1;shift+aeol=$1;shift+crlf=$1;shift+lfwarn=$1;shift+crlfwarn=$1;shift+lfmixcrlf=$1;shift+lfmixcr=$1;shift+crlfnul=$1;shift+pfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}#Commit files on top of existing file-create_gitattributes"$attr"&&+create_gitattributes"$attr"$aeol&&forfinLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldofname=${pfx}_$f.txt&&
@@ -163,6 +167,7 @@ stats_ascii () {# contruct the attr/ returned by git ls-files --eol# Take none (=empty), one or two args+# convert.c: eol=XX overrides text=auto attr_ascii(){case$1,$2in-text,*)echo"-text";;
@@ -441,24 +447,20 @@ test_expect_success 'commit -text' 'check_files_in_repoinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul'-# attr LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL-check_in_repo_NNOfalse""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"auto"LFLFLFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtrue"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOinput"text"LFLFLFLF_mix_CRLF_nul--check_in_repo_NNOfalse"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--+forcrlfintruefalseinput+do+# attr aeol LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL+check_in_repo_NNO""""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-text""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOauto""$crlfLFLFLFLF_mix_CRCRLF_nul+check_in_repo_NNOautolf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOautocrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+done################################################################################# Check how files in the repo are changed when they are checked out# How to read the table below:
@@ -490,89 +492,47 @@ LFNUL=LF_nulfiexportCRLF_MIX_LF_CRMIXNL-checkout_files""""""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""true""CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truecrlfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truelfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truenativeCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""true""CRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truelfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truenativeCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul--foridin""ident;+# Same handling with and without ident+foridin""do-checkout_files"crlf""$id"""false""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falselfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""input""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""inputlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"lf""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"-text""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+forceolinlfcrlfnative+do+forcrlfintruefalseinput+do+# -text overrides core.autocrlf and core.eol+# text and eol=crlf or eol=lf override core.autocrlf and core.eol+checkout_files-text"$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files-text"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files-text"$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text+checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# currently the same as text, eol=XXX+checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+done++# core.autocrlf false, different core.eol+checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# core.autocrlf true+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf = true overrides core.eol+checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLFLF_mix_CRLF_nul+checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# text: core.autocrlf = input overrides core.eol+checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text=auto + eol=XXX+done+# text: core.autocrlf=false uses core.eol+checkout_filestext"$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+# auto: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_filesauto"$id"""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
When the ident attributes is set, get_stream_filter() did not obey
core.autocrlf=true, and the file was checked out with LF.
Change the rule when a streaming filter can be used:
- if an external filter is specified, don't use a stream filter.
- if the worktree eol is CRLF and "auto" is active, don't use a stream filter.
- Otherwise the stream filter can be used.
Add test cases in t0027.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 19 +++++++------------
t/t0027-auto-crlf.sh | 2 +-
2 files changed, 8 insertions(+), 13 deletions(-)
From: Torsten Bögershausen <redacted>
Factor out the retrieval of the sha1 for a given path in
read_blob_data_from_index() into the function get_sha1_from_index().
This will be used in the next commit, when convert.c can do the
analyze for "text=auto" without slurping the whole blob into memory
at once.
Add a wrapper definition get_sha1_from_cache().
Signed-off-by: Torsten Bögershausen <redacted>
---
cache.h | 3 +++
read-cache.c | 29 ++++++++++++++++++-----------
2 files changed, 21 insertions(+), 11 deletions(-)
From: Torsten Bögershausen <redacted>
We define the working tree file is clean if either:
* the result of running convert_to_git() on the working tree
contents matches what is in the index (because that would mean
doing another "git add" on the path is a no-op); OR
* the result of running convert_to_working_tree() on the content
in the index matches what is in the working tree (because that
would mean doing another "git checkout -f" on the path is a
no-op).
Add an extra check in ce_compare_data() in read_cache.c.
When a file has CRLF in the index, and is checked out into the working tree,
but left unchabged, it is not normalized at the next commit.
Helped-by: Junio C Hamano [off-list ref]
Signed-off-by: Torsten Bögershausen <redacted>
---
read-cache.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
t/t6038-merge-text-auto.sh | 14 +++++------
2 files changed, 68 insertions(+), 7 deletions(-)
@@ -156,17 +156,78 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)ce_mark_uptodate(ce);}+/*+*Comparethedatainbufwiththedatainthefilepointedbyfdand+*return0iftheyareidentical,andnon-zeroiftheydiffer.+*/+staticintcompare_with_fd(constchar*input,ssize_tlen,intfd)+{+for(;;){+charbuf[1024*16];+ssize_tchunk_len,read_len;++chunk_len=sizeof(buf)<len?sizeof(buf):len;+read_len=xread(fd,buf,chunk_len?chunk_len:1);++if(!read_len)+/* EOF on the working tree file */+return!len?0:-1;++if(!len)+/* we expected there is nothing left */+return-1;++if(memcmp(buf,input,read_len))+return-1;+input+=read_len;+len-=read_len;+}+}+staticintce_compare_data(conststructcache_entry*ce,structstat*st){intmatch=-1;intfd=open(ce->name,O_RDONLY);+/*+*Wouldanother"git add"onthepathchangewhatisinthe+*indexforthepath?+*/if(fd>=0){unsignedcharsha1[20];if(!index_fd(sha1,fd,st,OBJ_BLOB,ce->name,0))match=hashcmp(sha1,ce->sha1);/* index_fd() closed the file descriptor already */}+if(!match)+returnmatch;++/*+*Wouldanother"git checkout -f"outoftheindexchange+*whatisintheworkingtreefile?+*/+fd=open(ce->name,O_RDONLY);+if(fd>=0){+enumobject_typetype;+unsignedlongsize_long;+void*data=read_sha1_file(ce->sha1,&type,&size_long);++if(type==OBJ_BLOB){+structstrbufworktree=STRBUF_INIT;+if(convert_to_working_tree(ce->name,data,+size_long,+&worktree)){+size_tsize;+free(data);+data=strbuf_detach(&worktree,&size);+size_long=size;+}+if(!compare_with_fd(data,size_long,fd))+match=0;+}+free(data);+close(fd);+}returnmatch;}
From: Torsten Bögershausen <redacted>
A follow-up after a discussion how to fix the flaky execution
of t0025, gmane/$284352.
This patch extends the work done in commit c480539:
"Make it work also for un-normalized repositories". Make sure that CRLF
can be converted round trip, or don't convert them at all.
The old handling would treat a file as unchanged after checkout,
as long as it is not touched in the work tree and mtime matches the value
recorded in the index.
When the mtime is changed in the working tree, or the inode is changed,
the file is reported as modified.
The following sequence is now handled reproducable:
$ git init
$ printf "line1\r\n" >file.bat
$ git add file.bat
$ git commit -m "Add file with CRLF" file.bat
$ echo "*.bat text eol=crlf" >.gitattributes
$ git commit -m "bat files should have CRLF"
$ git status
# nothing to commit, working directory clean
$ git push <upstream>
$ printf "newline\r\n" >>file.bat
$ mv file.bat file.sav
$ git checkout file.bat
$ git status
#modified: file.bat
The new handling makes sure that after running "git reset --hard".
"git status" reports the working tree as clean regarding CRLF conversion.
It makes sure that the Git-internal eol conversion is
doing roundtrip. A user can still write an external smudge/clean filter
outside Git, which doesn't do a roundtrip and the working directory is
not clean.
The functionality of has_cr_in_index() is turned into has_crlf_in_index(),
and the function is integrated into would_convert_crlf_at_commit().
Check for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR
is no longer used and removed, as well as "lonecr" in struct text_stat.
Rewrite check_safe_crlf() in convert.c to simulate checkin-checkout,
to detect whether any line endings are converted.
Add a warning, similar to the CRLF-LF replacement, when a file is commited,
and after the next checkout the line endings are not they should be.
Modify the lf_to_crlf_filter:
Files with LF are converted into CRLF, file with CRLF are not changed.
Files with mixed line endings are not converted, the filter fails, and Git
falls back to the non-streaming handling, see write_entry().
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/gitattributes.txt | 19 ++--
convert.c | 233 +++++++++++++++++++++++++---------------
t/t0025-crlf-auto.sh | 8 +-
t/t0027-auto-crlf.sh | 92 ++++++++--------
4 files changed, 212 insertions(+), 140 deletions(-)
@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'. `text` ^^^^^^-This attribute enables and controls end-of-line normalization. When a+This attribute enables and controls end-of-line conversion. When a text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the
@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol` Set:: Setting the `text` attribute on a path enables end-of-line- normalization and marks the path as a text file. End-of-line+ conversion and marks the path as a text file. End-of-line conversion takes place without guessing the content type.+ Files that have been commited with CRLF before the text attribute+ is set and commited are not normalized. No end-of-line conversion+ is done at checkout or checkin. Unset::
@@ -131,9 +134,9 @@ Unset:: Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic- end-of-line conversion. If Git decides that the content is- text, its line endings are converted to LF on checkin.- When the file has been commited with CRLF, no conversion is done.+ end-of-line normalization. If Git decides that the content is+ text, and the path has no CRLF in the index,+ its line endings are converted to LF on checkin. Unspecified::
@@ -148,8 +151,10 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It enables end-of-line conversion without any-content checks, effectively setting the `text` attribute.+working directory. It sets the `text` attribute, unless `text=auto`+is specified.+When the file had been commited with CRLF in the index, no conversion+is done at checkout or commit. Set to string value "crlf"::
@@ -32,7 +33,7 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignedstat_bits,lonecr,lonelf,crlf;+unsignedstat_bits,lonelf;/* These are just approximations! */unsignedprintable,nonprintable;
@@ -135,7 +133,7 @@ static unsigned get_convert_stats_sha1(unsigned const char *sha1,if(!readlen)break;do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);-if(stats.stat_bits&earlyout)+if((stats.stat_bits&earlyout)==earlyout)break;/* We found what we have been searching for */}close_and_exit_i:
@@ -239,43 +228,95 @@ static enum eol output_eol(enum crlf_action crlf_action)returncore_eol;}+staticintwould_convert_lf_at_checkout(unsignedconvert_stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+if(output_eol(crlf_action)!=EOL_CRLF)+return0;++/* No "naked" LF? Nothing to convert, regardless. */+if(!convert_stats&CONVERT_STAT_BITS_TXT_LF)+return0;++if(crlf_action==CRLF_AUTO||+crlf_action==CRLF_AUTO_INPUT||+crlf_action==CRLF_AUTO_CRLF){+/* auto: binary files are not converted */+if(convert_stats&CONVERT_STAT_BITS_BIN)+return0;+}+/* If we have any CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;++}++staticintwould_convert_crlf_at_commit(constchar*path,+conststructtext_stat*stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+unsignedstat_bits_index;+/* No CRLF? Nothing to convert, regardless. */+if(!(stats->stat_bits&CONVERT_STAT_BITS_TXT_CRLF))+return0;+/*+*IfthefileintheindexhasanyCRLFinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+stat_bits_index=get_convert_stats_sha1(get_sha1_from_cache(path),+CONVERT_STAT_BITS_TXT_CRLF);+if(stat_bits_index&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;+}+staticvoidcheck_safe_crlf(constchar*path,enumcrlf_actioncrlf_action,-structtext_stat*stats,enumsafe_crlfchecksafe)+enumsafe_crlfchecksafe,+unsignedconvert_stats,unsignednew_convert_stats){+enumeolnew_eol=output_eol(crlf_action);+constchar*err_warn_msg=NULL;if(!checksafe)return;--if(output_eol(crlf_action)==EOL_LF){+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)){/**CRLFswouldnotberestoredbycheckout:*checkifwe'dremoveCRLFs*/-if(stats->crlf){-if(checksafe==SAFE_CRLF_WARN)-warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("CRLF would be replaced by LF in %s.",path);-}-}elseif(output_eol(crlf_action)==EOL_CRLF){+if(checksafe==SAFE_CRLF_WARN)+warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("CRLF would be replaced by LF in %s.",path);+}+if(convert_stats&CONVERT_STAT_BITS_TXT_LF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_LF)){/**CRLFswouldbeaddedbycheckout:*checkifwehave"naked"LFs*/-if(stats->lonelf){-if(checksafe==SAFE_CRLF_WARN)-warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("LF would be replaced by CRLF in %s",path);-}+if(checksafe==SAFE_CRLF_WARN)+warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("LF would be replaced by CRLF in %s",path);+}+if((new_convert_stats&CONVERT_STAT_BITS_MIXED)==CONVERT_STAT_BITS_MIXED)+err_warn_msg="mixed eol";+elseif(new_eol==EOL_LF&&new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+err_warn_msg="CRLF";++if(err_warn_msg){+if(checksafe==SAFE_CRLF_WARN)+warning("%s will be present after commit and checkout in %s.",+err_warn_msg,path);+else+die("%s will be present after commit and checkout in %s",+err_warn_msg,path);}-}--staticinthas_cr_in_index(constchar*path)-{-unsignedconvert_stats;-convert_stats=get_convert_stats_sha1(get_sha1_from_cache(path),-CONVERT_STAT_BITS_ANY_CR);-returnconvert_stats&CONVERT_STAT_BITS_ANY_CR;}staticintcrlf_to_git(constchar*path,constchar*src,size_tlen,
@@ -354,28 +415,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,{char*to_free=NULL;structtext_statstats;-unsignedearlyout=CONVERT_STAT_BITS_TXT_CRLF|CONVERT_STAT_BITS_BIN;---if(!len||output_eol(crlf_action)!=EOL_CRLF)+unsignedearlyout=0;/* Need to count lonelf */+if(!len)return0;gather_stats(src,len,&stats,earlyout);--/* No "naked" LF? Nothing to convert, regardless. */-if(!stats.lonelf)+if(!would_convert_lf_at_checkout(stats.stat_bits,+len,crlf_action))return0;-if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;--if(stats.stat_bits&CONVERT_STAT_BITS_BIN)-return0;-}-/* are we "faking" in place editing ? */if(src==buf->buf)to_free=strbuf_detach(buf,NULL);
@@ -1067,6 +1115,8 @@ int is_null_stream_filter(struct stream_filter *filter)structlf_to_crlf_filter{structstream_filterfilter;unsignedhas_held:1;+unsignedexpanded_loneLF:1;+unsignedhad_CRLF:1;charheld;};
@@ -1107,7 +1157,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,charch=input[i];if(ch=='\n'){-output[o++]='\r';+if(!lf_to_crlf->had_CRLF){+output[o++]='\r';+lf_to_crlf->expanded_loneLF=1;+}+if(was_cr)+lf_to_crlf->had_CRLF=1;}elseif(was_cr){/**PreviousroundsawCRanditisnotfollowed
@@ -1136,6 +1191,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,was_cr=0;output[o++]=ch;+if(lf_to_crlf->expanded_loneLF&&+lf_to_crlf->had_CRLF){+/*+*MixedEOL,roundtripnotpossible.+*/+return1;+}+}*osize_p-=o;
@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' 'test-z"$LFonlydiff"-a-z"$CRLFonlydiff"-a-z"$LFwithNULdiff"'-test_expect_success'crlf=true causes a CRLF file to be normalized''+test_expect_success'crlf=true causes a CRLF file not to be normalized''# Backwards compatibility checkrm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&
@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"'-test_expect_success'text=true causes a CRLF file to be normalized''+test_expect_success'text=true causes a CRLF file not to be normalized''rm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&echo"CRLFonly text">.gitattributes&&
@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"' test_expect_success'eol=crlf gives a normalized file CRLFs with autocrlf=false''
@@ -71,10 +71,14 @@ check_warning () {case"$1"inLF_CRLF)echo"warning: LF will be replaced by CRLF">"$2".expect;;CRLF_LF)echo"warning: CRLF will be replaced by LF">"$2".expect;;+CRLF)echo"warning: CRLF will be present after commit and checkout">"$2".expect;;+mixed)echo"warning: mixed eol will be present after commit and checkout">"$2".expect;;'')>"$2".expect;;*)echo>&2"Illegal 1":"$1";returnfalse;;esac-grep"will be replaced by""$2"|sed-e"s/\(.*\) in [^ ]*$/\1/"|uniq>"$2".actual+egrep"will be replaced by|will be present after commit""$2"|+sed-e"s/\(.*\) in [^ ]*$/\1/"|+uniq>"$2".actualtest_cmp"$2".expect"$2".actual}
@@ -169,7 +173,7 @@ stats_ascii () {# Take none (=empty), one or two args# convert.c: eol=XX overrides text=auto attr_ascii(){-case$1,$2in+case"$1","$2"in-text,*)echo"-text";;text,)echo"text";;text,lf)echo"text eol=lf";;
@@ -456,9 +463,9 @@ docheck_in_repo_NNOauto""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautolf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautocrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldone################################################################################# Check how files in the repo are changed when they are checked out
@@ -492,8 +497,7 @@ fiexportCRLF_MIX_LF_CRMIXNL# Same handling with and without ident-#for id in "" ident-foridin""+foridin""identdoforceolinlfcrlfnativedo
@@ -501,38 +505,38 @@ dodo# -text overrides core.autocrlf and core.eol# text and eol=crlf or eol=lf override core.autocrlf and core.eol-checkout_files-text"$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files-text"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files-text"$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text-checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul# currently the same as text, eol=XXX-checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# core.autocrlf false, different core.eol-checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# core.autocrlf true-checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text: core.autocrlf = true overrides core.eol-checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul# text: core.autocrlf = input overrides core.eol-checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text=auto + eol=XXXdone# text: core.autocrlf=false uses core.eol-checkout_filestext"$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""falsecrlfCRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul+checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_filestext"$id"""false""$NLCRLFCRLF_mix_LF"$MIX_LF_CR""$LFNUL"+checkout_filestext"$id"""falsenative$NLCRLFCRLF_mix_LF"$MIX_LF_CR""$LFNUL"# auto: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
t6038 uses different code, dependig if NATIVE_CRLF is set ot not.
When the native line endings are LF, merge.renormalize is not tested very well.
Change the test to always use CRLF by setting core.eol=crlf.
After doing so, the test fails:
rm '.gitattributes'
rm 'control_file'
rm 'file'
rm 'inert_file'
HEAD is now at 0d9ffb6 add line from b
error: addinfo_cache failed for path 'file'
file: unmerged (cbd69ec7cd12dd0989e853923867d94c8519aa52)
file: unmerged (ad55e240aeb42e0d9a0e18d6d8b02dd82ee3e527)
file: unmerged (99b633103c15c20cebebf821133ab526b0ff90b2)
fatal: git write-tree failed to write a tree
Merging:
0d9ffb6 add line from b
virtual a
found 1 common ancestor:
1c56df1 Initial
Auto-merging file
not ok 4 - Merge addition of text=auto
This will be addressed in the next commit.
---
t/t6038-merge-text-auto.sh | 37 +++++++++++--------------------------
1 file changed, 11 insertions(+), 26 deletions(-)
From: Torsten Bögershausen <redacted>
Before this change,
$ echo "* text=auto" >.gitattributes
$ echo "* eol=crlf" >>.gitattributes
would have the same effect as
$ echo "* text" >.gitattributes
$ git config core.eol crlf
Since the 'eol' attribute had higher priority than 'text=auto', this may
corrupt binary files and is not what most users expect to happen.
Make the 'eol' attribute to obey 'text=auto', and now
$ echo "* text=auto" >.gitattributes
$ echo "* eol=crlf" >>.gitattributes
behaves the same as
$ echo "* text=auto" >.gitattributes
$ git config core.eol crlf
In other words,
$ echo "* text=auto eol=crlf" >.gitattributes
has the same effect as
$ git config core.autocrlf true
and
$ echo "* text=auto eol=lf" >.gitattributes
has the same effect as
$ git config core.autocrlf input
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 14 +++++++-------
Documentation/gitattributes.txt | 15 +++++++++------
convert.c | 42 +++++++++++++++++++++--------------------
convert.h | 3 ++-
t/t0025-crlf-auto.sh | 4 ++--
t/t0027-auto-crlf.sh | 32 +++++++++++++++----------------
t/t6038-merge-text-auto.sh | 23 ++++++++++++++--------
7 files changed, 73 insertions(+), 60 deletions(-)
@@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf` mechanism. core.autocrlf::- Setting this variable to "true" is almost the same as setting- the `text` attribute to "auto" on all files except that text- files are not guaranteed to be normalized: files that contain- `CRLF` in the repository will not be touched. Use this- setting if you want to have `CRLF` line endings in your- working directory even though the repository does not have- normalized line endings. This variable can be set to 'input',+ Setting this variable to "true" is the same as setting+ the `text` attribute to "auto" on all files and core.eol to "crlf".+ Set to true if you want to have `CRLF` line endings in your+ working directory and the repository has LF line endings.+ Text files are guaranteed not to be normalized: files that contain+ `CRLF` in the repository will not be touched.+ This variable can be set to 'input', in which case no output conversion is performed. core.symlinks::
@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the `core.eol` configuration variable for all text files.+Note that `core.autocrlf` overrides `core.eol` Set::
@@ -130,8 +131,9 @@ Unset:: Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic- end-of-line normalization. If Git decides that the content is- text, its line endings are normalized to LF on checkin.+ end-of-line conversion. If Git decides that the content is+ text, its line endings are converted to LF on checkin.+ When the file has been commited with CRLF, no conversion is done. Unspecified::
@@ -146,7 +148,7 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It enables end-of-line normalization without any+working directory. It enables end-of-line conversion without any content checks, effectively setting the `text` attribute. Set to string value "crlf"::
@@ -186,9 +188,10 @@ the working directory, and prevent .jpg files from being normalized regardless of their content. ------------------------+* text=auto *.txt text-*.vcproj eol=crlf-*.sh eol=lf+*.vcproj text eol=crlf+*.sh text eol=lf *.jpg -text ------------------------
@@ -198,7 +201,7 @@ normalization in Git. If you simply want to have CRLF line endings in your working directory regardless of the repository you are working with, you can set the-config variable "core.autocrlf" without changing any attributes.+config variable "core.autocrlf" without using any attributes. ------------------------ [core]
@@ -227,7 +227,9 @@ static enum eol output_eol(enum crlf_action crlf_action)returnEOL_LF;caseCRLF_UNDEFINED:caseCRLF_AUTO_CRLF:+returnEOL_CRLF;caseCRLF_AUTO_INPUT:+returnEOL_LF;caseCRLF_TEXT:caseCRLF_AUTO:/* fall through */
@@ -299,17 +301,15 @@ static int crlf_to_git(const char *path, const char *src, size_t len,if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;--if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/*-*IfthefileintheindexhasanyCRinit,donotconvert.-*Thisisthenewsaferautocrlfhandling.-*/-if(has_cr_in_index(path))-return0;-}+/*+*IfthefileintheindexhasanyCRinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+if(checksafe==SAFE_CRLF_RENORMALIZE)+checksafe=SAFE_CRLF_FALSE;+elseif(has_cr_in_index(path))+return0;}-check_safe_crlf(path,crlf_action,&stats,checksafe);/* Optimization: No CRLF? Nothing to convert, regardless. */
@@ -367,12 +367,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,return0;if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;-}+/* If we have any CR or CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(stats.lonecr||stats.crlf)+return0;if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;
@@ -892,9 +894,9 @@ const char *get_convert_attr_ascii(const char *path)caseCRLF_AUTO:return"text=auto";caseCRLF_AUTO_CRLF:-return"text=auto eol=crlf";/* This is not supported yet */+return"text=auto eol=crlf";caseCRLF_AUTO_INPUT:-return"text=auto eol=lf";/* This is not supported yet */+return"text=auto eol=lf";}return"";}
@@ -493,7 +492,8 @@ fiexportCRLF_MIX_LF_CRMIXNL# Same handling with and without ident-foridin""ident+#for id in "" ident+foridin""doforceolinlfcrlfnativedo
@@ -509,7 +509,7 @@ docheckout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul# currently the same as text, eol=XXXcheckout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# core.autocrlf false, different core.eol
@@ -531,8 +531,8 @@ docheckout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNULcheckout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL# auto: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filesauto"$id"""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
@@ -81,7 +88,7 @@ test_expect_success 'Merge after setting text=auto' 'rm-f.gitattributes&&gitreset--harda&&gitmergeb&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Merge addition of text=auto''
@@ -99,7 +106,7 @@ test_expect_success 'Merge addition of text=auto' 'rm-f.gitattributes&&gitreset--hardb&&gitmergea&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Detect CRLF/LF conflict after setting text=auto''
@@ -121,7 +128,7 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' 'gitreset--harda&&test_must_failgitmergeb&&fuzz_conflictfile>file.fuzzy&&-test_cmpexpectedfile.fuzzy+compare_filesexpectedfile.fuzzy' test_expect_success'Detect LF/CRLF conflict from addition of text=auto''
@@ -143,7 +150,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' 'gitreset--hardb&&test_must_failgitmergea&&fuzz_conflictfile>file.fuzzy&&-test_cmpexpectedfile.fuzzy+compare_filesexpectedfile.fuzzy' test_expect_failure'checkout -m after setting text=auto''
@@ -158,7 +165,7 @@ test_expect_failure 'checkout -m after setting text=auto' 'gitreset--hardinitial&&gitcheckouta--.&&gitcheckout-mb&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_failure'checkout -m addition of text=auto''
@@ -173,7 +180,7 @@ test_expect_failure 'checkout -m addition of text=auto' 'gitreset--hardinitial&&gitcheckoutb--.&&gitcheckout-ma&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_failure'cherry-pick patch from after text=auto was added''
@@ -187,7 +194,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' 'gitreset--hardb&&test_must_failgitcherry-picka>err2>&1&&grep"[Nn]othing added"err&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Test delete/normalize conflict''
From: Torsten Bögershausen <redacted>
When statistics are done for the autocrlf handling, the search in
the content can be stopped, if e.g
- a search for binary is done, and a NUL character is found
- a search for CRLF is done, and the first CRLF is found.
Similar when statistics for binary vs non-binary are gathered:
Whenever a lone CR or NUL is found, the search can be aborted.
When checking out files in "auto" mode, any file that has a "lone CR"
or a CRLF will not be converted, so the search can be aborted early.
Add the new bit, CONVERT_STAT_BITS_ANY_CR,
which is set for either lone CR or CRLF.
Many binary files have a NUL very early (within the first few bytes,
latest within the first 1..2K).
It is often not necessary to load the whole content of a file or blob
into memory.
Use a streaming handling for blobs and files in the worktree.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 159 ++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 103 insertions(+), 56 deletions(-)
@@ -13,10 +14,10 @@*translationwhenthe"text"attributeor"auto_crlf"optionisset.*/-/* Stat bits: When BIN is set, the txt bits are unset */#define CONVERT_STAT_BITS_TXT_LF 0x1#define CONVERT_STAT_BITS_TXT_CRLF 0x2#define CONVERT_STAT_BITS_BIN 0x4+#define CONVERT_STAT_BITS_ANY_CR 0x8enumcrlf_action{CRLF_UNDEFINED,
@@ -31,30 +32,36 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignednul,lonecr,lonelf,crlf;+unsignedstat_bits,lonecr,lonelf,crlf;/* These are just approximations! */unsignedprintable,nonprintable;};-staticvoidgather_stats(constchar*buf,unsignedlongsize,structtext_stat*stats)+staticvoiddo_gather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout){unsignedlongi;-memset(stats,0,sizeof(*stats));-+if(!buf||!size)+return;for(i=0;i<size;i++){unsignedcharc=buf[i];if(c=='\r'){+stats->stat_bits|=CONVERT_STAT_BITS_ANY_CR;if(i+1<size&&buf[i+1]=='\n'){stats->crlf++;i++;-}else+stats->stat_bits|=CONVERT_STAT_BITS_TXT_CRLF;+}else{stats->lonecr++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}continue;}if(c=='\n'){stats->lonelf++;+stats->stat_bits|=CONVERT_STAT_BITS_TXT_LF;continue;}if(c==127)
@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats->printable++;break;case0:-stats->nul++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;/* fall through */default:stats->nonprintable++;
@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *}elsestats->printable++;+if(stats->stat_bits&earlyout)+break;/* We found what we have been searching for */}/* If file ends with EOF then don't count this EOF as non-printable. */
@@ -86,41 +95,62 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat **Thesameheuristicsasdiff.c::mmfile_is_binary()*WetreatfileswithbareCRasbinary*/-staticintconvert_is_binary(unsignedlongsize,conststructtext_stat*stats)+staticvoidconvert_nonprintable(structtext_stat*stats){-if(stats->lonecr)-return1;-if(stats->nul)-return1;if((stats->printable>>7)<stats->nonprintable)-return1;-return0;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}++staticvoidgather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout)+{+memset(stats,0,sizeof(*stats));+do_gather_stats(buf,size,stats,earlyout);+convert_nonprintable(stats);}-staticunsignedintgather_convert_stats(constchar*data,unsignedlongsize)++staticunsignedget_convert_stats_sha1(unsignedconstchar*sha1,+unsignedearlyout){+structgit_istream*st;structtext_statstats;-intret=0;-if(!data||!size)-return0;-gather_stats(data,size,&stats);-if(convert_is_binary(size,&stats))-ret|=CONVERT_STAT_BITS_BIN;-if(stats.crlf)-ret|=CONVERT_STAT_BITS_TXT_CRLF;-if(stats.lonelf)-ret|=CONVERT_STAT_BITS_TXT_LF;+enumobject_typetype;+unsignedlongsz;-returnret;+if(!sha1)+return0;+memset(&stats,0,sizeof(stats));+st=open_istream(sha1,&type,&sz,NULL);+if(!st){+return0;+}+if(type!=OBJ_BLOB)+gotoclose_and_exit_i;+for(;;){+charbuf[1024];+ssize_treadlen=read_istream(st,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close_and_exit_i:+close_istream(st);+convert_nonprintable(&stats);+returnstats.stat_bits;}-staticconstchar*gather_convert_stats_ascii(constchar*data,unsignedlongsize)+staticconstchar*convert_stats_ascii(unsignedconvert_stats){-unsignedintconvert_stats=gather_convert_stats(data,size);-+unsignedmask=CONVERT_STAT_BITS_TXT_LF|+CONVERT_STAT_BITS_TXT_CRLF;if(convert_stats&CONVERT_STAT_BITS_BIN)return"-text";-switch(convert_stats){+switch(convert_stats&mask){caseCONVERT_STAT_BITS_TXT_LF:return"lf";caseCONVERT_STAT_BITS_TXT_CRLF:
@@ -132,24 +162,45 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si}}+staticunsignedget_convert_stats_wt(constchar*path)+{+structtext_statstats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+intfd;+memset(&stats,0,sizeof(stats));+fd=open(path,O_RDONLY);+if(fd<0)+return0;+for(;;){+charbuf[1024];+ssize_treadlen=read(fd,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close(fd);+convert_nonprintable(&stats);+returnstats.stat_bits;+}+constchar*get_cached_convert_stats_ascii(constchar*path){-constchar*ret;-unsignedlongsz;-void*data=read_blob_data_from_cache(path,&sz);-ret=gather_convert_stats_ascii(data,sz);-free(data);-returnret;+unsignedconvert_stats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+convert_stats=get_convert_stats_sha1(get_sha1_from_cache(path),+earlyout);+returnconvert_stats_ascii(convert_stats);}constchar*get_wt_convert_stats_ascii(constchar*path){-constchar*ret="";-structstrbufsb=STRBUF_INIT;-if(strbuf_read_file(&sb,path,0)>=0)-ret=gather_convert_stats_ascii(sb.buf,sb.len);-strbuf_release(&sb);-returnret;+unsignedconvert_stats;+convert_stats=get_convert_stats_wt(path);+returnconvert_stats_ascii(convert_stats);}staticinttext_eol_is_crlf(void)
From: Torsten Bögershausen <redacted>
When statistics are done for the autocrlf handling, the search in
the content can be stopped, if e.g
- a search for binary is done, and a NUL character is found
- a search for CRLF is done, and the first CRLF is found.
Similar when statistics for binary vs non-binary are gathered:
Whenever a lone CR or NUL is found, the search can be aborted.
When checking out files in "auto" mode, any file that has a "lone CR"
or a CRLF will not be converted, so the search can be aborted early.
Add the new bit, CONVERT_STAT_BITS_ANY_CR,
which is set for either lone CR or CRLF.
Many binary files have a NUL very early (within the first few bytes,
latest within the first 1..2K).
It is often not necessary to load the whole content of a file or blob
into memory.
Use a streaming handling for blobs and files in the worktree.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 159 ++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 103 insertions(+), 56 deletions(-)
@@ -13,10 +14,10 @@*translationwhenthe"text"attributeor"auto_crlf"optionisset.*/-/* Stat bits: When BIN is set, the txt bits are unset */#define CONVERT_STAT_BITS_TXT_LF 0x1#define CONVERT_STAT_BITS_TXT_CRLF 0x2#define CONVERT_STAT_BITS_BIN 0x4+#define CONVERT_STAT_BITS_ANY_CR 0x8enumcrlf_action{CRLF_UNDEFINED,
@@ -31,30 +32,36 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignednul,lonecr,lonelf,crlf;+unsignedstat_bits,lonecr,lonelf,crlf;/* These are just approximations! */unsignedprintable,nonprintable;};-staticvoidgather_stats(constchar*buf,unsignedlongsize,structtext_stat*stats)+staticvoiddo_gather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout){unsignedlongi;-memset(stats,0,sizeof(*stats));-+if(!buf||!size)+return;for(i=0;i<size;i++){unsignedcharc=buf[i];if(c=='\r'){+stats->stat_bits|=CONVERT_STAT_BITS_ANY_CR;if(i+1<size&&buf[i+1]=='\n'){stats->crlf++;i++;-}else+stats->stat_bits|=CONVERT_STAT_BITS_TXT_CRLF;+}else{stats->lonecr++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}continue;}if(c=='\n'){stats->lonelf++;+stats->stat_bits|=CONVERT_STAT_BITS_TXT_LF;continue;}if(c==127)
@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats->printable++;break;case0:-stats->nul++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;/* fall through */default:stats->nonprintable++;
@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *}elsestats->printable++;+if(stats->stat_bits&earlyout)+break;/* We found what we have been searching for */}/* If file ends with EOF then don't count this EOF as non-printable. */
@@ -86,41 +95,62 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat **Thesameheuristicsasdiff.c::mmfile_is_binary()*WetreatfileswithbareCRasbinary*/-staticintconvert_is_binary(unsignedlongsize,conststructtext_stat*stats)+staticvoidconvert_nonprintable(structtext_stat*stats){-if(stats->lonecr)-return1;-if(stats->nul)-return1;if((stats->printable>>7)<stats->nonprintable)-return1;-return0;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}++staticvoidgather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout)+{+memset(stats,0,sizeof(*stats));+do_gather_stats(buf,size,stats,earlyout);+convert_nonprintable(stats);}-staticunsignedintgather_convert_stats(constchar*data,unsignedlongsize)++staticunsignedget_convert_stats_sha1(unsignedconstchar*sha1,+unsignedearlyout){+structgit_istream*st;structtext_statstats;-intret=0;-if(!data||!size)-return0;-gather_stats(data,size,&stats);-if(convert_is_binary(size,&stats))-ret|=CONVERT_STAT_BITS_BIN;-if(stats.crlf)-ret|=CONVERT_STAT_BITS_TXT_CRLF;-if(stats.lonelf)-ret|=CONVERT_STAT_BITS_TXT_LF;+enumobject_typetype;+unsignedlongsz;-returnret;+if(!sha1)+return0;+memset(&stats,0,sizeof(stats));+st=open_istream(sha1,&type,&sz,NULL);+if(!st){+return0;+}+if(type!=OBJ_BLOB)+gotoclose_and_exit_i;+for(;;){+charbuf[1024];+ssize_treadlen=read_istream(st,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close_and_exit_i:+close_istream(st);+convert_nonprintable(&stats);+returnstats.stat_bits;}-staticconstchar*gather_convert_stats_ascii(constchar*data,unsignedlongsize)+staticconstchar*convert_stats_ascii(unsignedconvert_stats){-unsignedintconvert_stats=gather_convert_stats(data,size);-+unsignedmask=CONVERT_STAT_BITS_TXT_LF|+CONVERT_STAT_BITS_TXT_CRLF;if(convert_stats&CONVERT_STAT_BITS_BIN)return"-text";-switch(convert_stats){+switch(convert_stats&mask){caseCONVERT_STAT_BITS_TXT_LF:return"lf";caseCONVERT_STAT_BITS_TXT_CRLF:
@@ -132,24 +162,45 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si}}+staticunsignedget_convert_stats_wt(constchar*path)+{+structtext_statstats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+intfd;+memset(&stats,0,sizeof(stats));+fd=open(path,O_RDONLY);+if(fd<0)+return0;+for(;;){+charbuf[1024];+ssize_treadlen=read(fd,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close(fd);+convert_nonprintable(&stats);+returnstats.stat_bits;+}+constchar*get_cached_convert_stats_ascii(constchar*path){-constchar*ret;-unsignedlongsz;-void*data=read_blob_data_from_cache(path,&sz);-ret=gather_convert_stats_ascii(data,sz);-free(data);-returnret;+unsignedconvert_stats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+convert_stats=get_convert_stats_sha1(get_sha1_from_cache(path),+earlyout);+returnconvert_stats_ascii(convert_stats);}constchar*get_wt_convert_stats_ascii(constchar*path){-constchar*ret="";-structstrbufsb=STRBUF_INIT;-if(strbuf_read_file(&sb,path,0)>=0)-ret=gather_convert_stats_ascii(sb.buf,sb.len);-strbuf_release(&sb);-returnret;+unsignedconvert_stats;+convert_stats=get_convert_stats_wt(path);+returnconvert_stats_ascii(convert_stats);}staticinttext_eol_is_crlf(void)
From: Torsten Bögershausen <redacted>
Even though the configuration parser errors out when core.autocrlf
is set to 'input' when core.eol is set to 'crlf', there is no need
to do so, because the core.autocrlf setting trumps core.eol.
Allow all combinations of core.crlf and core.eol and document
that core.autocrlf overrides core.eol.
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 6 +++---
config.c | 4 ----
2 files changed, 3 insertions(+), 7 deletions(-)
@@ -337,9 +337,9 @@ core.quotePath:: core.eol:: Sets the line ending type to use in the working directory for- files that have the `text` property set. Alternatives are- 'lf', 'crlf' and 'native', which uses the platform's native- line ending. The default value is `native`. See+ files that have the `text` property set when core.autocrlf is false.+ Alternatives are 'lf', 'crlf' and 'native', which uses the platform's+ native line ending. The default value is `native`. See linkgit:gitattributes[5] for more information on end-of-line conversion.
From: Torsten Bögershausen <redacted>
When the content of a commited file is unchanged and the attributes are changed,
Git may not detect that the next commit must treat the file as changed.
This happens when lstat() doesn't detect a change, since neither inode,
mtime nor size are changed.
Add a singe "Z" character to change the file size (and content).
When the files are compared later in checkout_files(), the "Z" is removed
before the comparison.
Signed-off-by: Torsten Bögershausen <redacted>
---
Changes since v5:
- send the whole series, now 10/10
- Removed the "will change in future" in one commit msg
- Don't leak the filer in 4/10
t/t0027-auto-crlf.sh | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Changes since v6:
- Reword commit msg in 1/10
- Add SOB in 9/10
- Correct typos
From: Torsten Bögershausen <redacted>
Add more test cases for the not normalized files ("NNO"). The
"text" attribute is most important, use it as the first parameter.
"ident", if set, is the second paramater followed by the eol
attribute. The eol attribute overrides core.autocrlf, which
overrides core.eol.
indent is not yet used, this will be done in the next commit.
Use loops to test more combinations of attributes, like
"* text eol=crlf" or especially "*text=auto eol=crlf".
Signed-off-by: Torsten Bögershausen <redacted>
---
t/t0027-auto-crlf.sh | 298 ++++++++++++++++++++++-----------------------------
1 file changed, 129 insertions(+), 169 deletions(-)
@@ -100,16 +103,17 @@ commit_check_warn () {} commit_chk_wrnNNO(){-crlf=$1-attr=$2-lfwarn=$3-crlfwarn=$4-lfmixcrlf=$5-lfmixcr=$6-crlfnul=$7-pfx=NNO_${crlf}_attr_${attr}+attr=$1;shift+aeol=$1;shift+crlf=$1;shift+lfwarn=$1;shift+crlfwarn=$1;shift+lfmixcrlf=$1;shift+lfmixcr=$1;shift+crlfnul=$1;shift+pfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}#Commit files on top of existing file-create_gitattributes"$attr"&&+create_gitattributes"$attr"$aeol&&forfinLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldofname=${pfx}_$f.txt&&
@@ -163,6 +167,7 @@ stats_ascii () {# contruct the attr/ returned by git ls-files --eol# Take none (=empty), one or two args+# convert.c: eol=XX overrides text=auto attr_ascii(){case$1,$2in-text,*)echo"-text";;
@@ -441,24 +447,20 @@ test_expect_success 'commit -text' 'check_files_in_repoinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul'-# attr LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL-check_in_repo_NNOfalse""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"auto"LFLFLFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtrue"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOinput"text"LFLFLFLF_mix_CRLF_nul--check_in_repo_NNOfalse"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--+forcrlfintruefalseinput+do+# attr aeol LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL+check_in_repo_NNO""""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-text""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOauto""$crlfLFLFLFLF_mix_CRCRLF_nul+check_in_repo_NNOautolf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOautocrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+done################################################################################# Check how files in the repo are changed when they are checked out# How to read the table below:
@@ -490,89 +492,47 @@ LFNUL=LF_nulfiexportCRLF_MIX_LF_CRMIXNL-checkout_files""""""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""true""CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truecrlfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truelfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truenativeCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""true""CRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truelfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truenativeCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul--foridin""ident;+# Same handling with and without ident+foridin""do-checkout_files"crlf""$id"""false""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falselfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""input""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""inputlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"lf""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"-text""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+forceolinlfcrlfnative+do+forcrlfintruefalseinput+do+# -text overrides core.autocrlf and core.eol+# text and eol=crlf or eol=lf override core.autocrlf and core.eol+checkout_files-text"$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files-text"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files-text"$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text+checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# currently the same as text, eol=XXX+checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+done++# core.autocrlf false, different core.eol+checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# core.autocrlf true+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf = true overrides core.eol+checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLFLF_mix_CRLF_nul+checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# text: core.autocrlf = input overrides core.eol+checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text=auto + eol=XXX+done+# text: core.autocrlf=false uses core.eol+checkout_filestext"$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+# auto: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_filesauto"$id"""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
Factor out the retrieval of the sha1 for a given path in
read_blob_data_from_index() into the function get_sha1_from_index().
This will be used in the next commit, when convert.c can do the
analyze for "text=auto" without slurping the whole blob into memory
at once.
Add a wrapper definition get_sha1_from_cache().
Signed-off-by: Torsten Bögershausen <redacted>
---
cache.h | 3 +++
read-cache.c | 29 ++++++++++++++++++-----------
2 files changed, 21 insertions(+), 11 deletions(-)
From: Torsten Bögershausen <redacted>
When the ident attributes is set, get_stream_filter() did not obey
core.autocrlf=true, and the file was checked out with LF.
Change the rule when a streaming filter can be used:
- if an external filter is specified, don't use a stream filter.
- if the worktree eol is CRLF and "auto" is active, don't use a stream filter.
- Otherwise the stream filter can be used.
Add test cases in t0027.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 19 +++++++------------
t/t0027-auto-crlf.sh | 2 +-
2 files changed, 8 insertions(+), 13 deletions(-)
From: Torsten Bögershausen <redacted>
Before this change,
$ echo "* text=auto" >.gitattributes
$ echo "* eol=crlf" >>.gitattributes
would have the same effect as
$ echo "* text" >.gitattributes
$ git config core.eol crlf
Since the 'eol' attribute had higher priority than 'text=auto', this may
corrupt binary files and is not what users expect to happen.
Make the 'eol' attribute to obey 'text=auto', and now
$ echo "* text=auto" >.gitattributes
$ echo "* eol=crlf" >>.gitattributes
behaves the same as
$ echo "* text=auto" >.gitattributes
$ git config core.eol crlf
In other words,
$ echo "* text=auto eol=crlf" >.gitattributes
has the same effect as
$ git config core.autocrlf true
and
$ echo "* text=auto eol=lf" >.gitattributes
has the same effect as
$ git config core.autocrlf input
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 14 +++++++-------
Documentation/gitattributes.txt | 15 +++++++++------
convert.c | 42 +++++++++++++++++++++--------------------
convert.h | 3 ++-
t/t0025-crlf-auto.sh | 4 ++--
t/t0027-auto-crlf.sh | 32 +++++++++++++++----------------
t/t6038-merge-text-auto.sh | 23 ++++++++++++++--------
7 files changed, 73 insertions(+), 60 deletions(-)
@@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf` mechanism. core.autocrlf::- Setting this variable to "true" is almost the same as setting- the `text` attribute to "auto" on all files except that text- files are not guaranteed to be normalized: files that contain- `CRLF` in the repository will not be touched. Use this- setting if you want to have `CRLF` line endings in your- working directory even though the repository does not have- normalized line endings. This variable can be set to 'input',+ Setting this variable to "true" is the same as setting+ the `text` attribute to "auto" on all files and core.eol to "crlf".+ Set to true if you want to have `CRLF` line endings in your+ working directory and the repository has LF line endings.+ Text files are guaranteed not to be normalized: files that contain+ `CRLF` in the repository will not be touched.+ This variable can be set to 'input', in which case no output conversion is performed. core.symlinks::
@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the `core.eol` configuration variable for all text files.+Note that `core.autocrlf` overrides `core.eol` Set::
@@ -130,8 +131,9 @@ Unset:: Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic- end-of-line normalization. If Git decides that the content is- text, its line endings are normalized to LF on checkin.+ end-of-line conversion. If Git decides that the content is+ text, its line endings are converted to LF on checkin.+ When the file has been commited with CRLF, no conversion is done. Unspecified::
@@ -146,7 +148,7 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It enables end-of-line normalization without any+working directory. It enables end-of-line conversion without any content checks, effectively setting the `text` attribute. Set to string value "crlf"::
@@ -186,9 +188,10 @@ the working directory, and prevent .jpg files from being normalized regardless of their content. ------------------------+* text=auto *.txt text-*.vcproj eol=crlf-*.sh eol=lf+*.vcproj text eol=crlf+*.sh text eol=lf *.jpg -text ------------------------
@@ -198,7 +201,7 @@ normalization in Git. If you simply want to have CRLF line endings in your working directory regardless of the repository you are working with, you can set the-config variable "core.autocrlf" without changing any attributes.+config variable "core.autocrlf" without using any attributes. ------------------------ [core]
@@ -227,7 +227,9 @@ static enum eol output_eol(enum crlf_action crlf_action)returnEOL_LF;caseCRLF_UNDEFINED:caseCRLF_AUTO_CRLF:+returnEOL_CRLF;caseCRLF_AUTO_INPUT:+returnEOL_LF;caseCRLF_TEXT:caseCRLF_AUTO:/* fall through */
@@ -299,17 +301,15 @@ static int crlf_to_git(const char *path, const char *src, size_t len,if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;--if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/*-*IfthefileintheindexhasanyCRinit,donotconvert.-*Thisisthenewsaferautocrlfhandling.-*/-if(has_cr_in_index(path))-return0;-}+/*+*IfthefileintheindexhasanyCRinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+if(checksafe==SAFE_CRLF_RENORMALIZE)+checksafe=SAFE_CRLF_FALSE;+elseif(has_cr_in_index(path))+return0;}-check_safe_crlf(path,crlf_action,&stats,checksafe);/* Optimization: No CRLF? Nothing to convert, regardless. */
@@ -367,12 +367,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,return0;if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;-}+/* If we have any CR or CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(stats.lonecr||stats.crlf)+return0;if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;
@@ -892,9 +894,9 @@ const char *get_convert_attr_ascii(const char *path)caseCRLF_AUTO:return"text=auto";caseCRLF_AUTO_CRLF:-return"text=auto eol=crlf";/* This is not supported yet */+return"text=auto eol=crlf";caseCRLF_AUTO_INPUT:-return"text=auto eol=lf";/* This is not supported yet */+return"text=auto eol=lf";}return"";}
@@ -493,7 +492,8 @@ fiexportCRLF_MIX_LF_CRMIXNL# Same handling with and without ident-foridin""ident+#for id in "" ident+foridin""doforceolinlfcrlfnativedo
@@ -509,7 +509,7 @@ docheckout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul# currently the same as text, eol=XXXcheckout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# core.autocrlf false, different core.eol
@@ -531,8 +531,8 @@ docheckout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNULcheckout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL# auto: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filesauto"$id"""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
@@ -81,7 +88,7 @@ test_expect_success 'Merge after setting text=auto' 'rm-f.gitattributes&&gitreset--harda&&gitmergeb&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Merge addition of text=auto''
@@ -99,7 +106,7 @@ test_expect_success 'Merge addition of text=auto' 'rm-f.gitattributes&&gitreset--hardb&&gitmergea&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Detect CRLF/LF conflict after setting text=auto''
@@ -121,7 +128,7 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' 'gitreset--harda&&test_must_failgitmergeb&&fuzz_conflictfile>file.fuzzy&&-test_cmpexpectedfile.fuzzy+compare_filesexpectedfile.fuzzy' test_expect_success'Detect LF/CRLF conflict from addition of text=auto''
@@ -143,7 +150,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' 'gitreset--hardb&&test_must_failgitmergea&&fuzz_conflictfile>file.fuzzy&&-test_cmpexpectedfile.fuzzy+compare_filesexpectedfile.fuzzy' test_expect_failure'checkout -m after setting text=auto''
@@ -158,7 +165,7 @@ test_expect_failure 'checkout -m after setting text=auto' 'gitreset--hardinitial&&gitcheckouta--.&&gitcheckout-mb&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_failure'checkout -m addition of text=auto''
@@ -173,7 +180,7 @@ test_expect_failure 'checkout -m addition of text=auto' 'gitreset--hardinitial&&gitcheckoutb--.&&gitcheckout-ma&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_failure'cherry-pick patch from after text=auto was added''
@@ -187,7 +194,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' 'gitreset--hardb&&test_must_failgitcherry-picka>err2>&1&&grep"[Nn]othing added"err&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Test delete/normalize conflict''
From: Torsten Bögershausen <redacted>
We define the working tree file is clean if either:
* the result of running convert_to_git() on the working tree
contents matches what is in the index (because that would mean
doing another "git add" on the path is a no-op); OR
* the result of running convert_to_working_tree() on the content
in the index matches what is in the working tree (because that
would mean doing another "git checkout -f" on the path is a
no-op).
Add an extra check in ce_compare_data() in read_cache.c.
Helped-by: Junio C Hamano [off-list ref]
Signed-off-by: Torsten Bögershausen <redacted>
---
read-cache.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
t/t6038-merge-text-auto.sh | 14 +++++------
2 files changed, 68 insertions(+), 7 deletions(-)
@@ -156,17 +156,78 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)ce_mark_uptodate(ce);}+/*+*Comparethedatainbufwiththedatainthefilepointedbyfdand+*return0iftheyareidentical,andnon-zeroiftheydiffer.+*/+staticintcompare_with_fd(constchar*input,ssize_tlen,intfd)+{+for(;;){+charbuf[1024*16];+ssize_tchunk_len,read_len;++chunk_len=sizeof(buf)<len?sizeof(buf):len;+read_len=xread(fd,buf,chunk_len?chunk_len:1);++if(!read_len)+/* EOF on the working tree file */+return!len?0:-1;++if(!len)+/* we expected there is nothing left */+return-1;++if(memcmp(buf,input,read_len))+return-1;+input+=read_len;+len-=read_len;+}+}+staticintce_compare_data(conststructcache_entry*ce,structstat*st){intmatch=-1;intfd=open(ce->name,O_RDONLY);+/*+*Wouldanother"git add"onthepathchangewhatisinthe+*indexforthepath?+*/if(fd>=0){unsignedcharsha1[20];if(!index_fd(sha1,fd,st,OBJ_BLOB,ce->name,0))match=hashcmp(sha1,ce->sha1);/* index_fd() closed the file descriptor already */}+if(!match)+returnmatch;++/*+*Wouldanother"git checkout -f"outoftheindexchange+*whatisintheworkingtreefile?+*/+fd=open(ce->name,O_RDONLY);+if(fd>=0){+enumobject_typetype;+unsignedlongsize_long;+void*data=read_sha1_file(ce->sha1,&type,&size_long);++if(type==OBJ_BLOB){+structstrbufworktree=STRBUF_INIT;+if(convert_to_working_tree(ce->name,data,+size_long,+&worktree)){+size_tsize;+free(data);+data=strbuf_detach(&worktree,&size);+size_long=size;+}+if(!compare_with_fd(data,size_long,fd))+match=0;+}+free(data);+close(fd);+}returnmatch;}
From: Torsten Bögershausen <redacted>
t6038 uses different code, dependig if NATIVE_CRLF is set ot not.
When the native line endings are LF, merge.renormalize is not tested very well.
Change the test to always use CRLF by setting core.eol=crlf.
After doing so, the test fails:
rm '.gitattributes'
rm 'control_file'
rm 'file'
rm 'inert_file'
HEAD is now at 0d9ffb6 add line from b
error: addinfo_cache failed for path 'file'
file: unmerged (cbd69ec7cd12dd0989e853923867d94c8519aa52)
file: unmerged (ad55e240aeb42e0d9a0e18d6d8b02dd82ee3e527)
file: unmerged (99b633103c15c20cebebf821133ab526b0ff90b2)
fatal: git write-tree failed to write a tree
Merging:
0d9ffb6 add line from b
virtual a
found 1 common ancestor:
1c56df1 Initial
Auto-merging file
not ok 4 - Merge addition of text=auto
This will be addressed in the next commit.
Signed-off-by: Torsten Bögershausen <redacted>
---
t/t6038-merge-text-auto.sh | 37 +++++++++++--------------------------
1 file changed, 11 insertions(+), 26 deletions(-)
From: Torsten Bögershausen <redacted>
This patch extends the work done in commit c480539:
"Make it work also for un-normalized repositories". Make sure that CRLF
can be converted round trip, or don't convert them at all.
The old handling would treat a file as unchanged after checkout,
as long as it is not touched in the work tree and mtime matches the value
recorded in the index.
When the mtime is changed in the working tree, or the inode is changed,
the file is reported as modified.
The following sequence is now handled reproducable:
$ git init
$ printf "line1\r\n" >file.bat
$ git add file.bat
$ git commit -m "Add file with CRLF" file.bat
$ echo "*.bat text eol=crlf" >.gitattributes
$ git commit -m "bat files should have CRLF"
$ git status
# nothing to commit, working directory clean
$ git push <upstream>
$ printf "newline\r\n" >>file.bat
$ mv file.bat file.sav
$ git checkout file.bat
$ git status
#modified: file.bat
The new handling makes sure that after running "git reset --hard".
"git status" reports the working tree as clean regarding CRLF conversion.
It makes sure that the Git-internal eol conversion is
doing roundtrip. A user can still write an external smudge/clean filter
outside Git, which doesn't do a roundtrip and the working directory is
not clean.
The functionality of has_cr_in_index() is turned into has_crlf_in_index(),
and the function is integrated into would_convert_crlf_at_commit().
Check for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR
is no longer used and removed, as well as "lonecr" in struct text_stat.
Rewrite check_safe_crlf() in convert.c to simulate checkin-checkout,
to detect whether any line endings are converted.
Add a warning, similar to the CRLF-LF replacement, when a file is commited,
and after the next checkout the line endings are not what they should be.
Modify the lf_to_crlf_filter:
Files with LF are converted into CRLF, file with CRLF are not changed.
Files with mixed line endings are not converted, the filter fails, and Git
falls back to the non-streaming handling, see write_entry().
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/gitattributes.txt | 19 ++--
convert.c | 233 +++++++++++++++++++++++++---------------
t/t0025-crlf-auto.sh | 8 +-
t/t0027-auto-crlf.sh | 92 ++++++++--------
4 files changed, 212 insertions(+), 140 deletions(-)
@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'. `text` ^^^^^^-This attribute enables and controls end-of-line normalization. When a+This attribute enables and controls end-of-line conversion. When a text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the
@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol` Set:: Setting the `text` attribute on a path enables end-of-line- normalization and marks the path as a text file. End-of-line+ conversion and marks the path as a text file. End-of-line conversion takes place without guessing the content type.+ Files that have been commited with CRLF before the text attribute+ is set and commited are not normalized. No end-of-line conversion+ is done at checkout or checkin. Unset::
@@ -131,9 +134,9 @@ Unset:: Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic- end-of-line conversion. If Git decides that the content is- text, its line endings are converted to LF on checkin.- When the file has been commited with CRLF, no conversion is done.+ end-of-line normalization. If Git decides that the content is+ text, and the path has no CRLF in the index,+ its line endings are converted to LF on checkin. Unspecified::
@@ -148,8 +151,10 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It enables end-of-line conversion without any-content checks, effectively setting the `text` attribute.+working directory. It sets the `text` attribute, unless `text=auto`+is specified.+When the file had been commited with CRLF in the index, no conversion+is done at checkout or commit. Set to string value "crlf"::
@@ -32,7 +33,7 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignedstat_bits,lonecr,lonelf,crlf;+unsignedstat_bits,lonelf;/* These are just approximations! */unsignedprintable,nonprintable;
@@ -135,7 +133,7 @@ static unsigned get_convert_stats_sha1(unsigned const char *sha1,if(!readlen)break;do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);-if(stats.stat_bits&earlyout)+if((stats.stat_bits&earlyout)==earlyout)break;/* We found what we have been searching for */}close_and_exit_i:
@@ -239,43 +228,95 @@ static enum eol output_eol(enum crlf_action crlf_action)returncore_eol;}+staticintwould_convert_lf_at_checkout(unsignedconvert_stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+if(output_eol(crlf_action)!=EOL_CRLF)+return0;++/* No "naked" LF? Nothing to convert, regardless. */+if(!convert_stats&CONVERT_STAT_BITS_TXT_LF)+return0;++if(crlf_action==CRLF_AUTO||+crlf_action==CRLF_AUTO_INPUT||+crlf_action==CRLF_AUTO_CRLF){+/* auto: binary files are not converted */+if(convert_stats&CONVERT_STAT_BITS_BIN)+return0;+}+/* If we have any CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;++}++staticintwould_convert_crlf_at_commit(constchar*path,+conststructtext_stat*stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+unsignedstat_bits_index;+/* No CRLF? Nothing to convert, regardless. */+if(!(stats->stat_bits&CONVERT_STAT_BITS_TXT_CRLF))+return0;+/*+*IfthefileintheindexhasanyCRLFinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+stat_bits_index=get_convert_stats_sha1(get_sha1_from_cache(path),+CONVERT_STAT_BITS_TXT_CRLF);+if(stat_bits_index&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;+}+staticvoidcheck_safe_crlf(constchar*path,enumcrlf_actioncrlf_action,-structtext_stat*stats,enumsafe_crlfchecksafe)+enumsafe_crlfchecksafe,+unsignedconvert_stats,unsignednew_convert_stats){+enumeolnew_eol=output_eol(crlf_action);+constchar*err_warn_msg=NULL;if(!checksafe)return;--if(output_eol(crlf_action)==EOL_LF){+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)){/**CRLFswouldnotberestoredbycheckout:*checkifwe'dremoveCRLFs*/-if(stats->crlf){-if(checksafe==SAFE_CRLF_WARN)-warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("CRLF would be replaced by LF in %s.",path);-}-}elseif(output_eol(crlf_action)==EOL_CRLF){+if(checksafe==SAFE_CRLF_WARN)+warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("CRLF would be replaced by LF in %s.",path);+}+if(convert_stats&CONVERT_STAT_BITS_TXT_LF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_LF)){/**CRLFswouldbeaddedbycheckout:*checkifwehave"naked"LFs*/-if(stats->lonelf){-if(checksafe==SAFE_CRLF_WARN)-warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("LF would be replaced by CRLF in %s",path);-}+if(checksafe==SAFE_CRLF_WARN)+warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("LF would be replaced by CRLF in %s",path);+}+if((new_convert_stats&CONVERT_STAT_BITS_MIXED)==CONVERT_STAT_BITS_MIXED)+err_warn_msg="mixed eol";+elseif(new_eol==EOL_LF&&new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+err_warn_msg="CRLF";++if(err_warn_msg){+if(checksafe==SAFE_CRLF_WARN)+warning("%s will be present after commit and checkout in %s.",+err_warn_msg,path);+else+die("%s will be present after commit and checkout in %s",+err_warn_msg,path);}-}--staticinthas_cr_in_index(constchar*path)-{-unsignedconvert_stats;-convert_stats=get_convert_stats_sha1(get_sha1_from_cache(path),-CONVERT_STAT_BITS_ANY_CR);-returnconvert_stats&CONVERT_STAT_BITS_ANY_CR;}staticintcrlf_to_git(constchar*path,constchar*src,size_tlen,
@@ -354,28 +415,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,{char*to_free=NULL;structtext_statstats;-unsignedearlyout=CONVERT_STAT_BITS_TXT_CRLF|CONVERT_STAT_BITS_BIN;---if(!len||output_eol(crlf_action)!=EOL_CRLF)+unsignedearlyout=0;/* Need to count lonelf */+if(!len)return0;gather_stats(src,len,&stats,earlyout);--/* No "naked" LF? Nothing to convert, regardless. */-if(!stats.lonelf)+if(!would_convert_lf_at_checkout(stats.stat_bits,+len,crlf_action))return0;-if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;--if(stats.stat_bits&CONVERT_STAT_BITS_BIN)-return0;-}-/* are we "faking" in place editing ? */if(src==buf->buf)to_free=strbuf_detach(buf,NULL);
@@ -1067,6 +1115,8 @@ int is_null_stream_filter(struct stream_filter *filter)structlf_to_crlf_filter{structstream_filterfilter;unsignedhas_held:1;+unsignedexpanded_loneLF:1;+unsignedhad_CRLF:1;charheld;};
@@ -1107,7 +1157,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,charch=input[i];if(ch=='\n'){-output[o++]='\r';+if(!lf_to_crlf->had_CRLF){+output[o++]='\r';+lf_to_crlf->expanded_loneLF=1;+}+if(was_cr)+lf_to_crlf->had_CRLF=1;}elseif(was_cr){/**PreviousroundsawCRanditisnotfollowed
@@ -1136,6 +1191,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,was_cr=0;output[o++]=ch;+if(lf_to_crlf->expanded_loneLF&&+lf_to_crlf->had_CRLF){+/*+*MixedEOL,roundtripnotpossible.+*/+return1;+}+}*osize_p-=o;
@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' 'test-z"$LFonlydiff"-a-z"$CRLFonlydiff"-a-z"$LFwithNULdiff"'-test_expect_success'crlf=true causes a CRLF file to be normalized''+test_expect_success'crlf=true causes a CRLF file not to be normalized''# Backwards compatibility checkrm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&
@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"'-test_expect_success'text=true causes a CRLF file to be normalized''+test_expect_success'text=true causes a CRLF file not to be normalized''rm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&echo"CRLFonly text">.gitattributes&&
@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"' test_expect_success'eol=crlf gives a normalized file CRLFs with autocrlf=false''
@@ -71,10 +71,14 @@ check_warning () {case"$1"inLF_CRLF)echo"warning: LF will be replaced by CRLF">"$2".expect;;CRLF_LF)echo"warning: CRLF will be replaced by LF">"$2".expect;;+CRLF)echo"warning: CRLF will be present after commit and checkout">"$2".expect;;+mixed)echo"warning: mixed eol will be present after commit and checkout">"$2".expect;;'')>"$2".expect;;*)echo>&2"Illegal 1":"$1";returnfalse;;esac-grep"will be replaced by""$2"|sed-e"s/\(.*\) in [^ ]*$/\1/"|uniq>"$2".actual+egrep"will be replaced by|will be present after commit""$2"|+sed-e"s/\(.*\) in [^ ]*$/\1/"|+uniq>"$2".actualtest_cmp"$2".expect"$2".actual}
@@ -169,7 +173,7 @@ stats_ascii () {# Take none (=empty), one or two args# convert.c: eol=XX overrides text=auto attr_ascii(){-case$1,$2in+case"$1","$2"in-text,*)echo"-text";;text,)echo"text";;text,lf)echo"text eol=lf";;
@@ -456,9 +463,9 @@ docheck_in_repo_NNOauto""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautolf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautocrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldone################################################################################# Check how files in the repo are changed when they are checked out
@@ -492,8 +497,7 @@ fiexportCRLF_MIX_LF_CRMIXNL# Same handling with and without ident-#for id in "" ident-foridin""+foridin""identdoforceolinlfcrlfnativedo
@@ -501,38 +505,38 @@ dodo# -text overrides core.autocrlf and core.eol# text and eol=crlf or eol=lf override core.autocrlf and core.eol-checkout_files-text"$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files-text"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files-text"$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text-checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul# currently the same as text, eol=XXX-checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# core.autocrlf false, different core.eol-checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# core.autocrlf true-checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text: core.autocrlf = true overrides core.eol-checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul# text: core.autocrlf = input overrides core.eol-checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text=auto + eol=XXXdone# text: core.autocrlf=false uses core.eol-checkout_filestext"$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""falsecrlfCRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul+checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_filestext"$id"""false""$NLCRLFCRLF_mix_LF"$MIX_LF_CR""$LFNUL"+checkout_filestext"$id"""falsenative$NLCRLFCRLF_mix_LF"$MIX_LF_CR""$LFNUL"# auto: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
Add more test cases for the not normalized files ("NNO"). The
"text" attribute is most important, use it as the first parameter.
"ident", if set, is the second paramater followed by the eol
attribute. The eol attribute overrides core.autocrlf, which
overrides core.eol.
indent is not yet used, this will be done in the next commit.
Use loops to test more combinations of attributes, like
"* text eol=crlf" or especially "*text=auto eol=crlf".
Signed-off-by: Torsten Bögershausen <redacted>
---
t/t0027-auto-crlf.sh | 298 ++++++++++++++++++++++-----------------------------
1 file changed, 129 insertions(+), 169 deletions(-)
@@ -100,16 +103,17 @@ commit_check_warn () {} commit_chk_wrnNNO(){-crlf=$1-attr=$2-lfwarn=$3-crlfwarn=$4-lfmixcrlf=$5-lfmixcr=$6-crlfnul=$7-pfx=NNO_${crlf}_attr_${attr}+attr=$1;shift+aeol=$1;shift+crlf=$1;shift+lfwarn=$1;shift+crlfwarn=$1;shift+lfmixcrlf=$1;shift+lfmixcr=$1;shift+crlfnul=$1;shift+pfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}#Commit files on top of existing file-create_gitattributes"$attr"&&+create_gitattributes"$attr"$aeol&&forfinLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldofname=${pfx}_$f.txt&&
@@ -163,6 +167,7 @@ stats_ascii () {# contruct the attr/ returned by git ls-files --eol# Take none (=empty), one or two args+# convert.c: eol=XX overrides text=auto attr_ascii(){case$1,$2in-text,*)echo"-text";;
@@ -441,24 +447,20 @@ test_expect_success 'commit -text' 'check_files_in_repoinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul'-# attr LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL-check_in_repo_NNOfalse""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"auto"LFLFLFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtrue"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOinput"text"LFLFLFLF_mix_CRLF_nul--check_in_repo_NNOfalse"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--+forcrlfintruefalseinput+do+# attr aeol LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL+check_in_repo_NNO""""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-text""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOauto""$crlfLFLFLFLF_mix_CRCRLF_nul+check_in_repo_NNOautolf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOautocrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+done################################################################################# Check how files in the repo are changed when they are checked out# How to read the table below:
@@ -490,89 +492,47 @@ LFNUL=LF_nulfiexportCRLF_MIX_LF_CRMIXNL-checkout_files""""""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""true""CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truecrlfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truelfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truenativeCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""true""CRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truelfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truenativeCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul--foridin""ident;+# Same handling with and without ident+foridin""do-checkout_files"crlf""$id"""false""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falselfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""input""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""inputlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"lf""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"-text""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+forceolinlfcrlfnative+do+forcrlfintruefalseinput+do+# -text overrides core.autocrlf and core.eol+# text and eol=crlf or eol=lf override core.autocrlf and core.eol+checkout_files-text"$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files-text"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files-text"$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text+checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# currently the same as text, eol=XXX+checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+done++# core.autocrlf false, different core.eol+checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# core.autocrlf true+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf = true overrides core.eol+checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLFLF_mix_CRLF_nul+checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# text: core.autocrlf = input overrides core.eol+checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text=auto + eol=XXX+done+# text: core.autocrlf=false uses core.eol+checkout_filestext"$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+# auto: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_filesauto"$id"""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
When the ident attributes is set, get_stream_filter() did not obey
core.autocrlf=true, and the file was checked out with LF.
Change the rule when a streaming filter can be used:
- if an external filter is specified, don't use a stream filter.
- if the worktree eol is CRLF and "auto" is active, don't use a stream filter.
- Otherwise the stream filter can be used.
Add test cases in t0027.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 19 +++++++------------
t/t0027-auto-crlf.sh | 2 +-
2 files changed, 8 insertions(+), 13 deletions(-)
From: Torsten Bögershausen <redacted>
Even though the configuration parser errors out when core.autocrlf
is set to 'input' when core.eol is set to 'crlf', there is no need
to do so, because the core.autocrlf setting trumps core.eol.
Allow all combinations of core.crlf and core.eol and document
that core.autocrlf overrides core.eol.
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 6 +++---
config.c | 4 ----
2 files changed, 3 insertions(+), 7 deletions(-)
@@ -337,9 +337,9 @@ core.quotePath:: core.eol:: Sets the line ending type to use in the working directory for- files that have the `text` property set. Alternatives are- 'lf', 'crlf' and 'native', which uses the platform's native- line ending. The default value is `native`. See+ files that have the `text` property set when core.autocrlf is false.+ Alternatives are 'lf', 'crlf' and 'native', which uses the platform's+ native line ending. The default value is `native`. See linkgit:gitattributes[5] for more information on end-of-line conversion.
From: Torsten Bögershausen <redacted>
Factor out the retrieval of the sha1 for a given path in
read_blob_data_from_index() into the function get_sha1_from_index().
This will be used in the next commit, when convert.c can do the
analyze for "text=auto" without slurping the whole blob into memory
at once.
Add a wrapper definition get_sha1_from_cache().
Signed-off-by: Torsten Bögershausen <redacted>
---
cache.h | 3 +++
read-cache.c | 29 ++++++++++++++++++-----------
2 files changed, 21 insertions(+), 11 deletions(-)
From: Torsten Bögershausen <redacted>
t6038 uses different code, dependig if NATIVE_CRLF is set ot not. When
the native line endings are LF, merge.renormalize is not tested very well.
Change the test to always use CRLF by setting core.eol=crlf.
After doing so, the test fails:
rm '.gitattributes'
rm 'control_file'
rm 'file'
rm 'inert_file'
HEAD is now at 0d9ffb6 add line from b
error: addinfo_cache failed for path 'file'
file: unmerged (cbd69ec7cd12dd0989e853923867d94c8519aa52)
file: unmerged (ad55e240aeb42e0d9a0e18d6d8b02dd82ee3e527)
file: unmerged (99b633103c15c20cebebf821133ab526b0ff90b2)
fatal: git write-tree failed to write a tree
Merging:
0d9ffb6 add line from b
virtual a
found 1 common ancestor:
1c56df1 Initial
Auto-merging file
not ok 4 - Merge addition of text=auto
This will be addressed in the next commit.
Signed-off-by: Torsten Bögershausen <redacted>
---
t/t6038-merge-text-auto.sh | 37 +++++++++++--------------------------
1 file changed, 11 insertions(+), 26 deletions(-)
From: Torsten Bögershausen <redacted>
We define the working tree file is clean if either:
* the result of running convert_to_git() on the working tree
contents matches what is in the index (because that would mean
doing another "git add" on the path is a no-op); OR
* the result of running convert_to_working_tree() on the content
in the index matches what is in the working tree (because that
would mean doing another "git checkout -f" on the path is a
no-op).
Add an extra check in ce_compare_data() in read_cache.c.
Helped-by: Junio C Hamano [off-list ref]
Signed-off-by: Torsten Bögershausen <redacted>
---
read-cache.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
t/t6038-merge-text-auto.sh | 14 +++++------
2 files changed, 68 insertions(+), 7 deletions(-)
@@ -156,17 +156,78 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)ce_mark_uptodate(ce);}+/*+*Comparethedatainbufwiththedatainthefilepointedbyfdand+*return0iftheyareidentical,andnon-zeroiftheydiffer.+*/+staticintcompare_with_fd(constchar*input,ssize_tlen,intfd)+{+for(;;){+charbuf[1024*16];+ssize_tchunk_len,read_len;++chunk_len=sizeof(buf)<len?sizeof(buf):len;+read_len=xread(fd,buf,chunk_len?chunk_len:1);++if(!read_len)+/* EOF on the working tree file */+return!len?0:-1;++if(!len)+/* we expected there is nothing left */+return-1;++if(memcmp(buf,input,read_len))+return-1;+input+=read_len;+len-=read_len;+}+}+staticintce_compare_data(conststructcache_entry*ce,structstat*st){intmatch=-1;intfd=open(ce->name,O_RDONLY);+/*+*Wouldanother"git add"onthepathchangewhatisinthe+*indexforthepath?+*/if(fd>=0){unsignedcharsha1[20];if(!index_fd(sha1,fd,st,OBJ_BLOB,ce->name,0))match=hashcmp(sha1,ce->sha1);/* index_fd() closed the file descriptor already */}+if(!match)+returnmatch;++/*+*Wouldanother"git checkout -f"outoftheindexchange+*whatisintheworkingtreefile?+*/+fd=open(ce->name,O_RDONLY);+if(fd>=0){+enumobject_typetype;+unsignedlongsize_long;+void*data=read_sha1_file(ce->sha1,&type,&size_long);++if(type==OBJ_BLOB){+structstrbufworktree=STRBUF_INIT;+if(convert_to_working_tree(ce->name,data,+size_long,+&worktree)){+size_tsize;+free(data);+data=strbuf_detach(&worktree,&size);+size_long=size;+}+if(!compare_with_fd(data,size_long,fd))+match=0;+}+free(data);+close(fd);+}returnmatch;}
From: Torsten Bögershausen <redacted>
This patch extends the work done in commit c480539:
"Make it work also for un-normalized repositories". Make sure that CRLF
can be converted round trip, or don't convert them at all.
The old handling would treat a file as unchanged after checkout,
as long as it is not touched in the work tree and mtime matches the value
recorded in the index.
When the mtime is changed in the working tree, or the inode is changed,
the file is reported as modified.
The following sequence is now handled reproducable:
$ git init
$ printf "line1\r\n" >file.bat
$ git add file.bat
$ git commit -m "Add file with CRLF" file.bat
$ echo "*.bat text eol=crlf" >.gitattributes
$ git commit -m "bat files should have CRLF"
$ git status
# nothing to commit, working directory clean
$ git push <upstream>
$ printf "newline\r\n" >>file.bat
$ mv file.bat file.sav
$ git checkout file.bat
$ git status
#modified: file.bat
The new handling makes sure that after running "git reset --hard".
"git status" reports the working tree as clean regarding CRLF conversion.
It makes sure that the Git-internal eol conversion is
doing roundtrip. A user can still write an external smudge/clean filter
outside Git, which doesn't do a roundtrip and the working directory is
not clean.
The functionality of has_cr_in_index() is turned into has_crlf_in_index(),
and the function is integrated into would_convert_crlf_at_commit().
Check for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR
is no longer used and removed, as well as "lonecr" in struct text_stat.
Rewrite check_safe_crlf() in convert.c to simulate checkin-checkout,
to detect whether any line endings are converted.
Add a warning, similar to the CRLF-LF replacement, when a file is commited,
and after the next checkout the line endings are not what they should be.
Modify the lf_to_crlf_filter:
Files with LF are converted into CRLF, file with CRLF are not changed.
Files with mixed line endings are not converted, the filter fails, and Git
falls back to the non-streaming handling, see write_entry().
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/gitattributes.txt | 19 ++--
convert.c | 235 +++++++++++++++++++++++++---------------
t/t0025-crlf-auto.sh | 8 +-
t/t0027-auto-crlf.sh | 92 ++++++++--------
4 files changed, 213 insertions(+), 141 deletions(-)
@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'. `text` ^^^^^^-This attribute enables and controls end-of-line normalization. When a+This attribute enables and controls end-of-line conversion. When a text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the
@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol` Set:: Setting the `text` attribute on a path enables end-of-line- normalization and marks the path as a text file. End-of-line+ conversion and marks the path as a text file. End-of-line conversion takes place without guessing the content type.+ Files that have been commited with CRLF before the text attribute+ is set and commited are not normalized. No end-of-line conversion+ is done at checkout or checkin. Unset::
@@ -131,9 +134,9 @@ Unset:: Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic- end-of-line conversion. If Git decides that the content is- text, its line endings are converted to LF on checkin.- When the file has been commited with CRLF, no conversion is done.+ end-of-line normalization. If Git decides that the content is+ text, and the path has no CRLF in the index,+ its line endings are converted to LF on checkin. Unspecified::
@@ -148,8 +151,10 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It enables end-of-line conversion without any-content checks, effectively setting the `text` attribute.+working directory. It sets the `text` attribute, unless `text=auto`+is specified.+When the file had been commited with CRLF in the index, no conversion+is done at checkout or commit. Set to string value "crlf"::
@@ -32,7 +33,7 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignedstat_bits,lonecr,lonelf,crlf;+unsignedstat_bits,lonelf;/* These are just approximations! */unsignedprintable,nonprintable;
@@ -135,7 +133,7 @@ static unsigned get_convert_stats_sha1(unsigned const char *sha1,if(!readlen)break;do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);-if(stats.stat_bits&earlyout)+if((stats.stat_bits&earlyout)==earlyout)break;/* We found what we have been searching for */}close_and_exit_i:
@@ -239,43 +228,95 @@ static enum eol output_eol(enum crlf_action crlf_action)returncore_eol;}+staticintwould_convert_lf_at_checkout(unsignedconvert_stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+if(output_eol(crlf_action)!=EOL_CRLF)+return0;++/* No "naked" LF? Nothing to convert, regardless. */+if(!(convert_stats&CONVERT_STAT_BITS_TXT_LF))+return0;++if(crlf_action==CRLF_AUTO||+crlf_action==CRLF_AUTO_INPUT||+crlf_action==CRLF_AUTO_CRLF){+/* auto: binary files are not converted */+if(convert_stats&CONVERT_STAT_BITS_BIN)+return0;+}+/* If we have any CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;++}++staticintwould_convert_crlf_at_commit(constchar*path,+conststructtext_stat*stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+unsignedstat_bits_index;+/* No CRLF? Nothing to convert, regardless. */+if(!(stats->stat_bits&CONVERT_STAT_BITS_TXT_CRLF))+return0;+/*+*IfthefileintheindexhasanyCRLFinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+stat_bits_index=get_convert_stats_sha1(get_sha1_from_cache(path),+CONVERT_STAT_BITS_TXT_CRLF);+if(stat_bits_index&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;+}+staticvoidcheck_safe_crlf(constchar*path,enumcrlf_actioncrlf_action,-structtext_stat*stats,enumsafe_crlfchecksafe)+enumsafe_crlfchecksafe,+unsignedconvert_stats,unsignednew_convert_stats){+enumeolnew_eol=output_eol(crlf_action);+constchar*err_warn_msg=NULL;if(!checksafe)return;--if(output_eol(crlf_action)==EOL_LF){+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)){/**CRLFswouldnotberestoredbycheckout:*checkifwe'dremoveCRLFs*/-if(stats->crlf){-if(checksafe==SAFE_CRLF_WARN)-warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("CRLF would be replaced by LF in %s.",path);-}-}elseif(output_eol(crlf_action)==EOL_CRLF){+if(checksafe==SAFE_CRLF_WARN)+warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("CRLF would be replaced by LF in %s.",path);+}+if(convert_stats&CONVERT_STAT_BITS_TXT_LF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_LF)){/**CRLFswouldbeaddedbycheckout:*checkifwehave"naked"LFs*/-if(stats->lonelf){-if(checksafe==SAFE_CRLF_WARN)-warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("LF would be replaced by CRLF in %s",path);-}+if(checksafe==SAFE_CRLF_WARN)+warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("LF would be replaced by CRLF in %s",path);+}+if((new_convert_stats&CONVERT_STAT_BITS_MIXED)==CONVERT_STAT_BITS_MIXED)+err_warn_msg="mixed eol";+elseif(new_eol==EOL_LF&&new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+err_warn_msg="CRLF";++if(err_warn_msg){+if(checksafe==SAFE_CRLF_WARN)+warning("%s will be present after commit and checkout in %s.",+err_warn_msg,path);+else+die("%s will be present after commit and checkout in %s",+err_warn_msg,path);}-}--staticinthas_cr_in_index(constchar*path)-{-unsignedconvert_stats;-convert_stats=get_convert_stats_sha1(get_sha1_from_cache(path),-CONVERT_STAT_BITS_ANY_CR);-returnconvert_stats&CONVERT_STAT_BITS_ANY_CR;}staticintcrlf_to_git(constchar*path,constchar*src,size_tlen,
@@ -354,28 +415,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,{char*to_free=NULL;structtext_statstats;-unsignedearlyout=CONVERT_STAT_BITS_TXT_CRLF|CONVERT_STAT_BITS_BIN;---if(!len||output_eol(crlf_action)!=EOL_CRLF)+unsignedearlyout=0;/* Need to count lonelf */+if(!len)return0;gather_stats(src,len,&stats,earlyout);--/* No "naked" LF? Nothing to convert, regardless. */-if(!stats.lonelf)+if(!would_convert_lf_at_checkout(stats.stat_bits,+len,crlf_action))return0;-if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;--if(stats.stat_bits&CONVERT_STAT_BITS_BIN)-return0;-}-/* are we "faking" in place editing ? */if(src==buf->buf)to_free=strbuf_detach(buf,NULL);
@@ -1067,6 +1115,8 @@ int is_null_stream_filter(struct stream_filter *filter)structlf_to_crlf_filter{structstream_filterfilter;unsignedhas_held:1;+unsignedexpanded_loneLF:1;+unsignedhad_CRLF:1;charheld;};
@@ -1107,7 +1157,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,charch=input[i];if(ch=='\n'){-output[o++]='\r';+if(!lf_to_crlf->had_CRLF){+output[o++]='\r';+lf_to_crlf->expanded_loneLF=1;+}+if(was_cr)+lf_to_crlf->had_CRLF=1;}elseif(was_cr){/**PreviousroundsawCRanditisnotfollowed
@@ -1136,6 +1191,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,was_cr=0;output[o++]=ch;+if(lf_to_crlf->expanded_loneLF&&+lf_to_crlf->had_CRLF){+/*+*MixedEOL,roundtripnotpossible.+*/+return1;+}+}*osize_p-=o;
@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' 'test-z"$LFonlydiff"-a-z"$CRLFonlydiff"-a-z"$LFwithNULdiff"'-test_expect_success'crlf=true causes a CRLF file to be normalized''+test_expect_success'crlf=true causes a CRLF file not to be normalized''# Backwards compatibility checkrm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&
@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"'-test_expect_success'text=true causes a CRLF file to be normalized''+test_expect_success'text=true causes a CRLF file not to be normalized''rm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&echo"CRLFonly text">.gitattributes&&
@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"' test_expect_success'eol=crlf gives a normalized file CRLFs with autocrlf=false''
@@ -71,10 +71,14 @@ check_warning () {case"$1"inLF_CRLF)echo"warning: LF will be replaced by CRLF">"$2".expect;;CRLF_LF)echo"warning: CRLF will be replaced by LF">"$2".expect;;+CRLF)echo"warning: CRLF will be present after commit and checkout">"$2".expect;;+mixed)echo"warning: mixed eol will be present after commit and checkout">"$2".expect;;'')>"$2".expect;;*)echo>&2"Illegal 1":"$1";returnfalse;;esac-grep"will be replaced by""$2"|sed-e"s/\(.*\) in [^ ]*$/\1/"|uniq>"$2".actual+egrep"will be replaced by|will be present after commit""$2"|+sed-e"s/\(.*\) in [^ ]*$/\1/"|+uniq>"$2".actualtest_cmp"$2".expect"$2".actual}
@@ -169,7 +173,7 @@ stats_ascii () {# Take none (=empty), one or two args# convert.c: eol=XX overrides text=auto attr_ascii(){-case$1,$2in+case"$1","$2"in-text,*)echo"-text";;text,)echo"text";;text,lf)echo"text eol=lf";;
@@ -456,9 +463,9 @@ docheck_in_repo_NNOauto""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautolf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautocrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldone################################################################################# Check how files in the repo are changed when they are checked out
@@ -492,8 +497,7 @@ fiexportCRLF_MIX_LF_CRMIXNL# Same handling with and without ident-#for id in "" ident-foridin""+foridin""identdoforceolinlfcrlfnativedo
@@ -501,38 +505,38 @@ dodo# -text overrides core.autocrlf and core.eol# text and eol=crlf or eol=lf override core.autocrlf and core.eol-checkout_files-text"$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files-text"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files-text"$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text-checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul# currently the same as text, eol=XXX-checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# core.autocrlf false, different core.eol-checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# core.autocrlf true-checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text: core.autocrlf = true overrides core.eol-checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul# text: core.autocrlf = input overrides core.eol-checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text=auto + eol=XXXdone# text: core.autocrlf=false uses core.eol-checkout_filestext"$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""falsecrlfCRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul+checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_filestext"$id"""false""$NLCRLFCRLF_mix_LF"$MIX_LF_CR""$LFNUL"+checkout_filestext"$id"""falsenative$NLCRLFCRLF_mix_LF"$MIX_LF_CR""$LFNUL"# auto: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
When statistics are done for the autocrlf handling, the search in
the content can be stopped, if e.g
- a search for binary is done, and a NUL character is found
- a search for CRLF is done, and the first CRLF is found.
Similar when statistics for binary vs non-binary are gathered:
Whenever a lone CR or NUL is found, the search can be aborted.
When checking out files in "auto" mode, any file that has a "lone CR"
or a CRLF will not be converted, so the search can be aborted early.
Add the new bit, CONVERT_STAT_BITS_ANY_CR,
which is set for either lone CR or CRLF.
Many binary files have a NUL very early (within the first few bytes,
latest within the first 1..2K).
It is often not necessary to load the whole content of a file or blob
into memory.
Use a streaming handling for blobs and files in the worktree.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 159 ++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 103 insertions(+), 56 deletions(-)
@@ -13,10 +14,10 @@*translationwhenthe"text"attributeor"auto_crlf"optionisset.*/-/* Stat bits: When BIN is set, the txt bits are unset */#define CONVERT_STAT_BITS_TXT_LF 0x1#define CONVERT_STAT_BITS_TXT_CRLF 0x2#define CONVERT_STAT_BITS_BIN 0x4+#define CONVERT_STAT_BITS_ANY_CR 0x8enumcrlf_action{CRLF_UNDEFINED,
@@ -31,30 +32,36 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignednul,lonecr,lonelf,crlf;+unsignedstat_bits,lonecr,lonelf,crlf;/* These are just approximations! */unsignedprintable,nonprintable;};-staticvoidgather_stats(constchar*buf,unsignedlongsize,structtext_stat*stats)+staticvoiddo_gather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout){unsignedlongi;-memset(stats,0,sizeof(*stats));-+if(!buf||!size)+return;for(i=0;i<size;i++){unsignedcharc=buf[i];if(c=='\r'){+stats->stat_bits|=CONVERT_STAT_BITS_ANY_CR;if(i+1<size&&buf[i+1]=='\n'){stats->crlf++;i++;-}else+stats->stat_bits|=CONVERT_STAT_BITS_TXT_CRLF;+}else{stats->lonecr++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}continue;}if(c=='\n'){stats->lonelf++;+stats->stat_bits|=CONVERT_STAT_BITS_TXT_LF;continue;}if(c==127)
@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats->printable++;break;case0:-stats->nul++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;/* fall through */default:stats->nonprintable++;
@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *}elsestats->printable++;+if(stats->stat_bits&earlyout)+break;/* We found what we have been searching for */}/* If file ends with EOF then don't count this EOF as non-printable. */
@@ -86,41 +95,62 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat **Thesameheuristicsasdiff.c::mmfile_is_binary()*WetreatfileswithbareCRasbinary*/-staticintconvert_is_binary(unsignedlongsize,conststructtext_stat*stats)+staticvoidconvert_nonprintable(structtext_stat*stats){-if(stats->lonecr)-return1;-if(stats->nul)-return1;if((stats->printable>>7)<stats->nonprintable)-return1;-return0;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}++staticvoidgather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout)+{+memset(stats,0,sizeof(*stats));+do_gather_stats(buf,size,stats,earlyout);+convert_nonprintable(stats);}-staticunsignedintgather_convert_stats(constchar*data,unsignedlongsize)++staticunsignedget_convert_stats_sha1(unsignedconstchar*sha1,+unsignedearlyout){+structgit_istream*st;structtext_statstats;-intret=0;-if(!data||!size)-return0;-gather_stats(data,size,&stats);-if(convert_is_binary(size,&stats))-ret|=CONVERT_STAT_BITS_BIN;-if(stats.crlf)-ret|=CONVERT_STAT_BITS_TXT_CRLF;-if(stats.lonelf)-ret|=CONVERT_STAT_BITS_TXT_LF;+enumobject_typetype;+unsignedlongsz;-returnret;+if(!sha1)+return0;+memset(&stats,0,sizeof(stats));+st=open_istream(sha1,&type,&sz,NULL);+if(!st){+return0;+}+if(type!=OBJ_BLOB)+gotoclose_and_exit_i;+for(;;){+charbuf[1024];+ssize_treadlen=read_istream(st,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close_and_exit_i:+close_istream(st);+convert_nonprintable(&stats);+returnstats.stat_bits;}-staticconstchar*gather_convert_stats_ascii(constchar*data,unsignedlongsize)+staticconstchar*convert_stats_ascii(unsignedconvert_stats){-unsignedintconvert_stats=gather_convert_stats(data,size);-+unsignedmask=CONVERT_STAT_BITS_TXT_LF|+CONVERT_STAT_BITS_TXT_CRLF;if(convert_stats&CONVERT_STAT_BITS_BIN)return"-text";-switch(convert_stats){+switch(convert_stats&mask){caseCONVERT_STAT_BITS_TXT_LF:return"lf";caseCONVERT_STAT_BITS_TXT_CRLF:
@@ -132,24 +162,45 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si}}+staticunsignedget_convert_stats_wt(constchar*path)+{+structtext_statstats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+intfd;+memset(&stats,0,sizeof(stats));+fd=open(path,O_RDONLY);+if(fd<0)+return0;+for(;;){+charbuf[1024];+ssize_treadlen=read(fd,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close(fd);+convert_nonprintable(&stats);+returnstats.stat_bits;+}+constchar*get_cached_convert_stats_ascii(constchar*path){-constchar*ret;-unsignedlongsz;-void*data=read_blob_data_from_cache(path,&sz);-ret=gather_convert_stats_ascii(data,sz);-free(data);-returnret;+unsignedconvert_stats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+convert_stats=get_convert_stats_sha1(get_sha1_from_cache(path),+earlyout);+returnconvert_stats_ascii(convert_stats);}constchar*get_wt_convert_stats_ascii(constchar*path){-constchar*ret="";-structstrbufsb=STRBUF_INIT;-if(strbuf_read_file(&sb,path,0)>=0)-ret=gather_convert_stats_ascii(sb.buf,sb.len);-strbuf_release(&sb);-returnret;+unsignedconvert_stats;+convert_stats=get_convert_stats_wt(path);+returnconvert_stats_ascii(convert_stats);}staticinttext_eol_is_crlf(void)
From: Torsten Bögershausen <redacted>
When the content of a commited file is unchanged and the attributes are changed,
Git may not detect that the next commit must treat the file as changed.
This happens when lstat() doesn't detect a change, since neither inode,
mtime nor size are changed.
Add a singe "Z" character to change the file size (and content).
When the files are compared later in checkout_files(), the "Z" is removed
before the comparison.
Signed-off-by: Torsten Bögershausen <redacted>
---
Change since v6b:
- Remove 2 sparse warnings, thanks Ramsay
From: Torsten Bögershausen <redacted>
Before this change,
$ echo "* text=auto" >.gitattributes
$ echo "* eol=crlf" >>.gitattributes
would have the same effect as
$ echo "* text" >.gitattributes
$ git config core.eol crlf
Since the 'eol' attribute had higher priority than 'text=auto', this may
corrupt binary files and is not what users expect to happen.
Make the 'eol' attribute to obey 'text=auto', and now
$ echo "* text=auto" >.gitattributes
$ echo "* eol=crlf" >>.gitattributes
behaves the same as
$ echo "* text=auto" >.gitattributes
$ git config core.eol crlf
In other words,
$ echo "* text=auto eol=crlf" >.gitattributes
has the same effect as
$ git config core.autocrlf true
and
$ echo "* text=auto eol=lf" >.gitattributes
has the same effect as
$ git config core.autocrlf input
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 14 +++++++-------
Documentation/gitattributes.txt | 15 +++++++++------
convert.c | 42 +++++++++++++++++++++--------------------
convert.h | 3 ++-
t/t0025-crlf-auto.sh | 4 ++--
t/t0027-auto-crlf.sh | 32 +++++++++++++++----------------
t/t6038-merge-text-auto.sh | 23 ++++++++++++++--------
7 files changed, 73 insertions(+), 60 deletions(-)
@@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf` mechanism. core.autocrlf::- Setting this variable to "true" is almost the same as setting- the `text` attribute to "auto" on all files except that text- files are not guaranteed to be normalized: files that contain- `CRLF` in the repository will not be touched. Use this- setting if you want to have `CRLF` line endings in your- working directory even though the repository does not have- normalized line endings. This variable can be set to 'input',+ Setting this variable to "true" is the same as setting+ the `text` attribute to "auto" on all files and core.eol to "crlf".+ Set to true if you want to have `CRLF` line endings in your+ working directory and the repository has LF line endings.+ Text files are guaranteed not to be normalized: files that contain+ `CRLF` in the repository will not be touched.+ This variable can be set to 'input', in which case no output conversion is performed. core.symlinks::
@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the `core.eol` configuration variable for all text files.+Note that `core.autocrlf` overrides `core.eol` Set::
@@ -130,8 +131,9 @@ Unset:: Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic- end-of-line normalization. If Git decides that the content is- text, its line endings are normalized to LF on checkin.+ end-of-line conversion. If Git decides that the content is+ text, its line endings are converted to LF on checkin.+ When the file has been commited with CRLF, no conversion is done. Unspecified::
@@ -146,7 +148,7 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It enables end-of-line normalization without any+working directory. It enables end-of-line conversion without any content checks, effectively setting the `text` attribute. Set to string value "crlf"::
@@ -186,9 +188,10 @@ the working directory, and prevent .jpg files from being normalized regardless of their content. ------------------------+* text=auto *.txt text-*.vcproj eol=crlf-*.sh eol=lf+*.vcproj text eol=crlf+*.sh text eol=lf *.jpg -text ------------------------
@@ -198,7 +201,7 @@ normalization in Git. If you simply want to have CRLF line endings in your working directory regardless of the repository you are working with, you can set the-config variable "core.autocrlf" without changing any attributes.+config variable "core.autocrlf" without using any attributes. ------------------------ [core]
@@ -227,7 +227,9 @@ static enum eol output_eol(enum crlf_action crlf_action)returnEOL_LF;caseCRLF_UNDEFINED:caseCRLF_AUTO_CRLF:+returnEOL_CRLF;caseCRLF_AUTO_INPUT:+returnEOL_LF;caseCRLF_TEXT:caseCRLF_AUTO:/* fall through */
@@ -299,17 +301,15 @@ static int crlf_to_git(const char *path, const char *src, size_t len,if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;--if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/*-*IfthefileintheindexhasanyCRinit,donotconvert.-*Thisisthenewsaferautocrlfhandling.-*/-if(has_cr_in_index(path))-return0;-}+/*+*IfthefileintheindexhasanyCRinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+if(checksafe==SAFE_CRLF_RENORMALIZE)+checksafe=SAFE_CRLF_FALSE;+elseif(has_cr_in_index(path))+return0;}-check_safe_crlf(path,crlf_action,&stats,checksafe);/* Optimization: No CRLF? Nothing to convert, regardless. */
@@ -367,12 +367,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,return0;if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;-}+/* If we have any CR or CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(stats.lonecr||stats.crlf)+return0;if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;
@@ -892,9 +894,9 @@ const char *get_convert_attr_ascii(const char *path)caseCRLF_AUTO:return"text=auto";caseCRLF_AUTO_CRLF:-return"text=auto eol=crlf";/* This is not supported yet */+return"text=auto eol=crlf";caseCRLF_AUTO_INPUT:-return"text=auto eol=lf";/* This is not supported yet */+return"text=auto eol=lf";}return"";}
@@ -493,7 +492,8 @@ fiexportCRLF_MIX_LF_CRMIXNL# Same handling with and without ident-foridin""ident+#for id in "" ident+foridin""doforceolinlfcrlfnativedo
@@ -509,7 +509,7 @@ docheckout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul# currently the same as text, eol=XXXcheckout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# core.autocrlf false, different core.eol
@@ -531,8 +531,8 @@ docheckout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNULcheckout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL# auto: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filesauto"$id"""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
@@ -81,7 +88,7 @@ test_expect_success 'Merge after setting text=auto' 'rm-f.gitattributes&&gitreset--harda&&gitmergeb&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Merge addition of text=auto''
@@ -99,7 +106,7 @@ test_expect_success 'Merge addition of text=auto' 'rm-f.gitattributes&&gitreset--hardb&&gitmergea&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Detect CRLF/LF conflict after setting text=auto''
@@ -121,7 +128,7 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' 'gitreset--harda&&test_must_failgitmergeb&&fuzz_conflictfile>file.fuzzy&&-test_cmpexpectedfile.fuzzy+compare_filesexpectedfile.fuzzy' test_expect_success'Detect LF/CRLF conflict from addition of text=auto''
@@ -143,7 +150,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' 'gitreset--hardb&&test_must_failgitmergea&&fuzz_conflictfile>file.fuzzy&&-test_cmpexpectedfile.fuzzy+compare_filesexpectedfile.fuzzy' test_expect_failure'checkout -m after setting text=auto''
@@ -158,7 +165,7 @@ test_expect_failure 'checkout -m after setting text=auto' 'gitreset--hardinitial&&gitcheckouta--.&&gitcheckout-mb&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_failure'checkout -m addition of text=auto''
@@ -173,7 +180,7 @@ test_expect_failure 'checkout -m addition of text=auto' 'gitreset--hardinitial&&gitcheckoutb--.&&gitcheckout-ma&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_failure'cherry-pick patch from after text=auto was added''
@@ -187,7 +194,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' 'gitreset--hardb&&test_must_failgitcherry-picka>err2>&1&&grep"[Nn]othing added"err&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Test delete/normalize conflict''
From: Torsten Bögershausen <redacted>
Even though the configuration parser errors out when core.autocrlf
is set to 'input' when core.eol is set to 'crlf', there is no need
to do so, because the core.autocrlf setting trumps core.eol.
Allow all combinations of core.crlf and core.eol and document
that core.autocrlf overrides core.eol.
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 6 +++---
config.c | 4 ----
2 files changed, 3 insertions(+), 7 deletions(-)
@@ -337,9 +337,9 @@ core.quotePath:: core.eol:: Sets the line ending type to use in the working directory for- files that have the `text` property set. Alternatives are- 'lf', 'crlf' and 'native', which uses the platform's native- line ending. The default value is `native`. See+ files that have the `text` property set when core.autocrlf is false.+ Alternatives are 'lf', 'crlf' and 'native', which uses the platform's+ native line ending. The default value is `native`. See linkgit:gitattributes[5] for more information on end-of-line conversion.
From: Torsten Bögershausen <redacted>
When the ident attributes is set, get_stream_filter() did not obey
core.autocrlf=true, and the file was checked out with LF.
Change the rule when a streaming filter can be used:
- if an external filter is specified, don't use a stream filter.
- if the worktree eol is CRLF and "auto" is active, don't use a stream filter.
- Otherwise the stream filter can be used.
Add test cases in t0027.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 19 +++++++------------
t/t0027-auto-crlf.sh | 2 +-
2 files changed, 8 insertions(+), 13 deletions(-)
From: Torsten Bögershausen <redacted>
When statistics are done for the autocrlf handling, the search in
the content can be stopped, if e.g
- a search for binary is done, and a NUL character is found
- a search for CRLF is done, and the first CRLF is found.
Similar when statistics for binary vs non-binary are gathered:
Whenever a lone CR or NUL is found, the search can be aborted.
When checking out files in "auto" mode, any file that has a "lone CR"
or a CRLF will not be converted, so the search can be aborted early.
Add the new bit, CONVERT_STAT_BITS_ANY_CR,
which is set for either lone CR or CRLF.
Many binary files have a NUL very early (within the first few bytes,
latest within the first 1..2K).
It is often not necessary to load the whole content of a file or blob
into memory.
Use a streaming handling for blobs and files in the worktree.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 159 ++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 103 insertions(+), 56 deletions(-)
@@ -13,10 +14,10 @@*translationwhenthe"text"attributeor"auto_crlf"optionisset.*/-/* Stat bits: When BIN is set, the txt bits are unset */#define CONVERT_STAT_BITS_TXT_LF 0x1#define CONVERT_STAT_BITS_TXT_CRLF 0x2#define CONVERT_STAT_BITS_BIN 0x4+#define CONVERT_STAT_BITS_ANY_CR 0x8enumcrlf_action{CRLF_UNDEFINED,
@@ -31,30 +32,36 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignednul,lonecr,lonelf,crlf;+unsignedstat_bits,lonecr,lonelf,crlf;/* These are just approximations! */unsignedprintable,nonprintable;};-staticvoidgather_stats(constchar*buf,unsignedlongsize,structtext_stat*stats)+staticvoiddo_gather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout){unsignedlongi;-memset(stats,0,sizeof(*stats));-+if(!buf||!size)+return;for(i=0;i<size;i++){unsignedcharc=buf[i];if(c=='\r'){+stats->stat_bits|=CONVERT_STAT_BITS_ANY_CR;if(i+1<size&&buf[i+1]=='\n'){stats->crlf++;i++;-}else+stats->stat_bits|=CONVERT_STAT_BITS_TXT_CRLF;+}else{stats->lonecr++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}continue;}if(c=='\n'){stats->lonelf++;+stats->stat_bits|=CONVERT_STAT_BITS_TXT_LF;continue;}if(c==127)
@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats->printable++;break;case0:-stats->nul++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;/* fall through */default:stats->nonprintable++;
@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *}elsestats->printable++;+if(stats->stat_bits&earlyout)+break;/* We found what we have been searching for */}/* If file ends with EOF then don't count this EOF as non-printable. */
@@ -86,41 +95,62 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat **Thesameheuristicsasdiff.c::mmfile_is_binary()*WetreatfileswithbareCRasbinary*/-staticintconvert_is_binary(unsignedlongsize,conststructtext_stat*stats)+staticvoidconvert_nonprintable(structtext_stat*stats){-if(stats->lonecr)-return1;-if(stats->nul)-return1;if((stats->printable>>7)<stats->nonprintable)-return1;-return0;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}++staticvoidgather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout)+{+memset(stats,0,sizeof(*stats));+do_gather_stats(buf,size,stats,earlyout);+convert_nonprintable(stats);}-staticunsignedintgather_convert_stats(constchar*data,unsignedlongsize)++staticunsignedget_convert_stats_sha1(unsignedconstchar*sha1,+unsignedearlyout){+structgit_istream*st;structtext_statstats;-intret=0;-if(!data||!size)-return0;-gather_stats(data,size,&stats);-if(convert_is_binary(size,&stats))-ret|=CONVERT_STAT_BITS_BIN;-if(stats.crlf)-ret|=CONVERT_STAT_BITS_TXT_CRLF;-if(stats.lonelf)-ret|=CONVERT_STAT_BITS_TXT_LF;+enumobject_typetype;+unsignedlongsz;-returnret;+if(!sha1)+return0;+memset(&stats,0,sizeof(stats));+st=open_istream(sha1,&type,&sz,NULL);+if(!st){+return0;+}+if(type!=OBJ_BLOB)+gotoclose_and_exit_i;+for(;;){+charbuf[1024];+ssize_treadlen=read_istream(st,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close_and_exit_i:+close_istream(st);+convert_nonprintable(&stats);+returnstats.stat_bits;}-staticconstchar*gather_convert_stats_ascii(constchar*data,unsignedlongsize)+staticconstchar*convert_stats_ascii(unsignedconvert_stats){-unsignedintconvert_stats=gather_convert_stats(data,size);-+unsignedmask=CONVERT_STAT_BITS_TXT_LF|+CONVERT_STAT_BITS_TXT_CRLF;if(convert_stats&CONVERT_STAT_BITS_BIN)return"-text";-switch(convert_stats){+switch(convert_stats&mask){caseCONVERT_STAT_BITS_TXT_LF:return"lf";caseCONVERT_STAT_BITS_TXT_CRLF:
@@ -132,24 +162,45 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si}}+staticunsignedget_convert_stats_wt(constchar*path)+{+structtext_statstats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+intfd;+memset(&stats,0,sizeof(stats));+fd=open(path,O_RDONLY);+if(fd<0)+return0;+for(;;){+charbuf[1024];+ssize_treadlen=read(fd,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close(fd);+convert_nonprintable(&stats);+returnstats.stat_bits;+}+constchar*get_cached_convert_stats_ascii(constchar*path){-constchar*ret;-unsignedlongsz;-void*data=read_blob_data_from_cache(path,&sz);-ret=gather_convert_stats_ascii(data,sz);-free(data);-returnret;+unsignedconvert_stats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+convert_stats=get_convert_stats_sha1(get_sha1_from_cache(path),+earlyout);+returnconvert_stats_ascii(convert_stats);}constchar*get_wt_convert_stats_ascii(constchar*path){-constchar*ret="";-structstrbufsb=STRBUF_INIT;-if(strbuf_read_file(&sb,path,0)>=0)-ret=gather_convert_stats_ascii(sb.buf,sb.len);-strbuf_release(&sb);-returnret;+unsignedconvert_stats;+convert_stats=get_convert_stats_wt(path);+returnconvert_stats_ascii(convert_stats);}staticinttext_eol_is_crlf(void)
From: Torsten Bögershausen <redacted>
Before this change,
$ echo "* text=auto" >.gitattributes
$ echo "* eol=crlf" >>.gitattributes
would have the same effect as
$ echo "* text" >.gitattributes
$ git config core.eol crlf
Having an "eol" attribute is taken as a declaration that the
path is text. This may be logical (on a binary blob, you
wouldn't be defining an "eol" attribute in the first place)
but is not very useful if you wanted to say "I do not know
if the path is text; inspect the contents to see if it is
text, and apply this 'eol' conversion only if it is".
"text=auto" attribute combined with an "eol" attribute ought
to have meant that, but it didn't. Make it so.
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 14 ++++++------
Documentation/gitattributes.txt | 15 +++++++------
convert.c | 47 ++++++++++++++++++++++-------------------
convert.h | 3 ++-
t/t0025-crlf-auto.sh | 4 ++--
t/t0027-auto-crlf.sh | 32 ++++++++++++++--------------
t/t6038-merge-text-auto.sh | 23 +++++++++++++-------
7 files changed, 76 insertions(+), 62 deletions(-)
@@ -389,13 +389,13 @@ file with mixed line endings would be reported by the `core.safecrlf` mechanism. core.autocrlf::- Setting this variable to "true" is almost the same as setting- the `text` attribute to "auto" on all files except that text- files are not guaranteed to be normalized: files that contain- `CRLF` in the repository will not be touched. Use this- setting if you want to have `CRLF` line endings in your- working directory even though the repository does not have- normalized line endings. This variable can be set to 'input',+ Setting this variable to "true" is the same as setting+ the `text` attribute to "auto" on all files and core.eol to "crlf".+ Set to true if you want to have `CRLF` line endings in your+ working directory and the repository has LF line endings.+ Text files are guaranteed not to be normalized: files that contain+ `CRLF` in the repository will not be touched.+ This variable can be set to 'input', in which case no output conversion is performed. core.symlinks::
@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the `core.eol` configuration variable for all text files.+Note that `core.autocrlf` overrides `core.eol` Set::
@@ -130,8 +131,9 @@ Unset:: Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic- end-of-line normalization. If Git decides that the content is- text, its line endings are normalized to LF on checkin.+ end-of-line conversion. If Git decides that the content is+ text, its line endings are converted to LF on checkin.+ When the file has been commited with CRLF, no conversion is done. Unspecified::
@@ -146,7 +148,7 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It enables end-of-line normalization without any+working directory. It enables end-of-line conversion without any content checks, effectively setting the `text` attribute. Set to string value "crlf"::
@@ -186,9 +188,10 @@ the working directory, and prevent .jpg files from being normalized regardless of their content. ------------------------+* text=auto *.txt text-*.vcproj eol=crlf-*.sh eol=lf+*.vcproj text eol=crlf+*.sh text eol=lf *.jpg -text ------------------------
@@ -198,7 +201,7 @@ normalization in Git. If you simply want to have CRLF line endings in your working directory regardless of the repository you are working with, you can set the-config variable "core.autocrlf" without changing any attributes.+config variable "core.autocrlf" without using any attributes. ------------------------ [core]
@@ -225,16 +225,19 @@ static enum eol output_eol(enum crlf_action crlf_action)returnEOL_CRLF;caseCRLF_TEXT_INPUT:returnEOL_LF;-caseCRLF_UNDEFINED:caseCRLF_AUTO_CRLF:+returnEOL_CRLF;caseCRLF_AUTO_INPUT:+returnEOL_LF;caseCRLF_TEXT:caseCRLF_AUTO:/* fall through */returntext_eol_is_crlf()?EOL_CRLF:EOL_LF;+default:/* the above should cover all valid cases */+break;}warning("Illegal crlf_action %d\n",(int)crlf_action);-returncore_eol;+returnEOL_UNSET;}staticvoidcheck_safe_crlf(constchar*path,enumcrlf_actioncrlf_action,
@@ -299,17 +302,15 @@ static int crlf_to_git(const char *path, const char *src, size_t len,if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;--if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/*-*IfthefileintheindexhasanyCRinit,donotconvert.-*Thisisthenewsaferautocrlfhandling.-*/-if(has_cr_in_index(path))-return0;-}+/*+*IfthefileintheindexhasanyCRinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+if(checksafe==SAFE_CRLF_RENORMALIZE)+checksafe=SAFE_CRLF_FALSE;+elseif(has_cr_in_index(path))+return0;}-check_safe_crlf(path,crlf_action,&stats,checksafe);/* Optimization: No CRLF? Nothing to convert, regardless. */
@@ -367,12 +368,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,return0;if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;-}+/* If we have any CR or CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(stats.lonecr||stats.crlf)+return0;if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;
@@ -892,9 +895,9 @@ const char *get_convert_attr_ascii(const char *path)caseCRLF_AUTO:return"text=auto";caseCRLF_AUTO_CRLF:-return"text=auto eol=crlf";/* This is not supported yet */+return"text=auto eol=crlf";caseCRLF_AUTO_INPUT:-return"text=auto eol=lf";/* This is not supported yet */+return"text=auto eol=lf";}return"";}
@@ -493,7 +492,8 @@ fiexportCRLF_MIX_LF_CRMIXNL# Same handling with and without ident-foridin""ident+#for id in "" ident+foridin""doforceolinlfcrlfnativedo
@@ -509,7 +509,7 @@ docheckout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul# currently the same as text, eol=XXXcheckout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# core.autocrlf false, different core.eol
@@ -531,8 +531,8 @@ docheckout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNULcheckout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL# auto: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filesauto"$id"""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
@@ -81,7 +88,7 @@ test_expect_success 'Merge after setting text=auto' 'rm-f.gitattributes&&gitreset--harda&&gitmergeb&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Merge addition of text=auto''
@@ -99,7 +106,7 @@ test_expect_success 'Merge addition of text=auto' 'rm-f.gitattributes&&gitreset--hardb&&gitmergea&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Detect CRLF/LF conflict after setting text=auto''
@@ -121,7 +128,7 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' 'gitreset--harda&&test_must_failgitmergeb&&fuzz_conflictfile>file.fuzzy&&-test_cmpexpectedfile.fuzzy+compare_filesexpectedfile.fuzzy' test_expect_success'Detect LF/CRLF conflict from addition of text=auto''
@@ -143,7 +150,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' 'gitreset--hardb&&test_must_failgitmergea&&fuzz_conflictfile>file.fuzzy&&-test_cmpexpectedfile.fuzzy+compare_filesexpectedfile.fuzzy' test_expect_failure'checkout -m after setting text=auto''
@@ -158,7 +165,7 @@ test_expect_failure 'checkout -m after setting text=auto' 'gitreset--hardinitial&&gitcheckouta--.&&gitcheckout-mb&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_failure'checkout -m addition of text=auto''
@@ -173,7 +180,7 @@ test_expect_failure 'checkout -m addition of text=auto' 'gitreset--hardinitial&&gitcheckoutb--.&&gitcheckout-ma&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_failure'cherry-pick patch from after text=auto was added''
@@ -187,7 +194,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' 'gitreset--hardb&&test_must_failgitcherry-picka>err2>&1&&grep"[Nn]othing added"err&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Test delete/normalize conflict''
From: Torsten Bögershausen <redacted>
Add more test cases for the not normalized files ("NNO"). The
"text" attribute is most important, use it as the first parameter.
"ident", if set, is the second paramater followed by the eol
attribute. The eol attribute overrides core.autocrlf, which
overrides core.eol.
indent is not yet used, this will be done in the next commit.
Use loops to test more combinations of attributes, like
"* text eol=crlf" or especially "*text=auto eol=crlf".
Signed-off-by: Torsten Bögershausen <redacted>
---
t/t0027-auto-crlf.sh | 298 ++++++++++++++++++++++-----------------------------
1 file changed, 129 insertions(+), 169 deletions(-)
@@ -100,16 +103,17 @@ commit_check_warn () {} commit_chk_wrnNNO(){-crlf=$1-attr=$2-lfwarn=$3-crlfwarn=$4-lfmixcrlf=$5-lfmixcr=$6-crlfnul=$7-pfx=NNO_${crlf}_attr_${attr}+attr=$1;shift+aeol=$1;shift+crlf=$1;shift+lfwarn=$1;shift+crlfwarn=$1;shift+lfmixcrlf=$1;shift+lfmixcr=$1;shift+crlfnul=$1;shift+pfx=NNO_attr_${attr}_aeol_${aeol}_${crlf}#Commit files on top of existing file-create_gitattributes"$attr"&&+create_gitattributes"$attr"$aeol&&forfinLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldofname=${pfx}_$f.txt&&
@@ -163,6 +167,7 @@ stats_ascii () {# contruct the attr/ returned by git ls-files --eol# Take none (=empty), one or two args+# convert.c: eol=XX overrides text=auto attr_ascii(){case$1,$2in-text,*)echo"-text";;
@@ -441,24 +447,20 @@ test_expect_success 'commit -text' 'check_files_in_repoinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul'-# attr LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL-check_in_repo_NNOfalse""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput""LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"auto"LFLFLFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"auto"LFLFLFLF_mix_CRCRLF_nul--check_in_repo_NNOfalse"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtrue"text"LFLFLFLF_mix_CRLF_nul-check_in_repo_NNOinput"text"LFLFLFLF_mix_CRLF_nul--check_in_repo_NNOfalse"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtrue"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOinput"-text"LFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul--+forcrlfintruefalseinput+do+# attr aeol LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL+check_in_repo_NNO""""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-text""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNO-textcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOauto""$crlfLFLFLFLF_mix_CRCRLF_nul+check_in_repo_NNOautolf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOautocrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+done################################################################################# Check how files in the repo are changed when they are checked out# How to read the table below:
@@ -490,89 +492,47 @@ LFNUL=LF_nulfiexportCRLF_MIX_LF_CRMIXNL-checkout_files""""""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""true""CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truecrlfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truelfCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""""""truenativeCRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files""ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_files"auto"""""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"""""true""CRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truecrlfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truelfCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"""""truenativeCRLFCRLFCRLFLF_mix_CRLF_nul-checkout_files"auto"ident""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"auto"ident""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul--foridin""ident;+# Same handling with and without ident+foridin""do-checkout_files"crlf""$id"""false""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falselfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""falsenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""input""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""inputlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"crlf""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"lf""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"lf""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_files"text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"text""$id"""true""CRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truelfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"text""$id"""truenativeCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_files"-text""$id"""false""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""falsenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""input""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""inputlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""true""LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truecrlfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truelfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files"-text""$id"""truenativeLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+forceolinlfcrlfnative+do+forcrlfintruefalseinput+do+# -text overrides core.autocrlf and core.eol+# text and eol=crlf or eol=lf override core.autocrlf and core.eol+checkout_files-text"$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files-text"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files-text"$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text+checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# currently the same as text, eol=XXX+checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+done++# core.autocrlf false, different core.eol+checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# core.autocrlf true+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf = true overrides core.eol+checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLFLF_mix_CRLF_nul+checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+# text: core.autocrlf = input overrides core.eol+checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text=auto + eol=XXX+done+# text: core.autocrlf=false uses core.eol+checkout_filestext"$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+# text: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+# auto: core.autocrlf=false and core.eol unset(or native) uses native eol+checkout_filesauto"$id"""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
When the content of a commited file is unchanged and the attributes
are changed, Git may not detect that the next commit must treat the
file as changed. This happens when lstat() doesn't detect a change,
since neither inode, mtime nor size are changed.
Add a single "Z" character to change the file size and content.
When the files are compared later in checkout_files(), the "Z" is
removed before the comparison.
Signed-off-by: Torsten Bögershausen <redacted>
---
Changes against tb/convert-eol-autocrlf:
7/10 Implemented all comments, new commit message++
t/t0027-auto-crlf.sh | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Torsten Bögershausen <redacted>
Factor out the retrieval of the sha1 for a given path in
read_blob_data_from_index() into the function get_sha1_from_index().
This will be used in the next commit, when convert.c can do the
analyze for "text=auto" without slurping the whole blob into memory
at once.
Add a wrapper definition get_sha1_from_cache().
Signed-off-by: Torsten Bögershausen <redacted>
---
cache.h | 3 +++
read-cache.c | 29 ++++++++++++++++++-----------
2 files changed, 21 insertions(+), 11 deletions(-)
From: Torsten Bögershausen <redacted>
We define the working tree file is clean if either:
* the result of running convert_to_git() on the working tree
contents matches what is in the index (because that would mean
doing another "git add" on the path is a no-op); OR
* the result of running convert_to_working_tree() on the content
in the index matches what is in the working tree (because that
would mean doing another "git checkout -f" on the path is a
no-op).
Add an extra check in ce_compare_data() in read_cache.c.
Helped-by: Junio C Hamano [off-list ref]
Signed-off-by: Torsten Bögershausen <redacted>
---
read-cache.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
t/t6038-merge-text-auto.sh | 14 +++++------
2 files changed, 68 insertions(+), 7 deletions(-)
@@ -156,17 +156,78 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)ce_mark_uptodate(ce);}+/*+*Comparethedatainbufwiththedatainthefilepointedbyfdand+*return0iftheyareidentical,andnon-zeroiftheydiffer.+*/+staticintcompare_with_fd(constchar*input,ssize_tlen,intfd)+{+for(;;){+charbuf[1024*16];+ssize_tchunk_len,read_len;++chunk_len=sizeof(buf)<len?sizeof(buf):len;+read_len=xread(fd,buf,chunk_len?chunk_len:1);++if(!read_len)+/* EOF on the working tree file */+return!len?0:-1;++if(!len)+/* we expected there is nothing left */+return-1;++if(memcmp(buf,input,read_len))+return-1;+input+=read_len;+len-=read_len;+}+}+staticintce_compare_data(conststructcache_entry*ce,structstat*st){intmatch=-1;intfd=open(ce->name,O_RDONLY);+/*+*Wouldanother"git add"onthepathchangewhatisinthe+*indexforthepath?+*/if(fd>=0){unsignedcharsha1[20];if(!index_fd(sha1,fd,st,OBJ_BLOB,ce->name,0))match=hashcmp(sha1,ce->sha1);/* index_fd() closed the file descriptor already */}+if(!match)+returnmatch;++/*+*Wouldanother"git checkout -f"outoftheindexchange+*whatisintheworkingtreefile?+*/+fd=open(ce->name,O_RDONLY);+if(fd>=0){+enumobject_typetype;+unsignedlongsize_long;+void*data=read_sha1_file(ce->sha1,&type,&size_long);++if(type==OBJ_BLOB){+structstrbufworktree=STRBUF_INIT;+if(convert_to_working_tree(ce->name,data,+size_long,+&worktree)){+size_tsize;+free(data);+data=strbuf_detach(&worktree,&size);+size_long=size;+}+if(!compare_with_fd(data,size_long,fd))+match=0;+}+free(data);+close(fd);+}returnmatch;}
From: Torsten Bögershausen <redacted>
t6038 uses different code, dependig if NATIVE_CRLF is set ot not. When
the native line endings are LF, merge.renormalize is not tested very well.
Change the test to always use CRLF by setting core.eol=crlf.
After doing so, the test fails:
rm '.gitattributes'
rm 'control_file'
rm 'file'
rm 'inert_file'
HEAD is now at 0d9ffb6 add line from b
error: addinfo_cache failed for path 'file'
file: unmerged (cbd69ec7cd12dd0989e853923867d94c8519aa52)
file: unmerged (ad55e240aeb42e0d9a0e18d6d8b02dd82ee3e527)
file: unmerged (99b633103c15c20cebebf821133ab526b0ff90b2)
fatal: git write-tree failed to write a tree
Merging:
0d9ffb6 add line from b
virtual a
found 1 common ancestor:
1c56df1 Initial
Auto-merging file
not ok 4 - Merge addition of text=auto
This will be addressed in the next commit.
Signed-off-by: Torsten Bögershausen <redacted>
---
t/t6038-merge-text-auto.sh | 37 +++++++++++--------------------------
1 file changed, 11 insertions(+), 26 deletions(-)
From: Torsten Bögershausen <redacted>
This patch extends the work done in commit c480539:
"Make it work also for un-normalized repositories". Make sure that CRLF
can be converted round trip, or don't convert them at all.
The old handling would treat a file as unchanged after checkout,
as long as it is not touched in the work tree and mtime matches the value
recorded in the index.
When the mtime is changed in the working tree, or the inode is changed,
the file is reported as modified.
The following sequence is now handled reproducable:
$ git init
$ printf "line1\r\n" >file.bat
$ git add file.bat
$ git commit -m "Add file with CRLF" file.bat
$ echo "*.bat text eol=crlf" >.gitattributes
$ git commit -m "bat files should have CRLF"
$ git status
# nothing to commit, working directory clean
$ git push <upstream>
$ printf "newline\r\n" >>file.bat
$ mv file.bat file.sav
$ git checkout file.bat
$ git status
#modified: file.bat
The new handling makes sure that after running "git reset --hard".
"git status" reports the working tree as clean regarding CRLF conversion.
It makes sure that the Git-internal eol conversion is
doing roundtrip. A user can still write an external smudge/clean filter
outside Git, which doesn't do a roundtrip and the working directory is
not clean.
The functionality of has_cr_in_index() is turned into has_crlf_in_index(),
and the function is integrated into would_convert_crlf_at_commit().
Check for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR
is no longer used and removed, as well as "lonecr" in struct text_stat.
Rewrite check_safe_crlf() in convert.c to simulate checkin-checkout,
to detect whether any line endings are converted.
Add a warning, similar to the CRLF-LF replacement, when a file is commited,
and after the next checkout the line endings are not what they should be.
Modify the lf_to_crlf_filter:
Files with LF are converted into CRLF, file with CRLF are not changed.
Files with mixed line endings are not converted, the filter fails, and Git
falls back to the non-streaming handling, see write_entry().
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/gitattributes.txt | 19 ++--
convert.c | 235 +++++++++++++++++++++++++---------------
t/t0025-crlf-auto.sh | 8 +-
t/t0027-auto-crlf.sh | 92 ++++++++--------
4 files changed, 213 insertions(+), 141 deletions(-)
@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'. `text` ^^^^^^-This attribute enables and controls end-of-line normalization. When a+This attribute enables and controls end-of-line conversion. When a text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the
@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol` Set:: Setting the `text` attribute on a path enables end-of-line- normalization and marks the path as a text file. End-of-line+ conversion and marks the path as a text file. End-of-line conversion takes place without guessing the content type.+ Files that have been commited with CRLF before the text attribute+ is set and commited are not normalized. No end-of-line conversion+ is done at checkout or checkin. Unset::
@@ -131,9 +134,9 @@ Unset:: Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic- end-of-line conversion. If Git decides that the content is- text, its line endings are converted to LF on checkin.- When the file has been commited with CRLF, no conversion is done.+ end-of-line normalization. If Git decides that the content is+ text, and the path has no CRLF in the index,+ its line endings are converted to LF on checkin. Unspecified::
@@ -148,8 +151,10 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It enables end-of-line conversion without any-content checks, effectively setting the `text` attribute.+working directory. It sets the `text` attribute, unless `text=auto`+is specified.+When the file had been commited with CRLF in the index, no conversion+is done at checkout or commit. Set to string value "crlf"::
@@ -32,7 +33,7 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignedstat_bits,lonecr,lonelf,crlf;+unsignedstat_bits,lonelf;/* These are just approximations! */unsignedprintable,nonprintable;
@@ -135,7 +133,7 @@ static unsigned get_convert_stats_sha1(unsigned const char *sha1,if(!readlen)break;do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);-if(stats.stat_bits&earlyout)+if((stats.stat_bits&earlyout)==earlyout)break;/* We found what we have been searching for */}close_and_exit_i:
@@ -240,43 +229,95 @@ static enum eol output_eol(enum crlf_action crlf_action)returnEOL_UNSET;}+staticintwould_convert_lf_at_checkout(unsignedconvert_stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+if(output_eol(crlf_action)!=EOL_CRLF)+return0;++/* No "naked" LF? Nothing to convert, regardless. */+if(!(convert_stats&CONVERT_STAT_BITS_TXT_LF))+return0;++if(crlf_action==CRLF_AUTO||+crlf_action==CRLF_AUTO_INPUT||+crlf_action==CRLF_AUTO_CRLF){+/* auto: binary files are not converted */+if(convert_stats&CONVERT_STAT_BITS_BIN)+return0;+}+/* If we have any CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;++}++staticintwould_convert_crlf_at_commit(constchar*path,+conststructtext_stat*stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+unsignedstat_bits_index;+/* No CRLF? Nothing to convert, regardless. */+if(!(stats->stat_bits&CONVERT_STAT_BITS_TXT_CRLF))+return0;+/*+*IfthefileintheindexhasanyCRLFinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+stat_bits_index=get_convert_stats_sha1(get_sha1_from_cache(path),+CONVERT_STAT_BITS_TXT_CRLF);+if(stat_bits_index&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;+}+staticvoidcheck_safe_crlf(constchar*path,enumcrlf_actioncrlf_action,-structtext_stat*stats,enumsafe_crlfchecksafe)+enumsafe_crlfchecksafe,+unsignedconvert_stats,unsignednew_convert_stats){+enumeolnew_eol=output_eol(crlf_action);+constchar*err_warn_msg=NULL;if(!checksafe)return;--if(output_eol(crlf_action)==EOL_LF){+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)){/**CRLFswouldnotberestoredbycheckout:*checkifwe'dremoveCRLFs*/-if(stats->crlf){-if(checksafe==SAFE_CRLF_WARN)-warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("CRLF would be replaced by LF in %s.",path);-}-}elseif(output_eol(crlf_action)==EOL_CRLF){+if(checksafe==SAFE_CRLF_WARN)+warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("CRLF would be replaced by LF in %s.",path);+}+if(convert_stats&CONVERT_STAT_BITS_TXT_LF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_LF)){/**CRLFswouldbeaddedbycheckout:*checkifwehave"naked"LFs*/-if(stats->lonelf){-if(checksafe==SAFE_CRLF_WARN)-warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("LF would be replaced by CRLF in %s",path);-}+if(checksafe==SAFE_CRLF_WARN)+warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("LF would be replaced by CRLF in %s",path);+}+if((new_convert_stats&CONVERT_STAT_BITS_MIXED)==CONVERT_STAT_BITS_MIXED)+err_warn_msg="mixed eol";+elseif(new_eol==EOL_LF&&new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+err_warn_msg="CRLF";++if(err_warn_msg){+if(checksafe==SAFE_CRLF_WARN)+warning("%s will be present after commit and checkout in %s.",+err_warn_msg,path);+else+die("%s will be present after commit and checkout in %s",+err_warn_msg,path);}-}--staticinthas_cr_in_index(constchar*path)-{-unsignedconvert_stats;-convert_stats=get_convert_stats_sha1(get_sha1_from_cache(path),-CONVERT_STAT_BITS_ANY_CR);-returnconvert_stats&CONVERT_STAT_BITS_ANY_CR;}staticintcrlf_to_git(constchar*path,constchar*src,size_tlen,
@@ -355,28 +416,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,{char*to_free=NULL;structtext_statstats;-unsignedearlyout=CONVERT_STAT_BITS_TXT_CRLF|CONVERT_STAT_BITS_BIN;---if(!len||output_eol(crlf_action)!=EOL_CRLF)+unsignedearlyout=0;/* Need to count lonelf */+if(!len)return0;gather_stats(src,len,&stats,earlyout);--/* No "naked" LF? Nothing to convert, regardless. */-if(!stats.lonelf)+if(!would_convert_lf_at_checkout(stats.stat_bits,+len,crlf_action))return0;-if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;--if(stats.stat_bits&CONVERT_STAT_BITS_BIN)-return0;-}-/* are we "faking" in place editing ? */if(src==buf->buf)to_free=strbuf_detach(buf,NULL);
@@ -1068,6 +1116,8 @@ int is_null_stream_filter(struct stream_filter *filter)structlf_to_crlf_filter{structstream_filterfilter;unsignedhas_held:1;+unsignedexpanded_loneLF:1;+unsignedhad_CRLF:1;charheld;};
@@ -1108,7 +1158,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,charch=input[i];if(ch=='\n'){-output[o++]='\r';+if(!lf_to_crlf->had_CRLF){+output[o++]='\r';+lf_to_crlf->expanded_loneLF=1;+}+if(was_cr)+lf_to_crlf->had_CRLF=1;}elseif(was_cr){/**PreviousroundsawCRanditisnotfollowed
@@ -1137,6 +1192,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,was_cr=0;output[o++]=ch;+if(lf_to_crlf->expanded_loneLF&&+lf_to_crlf->had_CRLF){+/*+*MixedEOL,roundtripnotpossible.+*/+return1;+}+}*osize_p-=o;
@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' 'test-z"$LFonlydiff"-a-z"$CRLFonlydiff"-a-z"$LFwithNULdiff"'-test_expect_success'crlf=true causes a CRLF file to be normalized''+test_expect_success'crlf=true causes a CRLF file not to be normalized''# Backwards compatibility checkrm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&
@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"'-test_expect_success'text=true causes a CRLF file to be normalized''+test_expect_success'text=true causes a CRLF file not to be normalized''rm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&echo"CRLFonly text">.gitattributes&&
@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"' test_expect_success'eol=crlf gives a normalized file CRLFs with autocrlf=false''
@@ -71,10 +71,14 @@ check_warning () {case"$1"inLF_CRLF)echo"warning: LF will be replaced by CRLF">"$2".expect;;CRLF_LF)echo"warning: CRLF will be replaced by LF">"$2".expect;;+CRLF)echo"warning: CRLF will be present after commit and checkout">"$2".expect;;+mixed)echo"warning: mixed eol will be present after commit and checkout">"$2".expect;;'')>"$2".expect;;*)echo>&2"Illegal 1":"$1";returnfalse;;esac-grep"will be replaced by""$2"|sed-e"s/\(.*\) in [^ ]*$/\1/"|uniq>"$2".actual+egrep"will be replaced by|will be present after commit""$2"|+sed-e"s/\(.*\) in [^ ]*$/\1/"|+uniq>"$2".actualtest_cmp"$2".expect"$2".actual}
@@ -169,7 +173,7 @@ stats_ascii () {# Take none (=empty), one or two args# convert.c: eol=XX overrides text=auto attr_ascii(){-case$1,$2in+case"$1","$2"in-text,*)echo"-text";;text,)echo"text";;text,lf)echo"text eol=lf";;
@@ -456,9 +463,9 @@ docheck_in_repo_NNOauto""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautolf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautocrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldone################################################################################# Check how files in the repo are changed when they are checked out
@@ -492,8 +497,7 @@ fiexportCRLF_MIX_LF_CRMIXNL# Same handling with and without ident-#for id in "" ident-foridin""+foridin""identdoforceolinlfcrlfnativedo
@@ -501,38 +505,38 @@ dodo# -text overrides core.autocrlf and core.eol# text and eol=crlf or eol=lf override core.autocrlf and core.eol-checkout_files-text"$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files-text"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files-text"$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text-checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul# currently the same as text, eol=XXX-checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# core.autocrlf false, different core.eol-checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# core.autocrlf true-checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text: core.autocrlf = true overrides core.eol-checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul# text: core.autocrlf = input overrides core.eol-checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text=auto + eol=XXXdone# text: core.autocrlf=false uses core.eol-checkout_filestext"$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""falsecrlfCRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul+checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_filestext"$id"""false""$NLCRLFCRLF_mix_LF"$MIX_LF_CR""$LFNUL"+checkout_filestext"$id"""falsenative$NLCRLFCRLF_mix_LF"$MIX_LF_CR""$LFNUL"# auto: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
Changes since v8:
As discussed earlier, 1..4 should be broken out into
tb/autocrlf-fix or so.
1..4 are not part of this series any more.
The old 10/10 is now 6/6.
It is replaced by "ce_compare_data() checks for a sha1 of a path"
It now checks for "What would git add change in the index",
and not "is the working tree clean after checkout" -
thats how it should be.
Basically an old limititation of "has_crlf_in_index()" has been found and
fixed.
The commit message may need some tweaking, and
even the implementation, so feedback is welcome.
Beside that, I haven't run the tests under Windows yet.
Torsten Bögershausen (6):
read-cache: factor out get_sha1_from_index() helper
convert.c: stream and early out
convert: unify the "auto" handling of CRLF
convert.c: more safer crlf handling with text attribute
t6038; use crlf on all platforms
convert: ce_compare_data() checks for a sha1 of a path
Documentation/config.txt | 14 +-
Documentation/gitattributes.txt | 24 ++-
cache.h | 4 +
convert.c | 362 +++++++++++++++++++++++++++-------------
convert.h | 26 ++-
read-cache.c | 33 ++--
sha1_file.c | 17 +-
t/t0025-crlf-auto.sh | 12 +-
t/t0027-auto-crlf.sh | 98 +++++------
t/t6038-merge-text-auto.sh | 60 +++----
10 files changed, 407 insertions(+), 243 deletions(-)
--
2.0.0.rc1.6318.g0c2c796
From: Torsten Bögershausen <redacted>
Factor out the retrieval of the sha1 for a given path in
read_blob_data_from_index() into the function get_sha1_from_index().
This will be used in the next commit, when convert.c can do the
analyze for "text=auto" without slurping the whole blob into memory
at once.
Add a wrapper definition get_sha1_from_cache().
Signed-off-by: Torsten Bögershausen <redacted>
---
cache.h | 3 +++
read-cache.c | 29 ++++++++++++++++++-----------
2 files changed, 21 insertions(+), 11 deletions(-)
From: Torsten Bögershausen <redacted>
To compare a file in working tree with the index, convert_to_git() is used,
the the result is hashed and the hash value compared with ce->sha1.
Deep down would_convert_crlf_at_commit() is invoked, to check if CRLF
are converted or not: When a CRLF had been in the index before, CRLF in
the working tree are not converted.
While in a merge, a file name in the working tree has different blobs
in the index with different hash values.
Forwarding ce->sha1 from ce_compare_data() into crlf_to_git() makes sure
the would_convert_crlf_at_commit() looks at the appropriate blob.
---
cache.h | 1 +
convert.c | 30 ++++++++++++++++++++----------
convert.h | 23 +++++++++++++++++++----
read-cache.c | 4 +++-
sha1_file.c | 17 +++++++++++++----
t/t6038-merge-text-auto.sh | 12 ++++++------
6 files changed, 62 insertions(+), 25 deletions(-)
@@ -3313,12 +3317,15 @@ static int index_stream_convert_blob(unsigned char *sha1, int fd,{intret;constintwrite_object=flags&HASH_WRITE_OBJECT;+constintvalid_sha1=flags&HASH_CE_HAS_SHA1;structstrbufsbuf=STRBUF_INIT;assert(path);assert(would_convert_to_git_filter_fd(path));-convert_to_git_filter_fd(path,fd,&sbuf,+convert_to_git_filter_fd(path,+valid_sha1?sha1:NULL,+fd,&sbuf,write_object?safe_crlf:SAFE_CRLF_FALSE);if(write_object)
@@ -3396,6 +3403,8 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st,enumobject_typetype,constchar*path,unsignedflags){intret;+constunsignedchar*sha1_ce;+sha1_ce=flags&HASH_CE_HAS_SHA1?sha1:NULL;/**Callxsize_t()onlywhenneededtoavoidpotentiallyunnecessary
@@ -3406,7 +3415,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st,elseif(!S_ISREG(st->st_mode))ret=index_pipe(sha1,fd,type,path,flags);elseif(st->st_size<=big_file_threshold||type!=OBJ_BLOB||-(path&&would_convert_to_git(path)))+(path&&would_convert_to_git_ce_sha1(path,sha1_ce)))ret=index_core(sha1,fd,xsize_t(st->st_size),type,path,flags);else
From: Torsten Bögershausen <redacted>
A follow-up after a discussion how to fix the flaky execution
of t0025, gmane/$284352.
This patch extends the work done in commit c480539:
"Make it work also for un-normalized repositories". Make sure that CRLF
can be converted round trip, or don't convert them at all.
The old handling would treat a file as unchanged after checkout,
as long as it is not touched in the work tree and mtime matches the value
recorded in the index.
When the mtime is changed in the working tree, or the inode is changed,
the file is reported as modified.
The following sequence is now handled reproducable:
$ git init
$ printf "line1\r\n" >file.bat
$ git add file.bat
$ git commit -m "Add file with CRLF" file.bat
$ echo "*.bat text eol=crlf" >.gitattributes
$ git commit -m "bat files should have CRLF"
$ git status
# nothing to commit, working directory clean
$ git push <upstream>
$ printf "newline\r\n" >>file.bat
$ mv file.bat file.sav
$ git checkout file.bat
$ git status
#modified: file.bat
The new handling makes sure that after running "git reset --hard".
"git status" reports the working tree as clean regarding CRLF conversion.
It makes sure that the Git-internal eol conversion is
doing roundtrip. A user can still write an external smudge/clean filter
outside Git, which doesn't do a roundtrip and the working directory is
not clean.
The functionality of has_cr_in_index() is turned into has_crlf_in_index(),
and the function is integrated into would_convert_crlf_at_commit().
Check for CRLF in the index instead of CR, the bit CONVERT_STAT_BITS_ANY_CR
is no longer used and removed, as well as "lonecr" in struct text_stat.
Rewrite check_safe_crlf() in convert.c to simulate checkin-checkout,
to detect whether any line endings are converted.
Add a warning, similar to the CRLF-LF replacement, when a file is commited,
and after the next checkout the line endings are not they should be.
Modify the lf_to_crlf_filter:
Files with LF are converted into CRLF, file with CRLF are not changed.
Files with mixed line endings are not converted, the filter fails, and Git
falls back to the non-streaming handling, see write_entry().
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/gitattributes.txt | 19 ++--
convert.c | 233 +++++++++++++++++++++++++---------------
t/t0025-crlf-auto.sh | 8 +-
t/t0027-auto-crlf.sh | 92 ++++++++--------
4 files changed, 212 insertions(+), 140 deletions(-)
@@ -110,7 +110,7 @@ repository upon 'git add' and 'git commit'. `text` ^^^^^^-This attribute enables and controls end-of-line normalization. When a+This attribute enables and controls end-of-line conversion. When a text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the
@@ -120,8 +120,11 @@ Note that `core.autocrlf` overrides `core.eol` Set:: Setting the `text` attribute on a path enables end-of-line- normalization and marks the path as a text file. End-of-line+ conversion and marks the path as a text file. End-of-line conversion takes place without guessing the content type.+ Files that have been commited with CRLF before the text attribute+ is set and commited are not normalized. No end-of-line conversion+ is done at checkout or checkin. Unset::
@@ -131,9 +134,9 @@ Unset:: Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic- end-of-line conversion. If Git decides that the content is- text, its line endings are converted to LF on checkin.- When the file has been commited with CRLF, no conversion is done.+ end-of-line normalization. If Git decides that the content is+ text, and the path has no CRLF in the index,+ its line endings are converted to LF on checkin. Unspecified::
@@ -148,8 +151,10 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It enables end-of-line conversion without any-content checks, effectively setting the `text` attribute.+working directory. It sets the `text` attribute, unless `text=auto`+is specified.+When the file had been commited with CRLF in the index, no conversion+is done at checkout or commit. Set to string value "crlf"::
@@ -32,7 +33,7 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignedstat_bits,lonecr,lonelf,crlf;+unsignedstat_bits,lonelf;/* These are just approximations! */unsignedprintable,nonprintable;
@@ -135,7 +133,7 @@ static unsigned get_convert_stats_sha1(unsigned const char *sha1,if(!readlen)break;do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);-if(stats.stat_bits&earlyout)+if((stats.stat_bits&earlyout)==earlyout)break;/* We found what we have been searching for */}close_and_exit_i:
@@ -239,43 +228,95 @@ static enum eol output_eol(enum crlf_action crlf_action)returncore_eol;}+staticintwould_convert_lf_at_checkout(unsignedconvert_stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+if(output_eol(crlf_action)!=EOL_CRLF)+return0;++/* No "naked" LF? Nothing to convert, regardless. */+if(!convert_stats&CONVERT_STAT_BITS_TXT_LF)+return0;++if(crlf_action==CRLF_AUTO||+crlf_action==CRLF_AUTO_INPUT||+crlf_action==CRLF_AUTO_CRLF){+/* auto: binary files are not converted */+if(convert_stats&CONVERT_STAT_BITS_BIN)+return0;+}+/* If we have any CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;++}++staticintwould_convert_crlf_at_commit(constchar*path,+conststructtext_stat*stats,+size_tlen,+enumcrlf_actioncrlf_action)+{+unsignedstat_bits_index;+/* No CRLF? Nothing to convert, regardless. */+if(!(stats->stat_bits&CONVERT_STAT_BITS_TXT_CRLF))+return0;+/*+*IfthefileintheindexhasanyCRLFinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+stat_bits_index=get_convert_stats_sha1(get_sha1_from_cache(path),+CONVERT_STAT_BITS_TXT_CRLF);+if(stat_bits_index&CONVERT_STAT_BITS_TXT_CRLF)+return0;+return1;+}+staticvoidcheck_safe_crlf(constchar*path,enumcrlf_actioncrlf_action,-structtext_stat*stats,enumsafe_crlfchecksafe)+enumsafe_crlfchecksafe,+unsignedconvert_stats,unsignednew_convert_stats){+enumeolnew_eol=output_eol(crlf_action);+constchar*err_warn_msg=NULL;if(!checksafe)return;--if(output_eol(crlf_action)==EOL_LF){+if(convert_stats&CONVERT_STAT_BITS_TXT_CRLF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)){/**CRLFswouldnotberestoredbycheckout:*checkifwe'dremoveCRLFs*/-if(stats->crlf){-if(checksafe==SAFE_CRLF_WARN)-warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("CRLF would be replaced by LF in %s.",path);-}-}elseif(output_eol(crlf_action)==EOL_CRLF){+if(checksafe==SAFE_CRLF_WARN)+warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("CRLF would be replaced by LF in %s.",path);+}+if(convert_stats&CONVERT_STAT_BITS_TXT_LF&&+!(new_convert_stats&CONVERT_STAT_BITS_TXT_LF)){/**CRLFswouldbeaddedbycheckout:*checkifwehave"naked"LFs*/-if(stats->lonelf){-if(checksafe==SAFE_CRLF_WARN)-warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);-else/* i.e. SAFE_CRLF_FAIL */-die("LF would be replaced by CRLF in %s",path);-}+if(checksafe==SAFE_CRLF_WARN)+warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.",path);+else/* i.e. SAFE_CRLF_FAIL */+die("LF would be replaced by CRLF in %s",path);+}+if((new_convert_stats&CONVERT_STAT_BITS_MIXED)==CONVERT_STAT_BITS_MIXED)+err_warn_msg="mixed eol";+elseif(new_eol==EOL_LF&&new_convert_stats&CONVERT_STAT_BITS_TXT_CRLF)+err_warn_msg="CRLF";++if(err_warn_msg){+if(checksafe==SAFE_CRLF_WARN)+warning("%s will be present after commit and checkout in %s.",+err_warn_msg,path);+else+die("%s will be present after commit and checkout in %s",+err_warn_msg,path);}-}--staticinthas_cr_in_index(constchar*path)-{-unsignedconvert_stats;-convert_stats=get_convert_stats_sha1(get_sha1_from_cache(path),-CONVERT_STAT_BITS_ANY_CR);-returnconvert_stats&CONVERT_STAT_BITS_ANY_CR;}staticintcrlf_to_git(constchar*path,constchar*src,size_tlen,
@@ -354,28 +415,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,{char*to_free=NULL;structtext_statstats;-unsignedearlyout=CONVERT_STAT_BITS_TXT_CRLF|CONVERT_STAT_BITS_BIN;---if(!len||output_eol(crlf_action)!=EOL_CRLF)+unsignedearlyout=0;/* Need to count lonelf */+if(!len)return0;gather_stats(src,len,&stats,earlyout);--/* No "naked" LF? Nothing to convert, regardless. */-if(!stats.lonelf)+if(!would_convert_lf_at_checkout(stats.stat_bits,+len,crlf_action))return0;-if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;--if(stats.stat_bits&CONVERT_STAT_BITS_BIN)-return0;-}-/* are we "faking" in place editing ? */if(src==buf->buf)to_free=strbuf_detach(buf,NULL);
@@ -1067,6 +1115,8 @@ int is_null_stream_filter(struct stream_filter *filter)structlf_to_crlf_filter{structstream_filterfilter;unsignedhas_held:1;+unsignedexpanded_loneLF:1;+unsignedhad_CRLF:1;charheld;};
@@ -1107,7 +1157,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,charch=input[i];if(ch=='\n'){-output[o++]='\r';+if(!lf_to_crlf->had_CRLF){+output[o++]='\r';+lf_to_crlf->expanded_loneLF=1;+}+if(was_cr)+lf_to_crlf->had_CRLF=1;}elseif(was_cr){/**PreviousroundsawCRanditisnotfollowed
@@ -1136,6 +1191,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,was_cr=0;output[o++]=ch;+if(lf_to_crlf->expanded_loneLF&&+lf_to_crlf->had_CRLF){+/*+*MixedEOL,roundtripnotpossible.+*/+return1;+}+}*osize_p-=o;
@@ -39,7 +39,7 @@ test_expect_success 'default settings cause no changes' 'test-z"$LFonlydiff"-a-z"$CRLFonlydiff"-a-z"$LFwithNULdiff"'-test_expect_success'crlf=true causes a CRLF file to be normalized''+test_expect_success'crlf=true causes a CRLF file not to be normalized''# Backwards compatibility checkrm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&
@@ -49,10 +49,10 @@ test_expect_success 'crlf=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"'-test_expect_success'text=true causes a CRLF file to be normalized''+test_expect_success'text=true causes a CRLF file not to be normalized''rm-f.gitattributestmpLFonlyCRLFonlyLFwithNUL&&echo"CRLFonly text">.gitattributes&&
@@ -61,7 +61,7 @@ test_expect_success 'text=true causes a CRLF file to be normalized' '# Note, "normalized" means that git will normalize it if addedhas_crCRLFonly&&CRLFonlydiff=$(gitdiffCRLFonly)&&-test-n"$CRLFonlydiff"+test-z"$CRLFonlydiff"' test_expect_success'eol=crlf gives a normalized file CRLFs with autocrlf=false''
@@ -71,10 +71,14 @@ check_warning () {case"$1"inLF_CRLF)echo"warning: LF will be replaced by CRLF">"$2".expect;;CRLF_LF)echo"warning: CRLF will be replaced by LF">"$2".expect;;+CRLF)echo"warning: CRLF will be present after commit and checkout">"$2".expect;;+mixed)echo"warning: mixed eol will be present after commit and checkout">"$2".expect;;'')>"$2".expect;;*)echo>&2"Illegal 1":"$1";returnfalse;;esac-grep"will be replaced by""$2"|sed-e"s/\(.*\) in [^ ]*$/\1/"|uniq>"$2".actual+egrep"will be replaced by|will be present after commit""$2"|+sed-e"s/\(.*\) in [^ ]*$/\1/"|+uniq>"$2".actualtest_cmp"$2".expect"$2".actual}
@@ -169,7 +173,7 @@ stats_ascii () {# Take none (=empty), one or two args# convert.c: eol=XX overrides text=auto attr_ascii(){-case$1,$2in+case"$1","$2"in-text,*)echo"-text";;text,)echo"text";;text,lf)echo"text eol=lf";;
@@ -456,9 +463,9 @@ docheck_in_repo_NNOauto""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautolf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nulcheck_in_repo_NNOautocrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul-check_in_repo_NNOtext""$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextlf$crlfLFLFLFLF_mix_CRLF_nul-check_in_repo_NNOtextcrlf$crlfLFLFLFLF_mix_CRLF_nul+check_in_repo_NNOtext""$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nul+check_in_repo_NNOtextcrlf$crlfLFCRLFCRLF_mix_LFLF_mix_CRCRLF_nuldone################################################################################# Check how files in the repo are changed when they are checked out
@@ -492,8 +497,7 @@ fiexportCRLF_MIX_LF_CRMIXNL# Same handling with and without ident-#for id in "" ident-foridin""+foridin""identdoforceolinlfcrlfnativedo
@@ -501,38 +505,38 @@ dodo# -text overrides core.autocrlf and core.eol# text and eol=crlf or eol=lf override core.autocrlf and core.eol-checkout_files-text"$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files-text"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_files-text"$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"-text""$id""crlf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text-checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filestext"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul# currently the same as text, eol=XXX-checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# core.autocrlf false, different core.eol-checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id"""false"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# core.autocrlf true-checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_files"""$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text: core.autocrlf = true overrides core.eol-checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filesauto"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""true"$ceol"CRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul# text: core.autocrlf = input overrides core.eol-checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""input"$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text=auto + eol=XXXdone# text: core.autocrlf=false uses core.eol-checkout_filestext"$id"""falsecrlfCRLFCRLFCRLFCRLF_mix_CRCRLF_nul-checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filestext"$id"""falsecrlfCRLFCRLFCRLF_mix_LFCRLF_mix_CRCRLF_nul+checkout_filestext"$id"""falselfLFCRLFCRLF_mix_LFLF_mix_CRLF_nul# text: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL-checkout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL+checkout_filestext"$id"""false""$NLCRLFCRLF_mix_LF"$MIX_LF_CR""$LFNUL"+checkout_filestext"$id"""falsenative$NLCRLFCRLF_mix_LF"$MIX_LF_CR""$LFNUL"# auto: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
From: Torsten Bögershausen <redacted>
t6038 uses different code, dependig if NATIVE_CRLF is set ot not.
When the native line endings are LF, merge.renormalize is not tested very well.
Change the test to always use CRLF by setting core.eol=crlf.
After doing so, the test fails:
rm '.gitattributes'
rm 'control_file'
rm 'file'
rm 'inert_file'
HEAD is now at 0d9ffb6 add line from b
error: addinfo_cache failed for path 'file'
file: unmerged (cbd69ec7cd12dd0989e853923867d94c8519aa52)
file: unmerged (ad55e240aeb42e0d9a0e18d6d8b02dd82ee3e527)
file: unmerged (99b633103c15c20cebebf821133ab526b0ff90b2)
fatal: git write-tree failed to write a tree
Merging:
0d9ffb6 add line from b
virtual a
found 1 common ancestor:
1c56df1 Initial
Auto-merging file
not ok 4 - Merge addition of text=auto
This will be addressed in the next commit.
---
t/t6038-merge-text-auto.sh | 37 +++++++++++--------------------------
1 file changed, 11 insertions(+), 26 deletions(-)
From: Torsten Bögershausen <redacted>
Before this change,
$ echo "* text=auto" >.gitattributes
$ echo "* eol=crlf" >>.gitattributes
would have the same effect as
$ echo "* text" >.gitattributes
$ git config core.eol crlf
Since the 'eol' attribute had higher priority than 'text=auto', this may
corrupt binary files and is not what most users expect to happen.
Make the 'eol' attribute to obey 'text=auto', and now
$ echo "* text=auto" >.gitattributes
$ echo "* eol=crlf" >>.gitattributes
behaves the same as
$ echo "* text=auto" >.gitattributes
$ git config core.eol crlf
In other words,
$ echo "* text=auto eol=crlf" >.gitattributes
has the same effect as
$ git config core.autocrlf true
and
$ echo "* text=auto eol=lf" >.gitattributes
has the same effect as
$ git config core.autocrlf input
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/config.txt | 14 +++++++-------
Documentation/gitattributes.txt | 15 +++++++++------
convert.c | 42 +++++++++++++++++++++--------------------
convert.h | 3 ++-
t/t0025-crlf-auto.sh | 4 ++--
t/t0027-auto-crlf.sh | 32 +++++++++++++++----------------
t/t6038-merge-text-auto.sh | 23 ++++++++++++++--------
7 files changed, 73 insertions(+), 60 deletions(-)
@@ -397,13 +397,13 @@ file with mixed line endings would be reported by the `core.safecrlf` mechanism. core.autocrlf::- Setting this variable to "true" is almost the same as setting- the `text` attribute to "auto" on all files except that text- files are not guaranteed to be normalized: files that contain- `CRLF` in the repository will not be touched. Use this- setting if you want to have `CRLF` line endings in your- working directory even though the repository does not have- normalized line endings. This variable can be set to 'input',+ Setting this variable to "true" is the same as setting+ the `text` attribute to "auto" on all files and core.eol to "crlf".+ Set to true if you want to have `CRLF` line endings in your+ working directory and the repository has LF line endings.+ Text files are guaranteed not to be normalized: files that contain+ `CRLF` in the repository will not be touched.+ This variable can be set to 'input', in which case no output conversion is performed. core.symlinks::
@@ -115,6 +115,7 @@ text file is normalized, its line endings are converted to LF in the repository. To control what line ending style is used in the working directory, use the `eol` attribute for a single file and the `core.eol` configuration variable for all text files.+Note that `core.autocrlf` overrides `core.eol` Set::
@@ -130,8 +131,9 @@ Unset:: Set to string value "auto":: When `text` is set to "auto", the path is marked for automatic- end-of-line normalization. If Git decides that the content is- text, its line endings are normalized to LF on checkin.+ end-of-line conversion. If Git decides that the content is+ text, its line endings are converted to LF on checkin.+ When the file has been commited with CRLF, no conversion is done. Unspecified::
@@ -146,7 +148,7 @@ unspecified. ^^^^^ This attribute sets a specific line-ending style to be used in the-working directory. It enables end-of-line normalization without any+working directory. It enables end-of-line conversion without any content checks, effectively setting the `text` attribute. Set to string value "crlf"::
@@ -186,9 +188,10 @@ the working directory, and prevent .jpg files from being normalized regardless of their content. ------------------------+* text=auto *.txt text-*.vcproj eol=crlf-*.sh eol=lf+*.vcproj text eol=crlf+*.sh text eol=lf *.jpg -text ------------------------
@@ -198,7 +201,7 @@ normalization in Git. If you simply want to have CRLF line endings in your working directory regardless of the repository you are working with, you can set the-config variable "core.autocrlf" without changing any attributes.+config variable "core.autocrlf" without using any attributes. ------------------------ [core]
@@ -227,7 +227,9 @@ static enum eol output_eol(enum crlf_action crlf_action)returnEOL_LF;caseCRLF_UNDEFINED:caseCRLF_AUTO_CRLF:+returnEOL_CRLF;caseCRLF_AUTO_INPUT:+returnEOL_LF;caseCRLF_TEXT:caseCRLF_AUTO:/* fall through */
@@ -299,17 +301,15 @@ static int crlf_to_git(const char *path, const char *src, size_t len,if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;--if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/*-*IfthefileintheindexhasanyCRinit,donotconvert.-*Thisisthenewsaferautocrlfhandling.-*/-if(has_cr_in_index(path))-return0;-}+/*+*IfthefileintheindexhasanyCRinit,donotconvert.+*Thisisthenewsaferautocrlfhandling.+*/+if(checksafe==SAFE_CRLF_RENORMALIZE)+checksafe=SAFE_CRLF_FALSE;+elseif(has_cr_in_index(path))+return0;}-check_safe_crlf(path,crlf_action,&stats,checksafe);/* Optimization: No CRLF? Nothing to convert, regardless. */
@@ -367,12 +367,10 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,return0;if(crlf_action==CRLF_AUTO||crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-if(crlf_action==CRLF_AUTO_INPUT||crlf_action==CRLF_AUTO_CRLF){-/* If we have any CR or CRLF line endings, we do not touch it */-/* This is the new safer autocrlf-handling */-if(stats.lonecr||stats.crlf)-return0;-}+/* If we have any CR or CRLF line endings, we do not touch it */+/* This is the new safer autocrlf-handling */+if(stats.lonecr||stats.crlf)+return0;if(stats.stat_bits&CONVERT_STAT_BITS_BIN)return0;
@@ -892,9 +894,9 @@ const char *get_convert_attr_ascii(const char *path)caseCRLF_AUTO:return"text=auto";caseCRLF_AUTO_CRLF:-return"text=auto eol=crlf";/* This is not supported yet */+return"text=auto eol=crlf";caseCRLF_AUTO_INPUT:-return"text=auto eol=lf";/* This is not supported yet */+return"text=auto eol=lf";}return"";}
@@ -493,7 +492,8 @@ fiexportCRLF_MIX_LF_CRMIXNL# Same handling with and without ident-foridin""ident+#for id in "" ident+foridin""doforceolinlfcrlfnativedo
@@ -509,7 +509,7 @@ docheckout_filestext"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul# currently the same as text, eol=XXXcheckout_filesauto"$id""lf""$crlf""$ceol"LFCRLFCRLF_mix_LFLF_mix_CRLF_nul-checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLFCRLF_mix_CRCRLF_nul+checkout_filesauto"$id""crlf""$crlf""$ceol"CRLFCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# core.autocrlf false, different core.eol
@@ -531,8 +531,8 @@ docheckout_filestext"$id"""false""$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNULcheckout_filestext"$id"""falsenative$NLCRLF$MIX_CRLF_LF$MIX_LF_CR$LFNUL# auto: core.autocrlf=false and core.eol unset(or native) uses native eol-checkout_filesauto"$id"""false""$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul-checkout_filesauto"$id"""falsenative$NLCRLF$MIX_CRLF_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""false""$NLCRLFCRLF_mix_LFLF_mix_CRLF_nul+checkout_filesauto"$id"""falsenative$NLCRLFCRLF_mix_LFLF_mix_CRLF_nuldone# Should be the last test case: remove some files from the worktree
@@ -81,7 +88,7 @@ test_expect_success 'Merge after setting text=auto' 'rm-f.gitattributes&&gitreset--harda&&gitmergeb&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Merge addition of text=auto''
@@ -99,7 +106,7 @@ test_expect_success 'Merge addition of text=auto' 'rm-f.gitattributes&&gitreset--hardb&&gitmergea&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Detect CRLF/LF conflict after setting text=auto''
@@ -121,7 +128,7 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' 'gitreset--harda&&test_must_failgitmergeb&&fuzz_conflictfile>file.fuzzy&&-test_cmpexpectedfile.fuzzy+compare_filesexpectedfile.fuzzy' test_expect_success'Detect LF/CRLF conflict from addition of text=auto''
@@ -143,7 +150,7 @@ test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' 'gitreset--hardb&&test_must_failgitmergea&&fuzz_conflictfile>file.fuzzy&&-test_cmpexpectedfile.fuzzy+compare_filesexpectedfile.fuzzy' test_expect_failure'checkout -m after setting text=auto''
@@ -158,7 +165,7 @@ test_expect_failure 'checkout -m after setting text=auto' 'gitreset--hardinitial&&gitcheckouta--.&&gitcheckout-mb&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_failure'checkout -m addition of text=auto''
@@ -173,7 +180,7 @@ test_expect_failure 'checkout -m addition of text=auto' 'gitreset--hardinitial&&gitcheckoutb--.&&gitcheckout-ma&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_failure'cherry-pick patch from after text=auto was added''
@@ -187,7 +194,7 @@ test_expect_failure 'cherry-pick patch from after text=auto was added' 'gitreset--hardb&&test_must_failgitcherry-picka>err2>&1&&grep"[Nn]othing added"err&&-test_cmpexpectedfile+compare_filesexpectedfile' test_expect_success'Test delete/normalize conflict''
From: Torsten Bögershausen <redacted>
When statistics are done for the autocrlf handling, the search in
the content can be stopped, if e.g
- a search for binary is done, and a NUL character is found
- a search for CRLF is done, and the first CRLF is found.
Similar when statistics for binary vs non-binary are gathered:
Whenever a lone CR or NUL is found, the search can be aborted.
When checking out files in "auto" mode, any file that has a "lone CR"
or a CRLF will not be converted, so the search can be aborted early.
Add the new bit, CONVERT_STAT_BITS_ANY_CR,
which is set for either lone CR or CRLF.
Many binary files have a NUL very early (within the first few bytes,
latest within the first 1..2K).
It is often not necessary to load the whole content of a file or blob
into memory.
Use a streaming handling for blobs and files in the worktree.
Signed-off-by: Torsten Bögershausen <redacted>
---
convert.c | 159 ++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 103 insertions(+), 56 deletions(-)
@@ -13,10 +14,10 @@*translationwhenthe"text"attributeor"auto_crlf"optionisset.*/-/* Stat bits: When BIN is set, the txt bits are unset */#define CONVERT_STAT_BITS_TXT_LF 0x1#define CONVERT_STAT_BITS_TXT_CRLF 0x2#define CONVERT_STAT_BITS_BIN 0x4+#define CONVERT_STAT_BITS_ANY_CR 0x8enumcrlf_action{CRLF_UNDEFINED,
@@ -31,30 +32,36 @@ enum crlf_action {structtext_stat{/* NUL, CR, LF and CRLF counts */-unsignednul,lonecr,lonelf,crlf;+unsignedstat_bits,lonecr,lonelf,crlf;/* These are just approximations! */unsignedprintable,nonprintable;};-staticvoidgather_stats(constchar*buf,unsignedlongsize,structtext_stat*stats)+staticvoiddo_gather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout){unsignedlongi;-memset(stats,0,sizeof(*stats));-+if(!buf||!size)+return;for(i=0;i<size;i++){unsignedcharc=buf[i];if(c=='\r'){+stats->stat_bits|=CONVERT_STAT_BITS_ANY_CR;if(i+1<size&&buf[i+1]=='\n'){stats->crlf++;i++;-}else+stats->stat_bits|=CONVERT_STAT_BITS_TXT_CRLF;+}else{stats->lonecr++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}continue;}if(c=='\n'){stats->lonelf++;+stats->stat_bits|=CONVERT_STAT_BITS_TXT_LF;continue;}if(c==127)
@@ -67,7 +74,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats->printable++;break;case0:-stats->nul++;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;/* fall through */default:stats->nonprintable++;
@@ -75,6 +82,8 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *}elsestats->printable++;+if(stats->stat_bits&earlyout)+break;/* We found what we have been searching for */}/* If file ends with EOF then don't count this EOF as non-printable. */
@@ -86,41 +95,62 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat **Thesameheuristicsasdiff.c::mmfile_is_binary()*WetreatfileswithbareCRasbinary*/-staticintconvert_is_binary(unsignedlongsize,conststructtext_stat*stats)+staticvoidconvert_nonprintable(structtext_stat*stats){-if(stats->lonecr)-return1;-if(stats->nul)-return1;if((stats->printable>>7)<stats->nonprintable)-return1;-return0;+stats->stat_bits|=CONVERT_STAT_BITS_BIN;+}++staticvoidgather_stats(constchar*buf,unsignedlongsize,+structtext_stat*stats,unsignedearlyout)+{+memset(stats,0,sizeof(*stats));+do_gather_stats(buf,size,stats,earlyout);+convert_nonprintable(stats);}-staticunsignedintgather_convert_stats(constchar*data,unsignedlongsize)++staticunsignedget_convert_stats_sha1(unsignedconstchar*sha1,+unsignedearlyout){+structgit_istream*st;structtext_statstats;-intret=0;-if(!data||!size)-return0;-gather_stats(data,size,&stats);-if(convert_is_binary(size,&stats))-ret|=CONVERT_STAT_BITS_BIN;-if(stats.crlf)-ret|=CONVERT_STAT_BITS_TXT_CRLF;-if(stats.lonelf)-ret|=CONVERT_STAT_BITS_TXT_LF;+enumobject_typetype;+unsignedlongsz;-returnret;+if(!sha1)+return0;+memset(&stats,0,sizeof(stats));+st=open_istream(sha1,&type,&sz,NULL);+if(!st){+return0;+}+if(type!=OBJ_BLOB)+gotoclose_and_exit_i;+for(;;){+charbuf[1024];+ssize_treadlen=read_istream(st,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close_and_exit_i:+close_istream(st);+convert_nonprintable(&stats);+returnstats.stat_bits;}-staticconstchar*gather_convert_stats_ascii(constchar*data,unsignedlongsize)+staticconstchar*convert_stats_ascii(unsignedconvert_stats){-unsignedintconvert_stats=gather_convert_stats(data,size);-+unsignedmask=CONVERT_STAT_BITS_TXT_LF|+CONVERT_STAT_BITS_TXT_CRLF;if(convert_stats&CONVERT_STAT_BITS_BIN)return"-text";-switch(convert_stats){+switch(convert_stats&mask){caseCONVERT_STAT_BITS_TXT_LF:return"lf";caseCONVERT_STAT_BITS_TXT_CRLF:
@@ -132,24 +162,45 @@ static const char *gather_convert_stats_ascii(const char *data, unsigned long si}}+staticunsignedget_convert_stats_wt(constchar*path)+{+structtext_statstats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+intfd;+memset(&stats,0,sizeof(stats));+fd=open(path,O_RDONLY);+if(fd<0)+return0;+for(;;){+charbuf[1024];+ssize_treadlen=read(fd,buf,sizeof(buf));+if(readlen<0)+break;+if(!readlen)+break;+do_gather_stats(buf,(unsignedlong)readlen,&stats,earlyout);+if(stats.stat_bits&earlyout)+break;/* We found what we have been searching for */+}+close(fd);+convert_nonprintable(&stats);+returnstats.stat_bits;+}+constchar*get_cached_convert_stats_ascii(constchar*path){-constchar*ret;-unsignedlongsz;-void*data=read_blob_data_from_cache(path,&sz);-ret=gather_convert_stats_ascii(data,sz);-free(data);-returnret;+unsignedconvert_stats;+unsignedearlyout=CONVERT_STAT_BITS_BIN;+convert_stats=get_convert_stats_sha1(get_sha1_from_cache(path),+earlyout);+returnconvert_stats_ascii(convert_stats);}constchar*get_wt_convert_stats_ascii(constchar*path){-constchar*ret="";-structstrbufsb=STRBUF_INIT;-if(strbuf_read_file(&sb,path,0)>=0)-ret=gather_convert_stats_ascii(sb.buf,sb.len);-strbuf_release(&sb);-returnret;+unsignedconvert_stats;+convert_stats=get_convert_stats_wt(path);+returnconvert_stats_ascii(convert_stats);}staticinttext_eol_is_crlf(void)
RFH, the normalization as descrived in Documentation/gitattributes.txt
does not work anymore:
From a clean working directory:
-------------------------------------------------
$ echo "* text=auto" >.gitattributes
$ rm .git/index # Remove the index to force Git to
$ git reset # re-scan the working directory
$ git status # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"
-------------------------------------------------
I have different ideas, how a a normalizatio can be done:
A)
-------------------------------------------------
$ echo "* text=auto" >.gitattributes
$ rm .git/index
$ git add .
$ git status # Show files that will be normalized
$ git commit -m "Introduce end-of-line normalization"
-------------------------------------------------
B)
$ echo "* text=auto" >.gitattributes &&
$ git add .gitattributes &&
$ git ls-files --eol | egrep '^i/(crlf|mixed).*attr/(text|auto)' | ( TAB=$(printf "\t") ; sed -e "s/.*$TAB/dos2unix /" ) >/tmp/$$ &&
$ /bin/sh /tmp/$$ &&
$ rm -f /tmp/$$ &&
$ git add -u &&
$ git commit -m "Introduce end-of-line normalization"
C)
Teach "git add" to learn --renormalize and then
-------------------------------------------------
$ echo "* text=auto" >.gitattributes
$ git add -u --renormalize
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"
-------------------------------------------------
(None of them is really tested)
A) may loose the execute bit
B) dos2unix is not installed everywhere (like Mac OS)
C) seems to most attractive, but I couldn't find out how to forward
options from "git add" into convert.c
Any help is appreciated.
From: Torsten Bögershausen <redacted>
Sincec commit 6523728499e7 'convert: unify the "auto" handling of CRLF'
the normalization instruction in Documentation/gitattributes.txt
doesn't work any more.
Update the documentation and add a test case.
Reported by Kristian Adrup
https://github.com/git-for-windows/git/issues/954
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/gitattributes.txt | 7 +++----
t/t0025-crlf-auto.sh | 29 +++++++++++++++++++++++++++++
2 files changed, 32 insertions(+), 4 deletions(-)
@@ -227,11 +227,10 @@ From a clean working directory: ------------------------------------------------- $ echo "* text=auto" >.gitattributes-$ rm .git/index # Remove the index to force Git to-$ git reset # re-scan the working directory+$ git ls-files --eol | egrep "i/(crlf|mixed)" # find not normalized files+$ rm .git/index # Remove the index to re-scan the working directory+$ git add . $ git status # Show files that will be normalized-$ git add -u-$ git add .gitattributes $ git commit -m "Introduce end-of-line normalization" -------------------------------------------------
From: Torsten Bögershausen <redacted>
The instructions how to normalize the line endings should have been updated
as part of commit 6523728499e 'convert: unify the "auto" handling of CRLF',
(but that part never made it into the commit).
Update the documentation in Documentation/gitattributes.txt
and add a test case in t0025.
Reported by Kristian Adrup
https://github.com/git-for-windows/git/issues/954
Signed-off-by: Torsten Bögershausen <redacted>
---
Documentation/gitattributes.txt | 6 ++----
t/t0025-crlf-auto.sh | 26 ++++++++++++++++++++++++++
2 files changed, 28 insertions(+), 4 deletions(-)
@@ -227,11 +227,9 @@ From a clean working directory: ------------------------------------------------- $ echo "* text=auto" >.gitattributes-$ rm .git/index # Remove the index to force Git to-$ git reset # re-scan the working directory+$ rm .git/index # Remove the index to re-scan the working directory+$ git add . $ git status # Show files that will be normalized-$ git add -u-$ git add .gitattributes $ git commit -m "Introduce end-of-line normalization" -------------------------------------------------