git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v6b 08/10] convert.c: more safer crlf handling with text attribute

From
tboegi@web.de <tboegi@web.de>
Date
Apr 24, 2016, 15:11 UTC
Message-ID
<1461510689-21161-1-git-send-email-tboegi@web.de>
In-Reply-To
<xmqqegblor2l.fsf@gitster.mtv.corp.google.com>
From: Torsten Bögershausen <tboegi@web.de>

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 <tboegi@web.de>
---
 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(-)
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index d7a124b..836461d 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -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"::
 
diff --git a/convert.c b/convert.c
index 3782172..8d4c42a 100644
--- a/convert.c
+++ b/convert.c
@@ -17,7 +17,8 @@
 #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    0x8
+
+#define CONVERT_STAT_BITS_MIXED (CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF)
 
 enum crlf_action {
 	CRLF_UNDEFINED,
@@ -32,7 +33,7 @@ enum crlf_action {
 
 struct text_stat {
 	/* NUL, CR, LF and CRLF counts */
-	unsigned stat_bits, lonecr, lonelf, crlf;
+	unsigned stat_bits, lonelf;
 
 	/* These are just approximations! */
 	unsigned printable, nonprintable;
@@ -48,13 +49,10 @@ static void do_gather_stats(const char *buf, unsigned long size,
 	for (i = 0; i < size; i++) {
 		unsigned char c = buf[i];
 		if (c == '\r') {
-			stats->stat_bits |= CONVERT_STAT_BITS_ANY_CR;
 			if (i+1 < size && buf[i+1] == '\n') {
-				stats->crlf++;
 				i++;
 				stats->stat_bits |= CONVERT_STAT_BITS_TXT_CRLF;
 			} else {
-				stats->lonecr++;
 				stats->stat_bits |= CONVERT_STAT_BITS_BIN;
 			}
 			continue;
@@ -135,7 +133,7 @@ static unsigned get_convert_stats_sha1(unsigned const char *sha1,
 		if (!readlen)
 			break;
 		do_gather_stats(buf, (unsigned long)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:
@@ -146,11 +144,9 @@ close_and_exit_i:
 
 static const char *convert_stats_ascii(unsigned convert_stats)
 {
-	unsigned mask = CONVERT_STAT_BITS_TXT_LF |
-		CONVERT_STAT_BITS_TXT_CRLF;
 	if (convert_stats & CONVERT_STAT_BITS_BIN)
 		return "-text";
-	switch (convert_stats & mask) {
+	switch (convert_stats) {
 	case CONVERT_STAT_BITS_TXT_LF:
 		return "lf";
 	case CONVERT_STAT_BITS_TXT_CRLF:
@@ -162,7 +158,16 @@ static const char *convert_stats_ascii(unsigned convert_stats)
 	}
 }
 
-static unsigned get_convert_stats_wt(const char *path)
+const char *get_cached_convert_stats_ascii(const char *path)
+{
+	unsigned convert_stats;
+	unsigned earlyout = CONVERT_STAT_BITS_BIN;
+	convert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),
+					       earlyout);
+	return convert_stats_ascii(convert_stats);
+}
+
+const char *get_wt_convert_stats_ascii(const char *path)
 {
 	struct text_stat stats;
 	unsigned earlyout = CONVERT_STAT_BITS_BIN;
@@ -184,23 +189,7 @@ static unsigned get_convert_stats_wt(const char *path)
 	}
 	close(fd);
 	convert_nonprintable(&stats);
-	return stats.stat_bits;
-}
-
-const char *get_cached_convert_stats_ascii(const char *path)
-{
-	unsigned convert_stats;
-	unsigned earlyout = CONVERT_STAT_BITS_BIN;
-	convert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),
-					       earlyout);
-	return convert_stats_ascii(convert_stats);
-}
-
-const char *get_wt_convert_stats_ascii(const char *path)
-{
-	unsigned convert_stats;
-	convert_stats = get_convert_stats_wt(path);
-	return convert_stats_ascii(convert_stats);
+	return convert_stats_ascii(stats.stat_bits);
 }
 
 static int text_eol_is_crlf(void)
@@ -239,43 +228,95 @@ static enum eol output_eol(enum crlf_action crlf_action)
 	return core_eol;
 }
 
+static int would_convert_lf_at_checkout(unsigned convert_stats,
+					size_t len,
+					enum crlf_action crlf_action)
+{
+	if (output_eol(crlf_action) != EOL_CRLF)
+		return 0;
+
+	/* No "naked" LF? Nothing to convert, regardless. */
+	if (!convert_stats & CONVERT_STAT_BITS_TXT_LF)
+		return 0;
+
+	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)
+			return 0;
+	}
+	/* 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)
+		return 0;
+	return 1;
+
+}
+
+static int would_convert_crlf_at_commit(const char * path,
+					const struct text_stat *stats,
+					size_t len,
+					enum crlf_action crlf_action)
+{
+	unsigned stat_bits_index;
+	/* No CRLF? Nothing to convert, regardless. */
+	if (!(stats->stat_bits & CONVERT_STAT_BITS_TXT_CRLF))
+		return 0;
+	/*
+	 * If the file in the index has any CRLF in it, do not convert.
+	 * This is the new safer autocrlf handling.
+	 */
+	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)
+		return 0;
+	return 1;
+}
+
 static void check_safe_crlf(const char *path, enum crlf_action crlf_action,
-                            struct text_stat *stats, enum safe_crlf checksafe)
+			    enum safe_crlf checksafe,
+			    unsigned convert_stats, unsigned new_convert_stats)
 {
+	enum eol new_eol = output_eol(crlf_action);
+	const char *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)) {
 		/*
 		 * CRLFs would not be restored by checkout:
 		 * check if we'd remove CRLFs
 		 */
-		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);
-		}
-	} else if (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)) {
 		/*
 		 * CRLFs would be added by checkout:
 		 * check if we have "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";
+	else if (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);
 	}
-}
-
-static int has_cr_in_index(const char *path)
-{
-	unsigned convert_stats;
-	convert_stats = get_convert_stats_sha1(get_sha1_from_cache(path),
-					       CONVERT_STAT_BITS_ANY_CR);
-	return convert_stats & CONVERT_STAT_BITS_ANY_CR;
 }
 
 static int crlf_to_git(const char *path, const char *src, size_t len,
@@ -284,7 +325,7 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
 {
 	struct text_stat stats;
 	char *dst;
-
+	int convert_crlf;
 	if (crlf_action == CRLF_BINARY ||
 	    (src && !len))
 		return 0;
@@ -296,24 +337,42 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
 	if (!buf && !src)
 		return 1;
 
-	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)
 			return 0;
-		/*
-		 * If the file in the index has any CR in it, do not convert.
-		 * This is the new safer autocrlf handling.
-		 */
-		if (checksafe == SAFE_CRLF_RENORMALIZE)
-			checksafe = SAFE_CRLF_FALSE;
-		else if (has_cr_in_index(path))
-			return 0;
+	} else {
+		gather_stats(src, len, &stats, 0);
+	}
+	if (checksafe == SAFE_CRLF_RENORMALIZE) {
+		convert_crlf = 1;
+		checksafe = SAFE_CRLF_FALSE;
+	} else {
+		convert_crlf = would_convert_crlf_at_commit(path, &stats, len,
+							    crlf_action);
 	}
