[PATCH 1/3] git reset --hard gives clean working tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Torsten Bögershausen <tboegi@xxxxxx>

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, and adjust
the test cases in t0025:
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.
Whenever the file is changed in the working tree, a line is added/deleted
or dos2unix is run, it may be normalized at the next commit,
depending on .gitattributes.

This patch is a result of a longer discussion on the mailing list,
how to fix the flaky t0025.

Suggested-by: Junio C Hamano <gitster@xxxxxxxxx>
Signed-off-by: Torsten Bögershausen <tboegi@xxxxxx>
---
This is my attempt to help to fix flaky t0025:
 - steal the code from Junio
 - Add test case, change the existing if needed.
 - Spice with some optimizations
The commit messages may be in the state "improvable".

 read-cache.c         | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 t/t0025-crlf-auto.sh | 57 +++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 109 insertions(+), 6 deletions(-)

diff --git a/read-cache.c b/read-cache.c
index 394ce14..2948b8f 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -156,17 +156,75 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
 		ce_mark_uptodate(ce);
 }
 
+/*
+ * Compare the data in buf with the data in the file pointed by fd and
+ * return 0 if they are identical, and non-zero if they differ.
+ */
+static int compare_with_fd(const char *input, ssize_t len, int fd)
+{
+	for (;;) {
+		char buf[1024 * 16];
+		ssize_t chunk_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;
+	}
+}
+
 static int ce_compare_data(const struct cache_entry *ce, struct stat *st)
 {
 	int match = -1;
 	int fd = open(ce->name, O_RDONLY);
 
+	/*
+	 * Would another "git add" on the path change what is in the
+	 * index for the path?
+	 */
 	if (fd >= 0) {
 		unsigned char sha1[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)
+		return match;
+
+	/*
+	 * Would another "git checkout -f" out of the index change
+	 * what is in the working tree file?
+	 */
+	fd = open(ce->name, O_RDONLY);
+	if (fd >= 0) {
+		enum object_type type;
+		unsigned long size;
+		void *data = read_sha1_file(ce->sha1, &type, &size);
+
+		if (type == OBJ_BLOB) {
+			struct strbuf worktree = STRBUF_INIT;
+			if (convert_to_working_tree(ce->name, data, size,
+																	&worktree)) {
+				free(data);
+				data = strbuf_detach(&worktree, &size);
+			}
+			if (!compare_with_fd(data, size, fd))
+				match = 0;
+		}
+		free(data);
+		close(fd);
+	}
 	return match;
 }
 
diff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh
index c164b46..4a7e5c0 100755
--- a/t/t0025-crlf-auto.sh
+++ b/t/t0025-crlf-auto.sh
@@ -14,6 +14,8 @@ test_expect_success setup '
 
 	for w in Hello world how are you; do echo $w; done >LFonly &&
 	for w in I am very very fine thank you; do echo ${w}Q; done | q_to_cr >CRLFonly &&
+	cp CRLFonly CRLFonly1 &&
+	cp CRLFonly CRLFonly2 &&
 	for w in Oh here is a QNUL byte how alarming; do echo ${w}; done | q_to_nul >LFwithNUL &&
 	git add . &&
 
@@ -23,6 +25,28 @@ test_expect_success setup '
 	CRLFonly=$(git rev-parse HEAD:CRLFonly) &&
 	LFwithNUL=$(git rev-parse HEAD:LFwithNUL) &&
 
+	cp CRLFonly CRLFonly.orig &&
+	for w in I am very very fine thank YOU; do echo ${w}Q; done | q_to_cr >CRLFonly.changed &&
+	cat >expnorm  <<-EOF &&
+		MIQ
+		MamQ
+		MveryQ
+		MveryQ
+		MfineQ
+		MthankQ
+		MyouQ
+		PI
+		Pam
+		Pvery
+		Pvery
+		Pfine
+		Pthank
+		PYOU
+	EOF
+	cat >expunor  <<-EOF &&
+		MyouQ
+		PYOUQ
+	EOF
 	echo happy.
 '
 
@@ -39,7 +63,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 an unchanged CRLF file not to be normalized' '
 
 	# Backwards compatibility check
 	rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&
@@ -49,10 +73,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 an unchanged CRLF file not to be normalized' '
 
 	rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&
 	echo "CRLFonly text" > .gitattributes &&
@@ -61,7 +85,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' '
@@ -114,7 +138,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' '
 	test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff"
 '
 
-test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '
+test_expect_success 'text=auto, autocrlf=true  causes an unchanged CRLF file not to be normalized' '
 
 	rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL &&
 	git config core.autocrlf true &&
@@ -126,7 +150,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' '
 	LFonlydiff=$(git diff LFonly) &&
 	CRLFonlydiff=$(git diff CRLFonly) &&
 	LFwithNULdiff=$(git diff LFwithNUL) &&
-	test -z "$LFonlydiff" -a -n "$CRLFonlydiff" -a -z "$LFwithNULdiff"
+	test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff"
 '
 
 test_expect_success 'text=auto, autocrlf=true does not normalize binary files' '
@@ -152,4 +176,25 @@ test_expect_success 'eol=crlf _does_ normalize binary files' '
 	test -z "$LFwithNULdiff"
 '
 
+test_expect_success 'crlf=true causes a changed CRLF file to be normalized' '
+	git config core.autocrlf false &&
+	echo "CRLFonly1 crlf" > .gitattributes &&
+	# Note, "normalized" means that git will normalize it if added
+	cp CRLFonly.changed CRLFonly1 &&
+	git add CRLFonly1 &&
+	git diff --cached CRLFonly1 |
+	tr "\015" Q | sed -ne "/^[+-][a-zA-Z]/p" | tr "+-" PM >actual1 &&
+	test_cmp expnorm actual1
+'
+
+test_expect_success 'autocrlf=true causes a changed CRLF file not to be normalized' '
+	git config core.autocrlf true &&
+	echo > .gitattributes &&
+	# Note, "normalized" means that git will normalize it if added
+	cp CRLFonly.changed CRLFonly2 &&
+	git add CRLFonly2 &&
+	git diff --cached CRLFonly2 |
+	tr "\015" Q  | sed -ne "/^[+-][a-zA-Z]/p" |	tr "+-" PM >actual2 &&
+	test_cmp expunor actual2
+'
 test_done
-- 
2.7.0.303.g2c4f448.dirty

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]