-	check_safe_crlf(path, crlf_action, &stats, checksafe);
 
-	/* Optimization: No CRLF? Nothing to convert, regardless. */
-	if (!stats.crlf)
+	if (checksafe) {
+		unsigned convert_stats = stats.stat_bits;
+		unsigned new_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)
 		return 0;
 
 	/*
@@ -327,7 +386,9 @@ static int crlf_to_git(const char *path, const char *src, size_t len,
 	if (strbuf_avail(buf) + buf->len < len)
 		strbuf_grow(buf, len - buf->len);
 	dst = buf->buf;
-	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) {
 		/*
 		 * If we guessed, we already know we rejected a file with
 		 * lone CR, and we can strip a CR without looking at what
@@ -354,28 +415,15 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,
 {
 	char *to_free = NULL;
 	struct text_stat stats;
-	unsigned earlyout = CONVERT_STAT_BITS_TXT_CRLF | CONVERT_STAT_BITS_BIN;
-
-
-	if (!len || output_eol(crlf_action) != EOL_CRLF)
+	unsigned earlyout = 0; /* Need to count lonelf */
+	if (!len)
 		return 0;
 
 	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))
 		return 0;
 
-	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 )
-			return 0;
-
-		if (stats.stat_bits & CONVERT_STAT_BITS_BIN)
-			return 0;
-	}
-
 	/* 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)
 struct lf_to_crlf_filter {
 	struct stream_filter filter;
 	unsigned has_held:1;
+	unsigned expanded_loneLF:1;
+	unsigned had_CRLF:1;
 	char held;
 };
 
@@ -1107,7 +1157,12 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,
 			char ch = 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;
 			} else if (was_cr) {
 				/*
 				 * Previous round saw CR and it is not followed
@@ -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) {
+				/*
+				 * Mixed EOL, round trip not possible.
+				 */
+				return 1;
+			}
+
 		}
 
 		*osize_p -= o;
diff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh
index d0bee08..b5f93e2 100755
--- a/t/t0025-crlf-auto.sh
+++ b/t/t0025-crlf-auto.sh
@@ -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 check
 	rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&
@@ -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 added
 	has_cr CRLFonly &&
 	CRLFonlydiff=$(git diff CRLFonly) &&
-	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 .gitattributes tmp LFonly CRLFonly LFwithNUL &&
 	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 added
 	has_cr CRLFonly &&
 	CRLFonlydiff=$(git diff CRLFonly) &&
-	test -n "$CRLFonlydiff"
+	test -z "$CRLFonlydiff"
 '
 
 test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' '
diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index 8367d0b..a16e513 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -71,10 +71,14 @@ check_warning () {
 	case "$1" in
 	LF_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" ; return false ;;
 	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".actual
 	test_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,$2 in
+	case "$1","$2" in
 	-text,*)   echo "-text" ;;
 	text,)     echo "text" ;;
 	text,lf)   echo "text eol=lf" ;;
@@ -349,10 +353,12 @@ then
 	WILC=LF_CRLF
 	WICL=
 	WAMIX=LF_CRLF
+	Pcrlf=
 else
 	WILC=
 	WICL=CRLF_LF
 	WAMIX=CRLF_LF
+	Pcrlf=CRLF
 fi
 
 #                         attr   LF        CRLF      CRLFmixLF LFmixCR   CRLFNUL
@@ -392,31 +398,32 @@ test_expect_success 'commit files attr=crlf' '
 	commit_check_warn input "crlf" "LF_CRLF" ""        "LF_CRLF" "LF_CRLF" ""
 '
 
-#                 attr                    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL
+#                 attr    aeol    ceol    LF        CRLF      CRLFmixLF   LF_mix_CR   CRLFNUL
 commit_chk_wrnNNO ""      ""      false   ""        ""        ""          ""          ""
-commit_chk_wrnNNO ""      ""      true    LF_CRLF   ""        ""          ""          ""
-commit_chk_wrnNNO ""      ""      input   ""        ""        ""          ""          ""
+commit_chk_wrnNNO ""      ""      true    LF_CRLF   ""        mixed       ""          ""
+commit_chk_wrnNNO ""      ""      input   ""        CRLF      mixed       ""          ""
+
+commit_chk_wrnNNO "auto"  ""      false   "$WILC"   "$Pcrlf"  mixed       ""          ""
+commit_chk_wrnNNO "auto"  ""      true    LF_CRLF   ""        mixed       ""          ""
+commit_chk_wrnNNO "auto"  ""      input   ""        CRLF      mixed       ""          ""
+commit_chk_wrnNNO "text"  ""      false   "$WILC"   "$Pcrlf"  mixed       "$WILC"     "$Pcrlf"
+commit_chk_wrnNNO "text"  ""      true    LF_CRLF   ""        mixed       LF_CRLF     ""
+commit_chk_wrnNNO "text"  ""      input   ""        CRLF      mixed       ""          CRLF
+
 
-commit_chk_wrnNNO "auto"  ""      false   "$WILC"   ""        ""          ""          ""
-commit_chk_wrnNNO "auto"  ""      true    LF_CRLF   ""        ""          ""          ""
-commit_chk_wrnNNO "auto"  ""      input   ""        ""        ""          ""          ""
 for crlf in true false input
 do
 	commit_chk_wrnNNO -text ""      $crlf   ""        ""        ""          ""          ""
 	commit_chk_wrnNNO -text lf      $crlf   ""        ""        ""          ""          ""
 	commit_chk_wrnNNO -text crlf    $crlf   ""        ""        ""          ""          ""
-	commit_chk_wrnNNO ""    lf      $crlf   ""       CRLF_LF    CRLF_LF      ""         CRLF_LF
-	commit_chk_wrnNNO ""    crlf    $crlf   LF_CRLF   ""        LF_CRLF     LF_CRLF     ""
-	commit_chk_wrnNNO auto  lf    	$crlf   ""        ""        ""          ""          ""
-	commit_chk_wrnNNO auto  crlf  	$crlf   LF_CRLF   ""        ""          ""          ""
-	commit_chk_wrnNNO text  lf    	$crlf   ""       CRLF_LF    CRLF_LF     ""          CRLF_LF
-	commit_chk_wrnNNO text  crlf  	$crlf   LF_CRLF   ""        LF_CRLF     LF_CRLF     ""
+	commit_chk_wrnNNO ""    lf      $crlf   ""        CRLF      mixed       ""          CRLF
+	commit_chk_wrnNNO ""    crlf    $crlf   LF_CRLF   ""        mixed       LF_CRLF     ""
+	commit_chk_wrnNNO auto  lf      $crlf   ""        CRLF      mixed       ""          ""
+	commit_chk_wrnNNO auto  crlf    $crlf   LF_CRLF   ""        mixed       ""          ""
+	commit_chk_wrnNNO text  lf      $crlf   ""        CRLF      mixed       ""          CRLF
+	commit_chk_wrnNNO text  crlf    $crlf   LF_CRLF   ""        mixed       LF_CRLF     ""
 done
 
-commit_chk_wrnNNO "text"  ""      false   "$WILC"   "$WICL"   "$WAMIX"    "$WILC"     "$WICL"
-commit_chk_wrnNNO "text"  ""      true    LF_CRLF   ""        LF_CRLF     LF_CRLF     ""
-commit_chk_wrnNNO "text"  ""      input   ""        CRLF_LF   CRLF_LF     ""          CRLF_LF
-
 test_expect_success 'create files cleanup' '
 	rm -f *.txt &&
 	git -c core.autocrlf=false reset --hard
@@ -456,9 +463,9 @@ do
 	check_in_repo_NNO auto  ""     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul
 	check_in_repo_NNO auto  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul
 	check_in_repo_NNO auto  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul
-	check_in_repo_NNO text  ""     $crlf   LF  LF    LF           LF_mix_CR  LF_nul
-	check_in_repo_NNO text  lf     $crlf   LF  LF    LF           LF_mix_CR  LF_nul
-	check_in_repo_NNO text  crlf   $crlf   LF  LF    LF           LF_mix_CR  LF_nul
+	check_in_repo_NNO text  ""     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul
+	check_in_repo_NNO text  lf     $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul
+	check_in_repo_NNO text  crlf   $crlf   LF  CRLF  CRLF_mix_LF  LF_mix_CR  CRLF_nul
 done
 ################################################################################
 # Check how files in the repo are changed when they are checked out
@@ -479,12 +486,10 @@ done
 
 if test_have_prereq NATIVE_CRLF
 then
-MIX_CRLF_LF=CRLF
 MIX_LF_CR=CRLF_mix_CR
 NL=CRLF
 LFNUL=CRLF_nul
 else
-MIX_CRLF_LF=CRLF_mix_LF
 MIX_LF_CR=LF_mix_CR
 NL=LF
 LFNUL=LF_nul
@@ -492,8 +497,7 @@ fi
 export CRLF_MIX_LF_CR MIX NL
 
 # Same handling with and without ident
-#for id in "" ident
-for id in ""
+for id in "" ident
 do
 	for ceol in lf crlf native
 	do
@@ -501,38 +505,38 @@ do
 		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"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
-			checkout_files -text "$id" "lf"   "$crlf" "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
-			checkout_files -text "$id" "crlf" "$crlf" "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+			checkout_files "-text" "$id" ""     "$crlf" "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+			checkout_files "-text" "$id" "lf"   "$crlf" "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+			checkout_files "-text" "$id" "crlf" "$crlf" "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
 			# text
-			checkout_files text  "$id" "lf"   "$crlf" "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
-			checkout_files text  "$id" "crlf" "$crlf" "$ceol"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+			checkout_files text    "$id" "lf"   "$crlf" "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+			checkout_files text    "$id" "crlf" "$crlf" "$ceol"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul
 			# currently the same as text, eol=XXX
-			checkout_files auto  "$id" "lf"   "$crlf" "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
-			checkout_files auto  "$id" "crlf" "$crlf" "$ceol"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+			checkout_files auto    "$id" "lf"   "$crlf" "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+			checkout_files auto    "$id" "crlf" "$crlf" "$ceol"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
 		done
 
 		# core.autocrlf false, different core.eol
-		checkout_files   ""    "$id" ""     false   "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+		checkout_files   ""      "$id" ""     false   "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
 		# core.autocrlf true
-		checkout_files   ""    "$id" ""     true    "$ceol"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+		checkout_files   ""      "$id" ""     true    "$ceol"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
 		# text: core.autocrlf = true overrides core.eol
-		checkout_files   auto  "$id" ""     true    "$ceol"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
-		checkout_files   text  "$id" ""     true    "$ceol"  CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+		checkout_files   auto    "$id" ""     true    "$ceol"  CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+		checkout_files   text    "$id" ""     true    "$ceol"  CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul
 		# text: core.autocrlf = input overrides core.eol
-		checkout_files   text  "$id" ""     input   "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
-		checkout_files   auto  "$id" ""     input   "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+		checkout_files   text    "$id" ""     input   "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+		checkout_files   auto    "$id" ""     input   "$ceol"  LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
 		# text=auto + eol=XXX
 	done
 	# text: core.autocrlf=false uses core.eol
-	checkout_files     text  "$id" ""     false   crlf     CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
-	checkout_files     text  "$id" ""     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+	checkout_files     text    "$id" ""     false   crlf     CRLF  CRLF  CRLF_mix_LF  CRLF_mix_CR  CRLF_nul
+	checkout_files     text    "$id" ""     false   lf       LF    CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
 	# text: core.autocrlf=false and core.eol unset(or native) uses native eol
-	checkout_files     text  "$id" ""     false   ""       $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL
-	checkout_files     text  "$id" ""     false   native   $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   $LFNUL
+	checkout_files     text    "$id" ""     false   ""       $NL   CRLF  CRLF_mix_LF  "$MIX_LF_CR" "$LFNUL"
+	checkout_files     text    "$id" ""     false   native   $NL   CRLF  CRLF_mix_LF  "$MIX_LF_CR" "$LFNUL"
 	# auto: core.autocrlf=false and core.eol unset(or native) uses native eol
-	checkout_files     auto  "$id" ""     false   ""       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
-	checkout_files     auto  "$id" ""     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+	checkout_files     auto    "$id" ""     false   ""       $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
+	checkout_files     auto    "$id" ""     false   native   $NL   CRLF  CRLF_mix_LF  LF_mix_CR    LF_nul
 done
 
 # Should be the last test case: remove some files from the worktree
-- 
2.8.0.rc2.2.g1a4d45a.dirty
Previous: tboegi@web.deNext: tboegi@web.de
Message 73 of 126 in “git reset --hard gives clean working tree”
  1. 1/3 git reset --hard gives clean working treetboegi@web.de, Feb 11, 2016
  2. Junio C HamanoFeb 11, 2016
  3. Torsten BögershausenMar 5, 2016
  4. Junio C HamanoMar 5, 2016
  5. Torsten BögershausenMar 5, 2016
  6. Junio C HamanoMar 5, 2016
  7. Junio C HamanoMar 7, 2016
  8. Junio C HamanoMar 7, 2016
  9. Torsten BögershausenMar 7, 2016
  10. Junio C HamanoMar 7, 2016
  11. 1/7 Make it possible to get sha1 for a path from the indextboegi@web.de, Mar 29, 2016
  12. Duy NguyenMar 29, 2016
  13. Duy NguyenMar 29, 2016
  14. Torsten BögershausenMar 29, 2016
  15. Eric SunshineMar 29, 2016
  16. 2/7 convert.c: stream and early outtboegi@web.de, Mar 29, 2016
  17. 3/7 Allow core.autocrlf=input and core.eol=crlftboegi@web.de, Mar 29, 2016
  18. 4/7 t0027: TC for combined attributestboegi@web.de, Mar 29, 2016
  19. 5/7 CRLF: unify the "auto" handlingtboegi@web.de, Mar 29, 2016
  20. Eric SunshineMar 29, 2016
  21. 6/7 correct blame for files commited with CRLFtboegi@web.de, Mar 29, 2016
  22. Junio C HamanoMar 29, 2016
  23. Torsten BögershausenMar 29, 2016
  24. Junio C HamanoMar 29, 2016
  25. Junio C HamanoMar 29, 2016
  26. Junio C HamanoMar 29, 2016
  27. Junio C HamanoMar 29, 2016
  28. Torsten BögershausenMar 30, 2016
  29. 7/7 convert.c: more safer crlf handling with text attributetboegi@web.de, Mar 29, 2016
  30. Junio C HamanoMar 29, 2016
  31. 1/7 Make it possible to get sha1 for a path from the indextboegi@web.de, Apr 1, 2016
  32. 2/7 convert.c: stream and early outtboegi@web.de, Apr 1, 2016
  33. 3/7 Allow core.autocrlf=input and core.eol=crlftboegi@web.de, Apr 1, 2016
  34. Junio C HamanoApr 1, 2016
  35. 4/7 t0027: TC for combined attributestboegi@web.de, Apr 1, 2016
  36. Junio C HamanoApr 1, 2016
  37. 5/7 CRLF: unify the "auto" handlingtboegi@web.de, Apr 1, 2016
  38. Junio C HamanoApr 1, 2016
  39. 6/7 correct blame for files commited with CRLFtboegi@web.de, Apr 1, 2016
  40. Junio C HamanoApr 1, 2016
  41. Torsten BögershausenApr 3, 2016
  42. 7/7 convert.c: more safer crlf handling with text attributetboegi@web.de, Apr 1, 2016
  43. correct blame for files commited with CRLFtboegi@web.de, Apr 5, 2016
  44. Junio C HamanoApr 5, 2016
  45. Junio C HamanoApr 5, 2016
  46. Torsten BögershausenApr 6, 2016
  47. 1/4 t0027: Make more reliabletboegi@web.de, Apr 19, 2016
  48. 2/4 convert: allow core.autocrlf=input and core.eol=crlftboegi@web.de, Apr 19, 2016
  49. 3/4 t0027: test cases for combined attributestboegi@web.de, Apr 19, 2016
  50. Junio C HamanoApr 19, 2016
  51. Torsten BögershausenApr 20, 2016
  52. 4/4 convert.c: ident + core.autocrlf didn't worktboegi@web.de, Apr 19, 2016
  53. Junio C HamanoApr 20, 2016
  54. 01/10 t0027: Make more reliabletboegi@web.de, Apr 22, 2016
  55. Junio C HamanoApr 22, 2016
  56. Torsten BögershausenApr 24, 2016
  57. 02/10 convert: allow core.autocrlf=input and core.eol=crlftboegi@web.de, Apr 22, 2016
  58. 03/10 t0027: test cases for combined attributestboegi@web.de, Apr 22, 2016
  59. 04/10 convert.c: ident + core.autocrlf didn't worktboegi@web.de, Apr 22, 2016
  60. 05/10 read-cache: factor out get_sha1_from_index() helpertboegi@web.de, Apr 22, 2016
  61. 06/10 convert.c: stream and early outtboegi@web.de, Apr 22, 2016
  62. 07/10 convert: unify the "auto" handling of CRLFtboegi@web.de, Apr 22, 2016
  63. 08/10 convert.c: more safer crlf handling with text attributetboegi@web.de, Apr 22, 2016
  64. 09/10 t6038; use crlf on all platformstboegi@web.de, Apr 22, 2016
  65. 10/10 ce_compare_data() did not respect conversiontboegi@web.de, Apr 22, 2016
  66. 01/10 t0027: Make commit_chk_wrnNNO() reliabletboegi@web.de, Apr 24, 2016
  67. 02/10 convert: allow core.autocrlf=input and core.eol=crlftboegi@web.de, Apr 24, 2016
  68. 03/10 t0027: test cases for combined attributestboegi@web.de, Apr 24, 2016
  69. 04/10 convert.c: ident + core.autocrlf didn't worktboegi@web.de, Apr 24, 2016
  70. 05/10 read-cache: factor out get_sha1_from_index() helpertboegi@web.de, Apr 24, 2016
  71. 06/10 convert.c: stream and early outtboegi@web.de, Apr 24, 2016
  72. 07/10 convert: unify the "auto" handling of CRLFtboegi@web.de, Apr 24, 2016
  73. 08/10 convert.c: more safer crlf handling with text attributetboegi@web.de, Apr 24, 2016
  74. 09/10 t6038; use crlf on all platformstboegi@web.de, Apr 24, 2016
  75. 10/10 ce_compare_data() did not respect conversiontboegi@web.de, Apr 24, 2016
  76. 01/10 t0027: Make commit_chk_wrnNNO() reliabletboegi@web.de, Apr 25, 2016
  77. Junio C HamanoApr 25, 2016
  78. 02/10 convert: allow core.autocrlf=input and core.eol=crlftboegi@web.de, Apr 25, 2016
  79. 03/10 t0027: test cases for combined attributestboegi@web.de, Apr 25, 2016
  80. 04/10 convert.c: ident + core.autocrlf didn't worktboegi@web.de, Apr 25, 2016
  81. 05/10 read-cache: factor out get_sha1_from_index() helpertboegi@web.de, Apr 25, 2016
  82. 06/10 convert.c: stream and early outtboegi@web.de, Apr 25, 2016
  83. 07/10 convert: unify the "auto" handling of CRLFtboegi@web.de, Apr 25, 2016
  84. Junio C HamanoApr 25, 2016
  85. Torsten BögershausenApr 26, 2016
  86. Junio C HamanoApr 26, 2016
  87. 08/10 convert.c: more safer crlf handling with text attributetboegi@web.de, Apr 25, 2016
  88. 09/10 t6038; use crlf on all platformstboegi@web.de, Apr 25, 2016
  89. 10/10 ce_compare_data() did not respect conversiontboegi@web.de, Apr 25, 2016
  90. 01/10 t0027: make commit_chk_wrnNNO() reliabletboegi@web.de, Apr 29, 2016
  91. 02/10 convert: allow core.autocrlf=input and core.eol=crlftboegi@web.de, Apr 29, 2016
  92. 03/10 t0027: test cases for combined attributestboegi@web.de, Apr 29, 2016
  93. 04/10 convert.c: ident + core.autocrlf didn't worktboegi@web.de, Apr 29, 2016
  94. 05/10 read-cache: factor out get_sha1_from_index() helpertboegi@web.de, Apr 29, 2016
  95. 06/10 convert.c: stream and early outtboegi@web.de, Apr 29, 2016
  96. 07/10 convert: unify the "auto" handling of CRLFtboegi@web.de, Apr 29, 2016
  97. Torsten BögershausenNov 25, 2016
  98. 1/1 New way to normalize the line endingstboegi@web.de, Nov 27, 2016
  99. Junio C HamanoNov 29, 2016
  100. 1/1 Document how to normalize the line endingstboegi@web.de, Apr 12, 2017
  101. 08/10 convert.c: more safer crlf handling with text attributetboegi@web.de, Apr 29, 2016
  102. 09/10 t6038; use crlf on all platformstboegi@web.de, Apr 29, 2016
  103. 10/10 ce_compare_data() did not respect conversiontboegi@web.de, Apr 29, 2016
  104. Junio C HamanoApr 29, 2016
  105. Junio C HamanoApr 29, 2016
  106. Torsten BögershausenMay 1, 2016
  107. Junio C HamanoMay 2, 2016
  108. Junio C HamanoMay 2, 2016
  109. Torsten BögershausenMay 3, 2016
  110. Junio C HamanoMay 3, 2016
  111. Torsten BögershausenMay 4, 2016
  112. Junio C HamanoMay 4, 2016
  113. Torsten BögershausenMay 6, 2016
  114. Junio C HamanoMay 6, 2016
  115. 0/6 convert-eol-autocrlf, old 5..10 now 1..6tboegi@web.de, May 7, 2016
  116. 1/6 read-cache: factor out get_sha1_from_index() helpertboegi@web.de, May 7, 2016
  117. Junio C HamanoMay 9, 2016
  118. 2/6 convert.c: stream and early outtboegi@web.de, May 7, 2016
  119. Junio C HamanoMay 9, 2016
  120. Torsten BögershausenMay 11, 2016
  121. 3/6 convert: unify the "auto" handling of CRLFtboegi@web.de, May 7, 2016
  122. 4/6 convert.c: more safer crlf handling with text attributetboegi@web.de, May 7, 2016
  123. 5/6 t6038; use crlf on all platformstboegi@web.de, May 7, 2016
  124. 6/6 convert: ce_compare_data() checks for a sha1 of a pathtboegi@web.de, May 7, 2016
  125. 2/3 Factor out convert_cmp_checkout() into convert.ctboegi@web.de, Feb 11, 2016
  126. 3/3 convert.c: Optimize convert_cmp_checkout() for changed file lentboegi@web.de, Feb 11, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.