git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: durham@fb.com, mitrandir@fb.com,
	"Junio C Hamano" <gitster@pobox.com>,
	"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 1/2] dir.c: fix bug in 'nd/exclusion-regression-fix' topic
Date: Thu, 17 Mar 2016 19:45:42 +0700	[thread overview]
Message-ID: <1458218744-15810-2-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1458218744-15810-1-git-send-email-pclouds@gmail.com>

The topic in question introduces "sticky" path list for this purpose:
given a path 'abc/def', if 'abc' already matches a pattern X, it's added
to X's sticky path list. When we need to check if 'abc/def' matches
pattern X and see that 'abc' is already in the list, we conclude right
away that 'abc/def' also matches X.

The short reason for sticky path list is to workaround limitations of
matching code (*) that will return "not match" when we compare 'abc/def'
and pattern X.

The bug is in this code. Not only it does "when we need to check if
'abc/def' matches...", it does an extra thing: if 'foo/bar' is _not_ in
the list, return 'not matched' by bypassing all matching code with the
"continue;" statement. It should let the remaining code decide match
status instead.

This bug affects both .gitignore and sparse checkout, but it's reported
as a sparse checkout bug, so let's examine how it happens. The
sparse-checkout pattern has two rules

    /*
    !one/hideme

and the worktree has three tracked files, one/hideme, one/showme and
two/showme. What happens is this

* check "one", it matches the first pattern -> positive -> keep
  examining.

*1* "thanks" to 'nd/exclusion-regression-fix' we detect this pair of
  patterns, so we put "one" in the sticky list of pattern "/*"

* enter "one", check "one/hideme", it matches the second pattern
  first (we search from bottom up) -> negative -> excluded

* check "one/showme", it does not match the second pattern.

*2* We then check it against the first pattern and notice the sticky list
  that includes "one", so we decide right away that "one/showme" is
  included.

* leave "one", check "two" which does not match the second pattern.

*3* then we check "two" against the first pattern and notice that this
   pattern has a non-empty sticky list, which contains "one", not "two".
   This bug kicks in and bypasses the true matching logic for pattern
   "/*". As a result, we exclude "two/showme".

One may notice that the order of these steps matter. If *3* occurs
before *1*, then the sticky list at that moment is empty and the bug
does not kick in. Sparse checkout always examines entries in
alphabetical order, so "abc/showme" would be examined before "one" and
not hit this bug!

The last remark is important when we move to .gitignore. We receive the
list of entries with readdir() and cannot control the order of
entries. Which means we can't write a test for .gitignore that will
reliably fail without this fix. Which is why this patch only adds a test
for sparse checkout, even though the same above steps happen to
.gitignore.

(*) which will be fixed later and described in detail then. For this
commit, it's sufficient to see the following link because the
explanation is long:

http://article.gmane.org/gmane.comp.version-control.git/288479

Reported-by: Durham Goode <durham@fb.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 dir.c                                |  1 -
 t/t1011-read-tree-sparse-checkout.sh | 20 ++++++++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/dir.c b/dir.c
index 69e0be6..77f38a5 100644
--- a/dir.c
+++ b/dir.c
@@ -1027,7 +1027,6 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
 				exc = x;
 				break;
 			}
-			continue;
 		}
 
 		if (x->flags & EXC_FLAG_MUSTBEDIR) {
diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index 0c74bee..ecc5e93 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -274,4 +274,24 @@ test_expect_success 'checkout with --ignore-skip-worktree-bits' '
 	git diff --exit-code HEAD
 '
 
+test_expect_success 'sparse checkout and dir.c sticky bits' '
+	git init sticky &&
+	(
+		cd sticky &&
+		mkdir one two &&
+		touch one/hideme one/showme two/showme &&
+		git add . &&
+		git commit -m initial &&
+		cat >.git/info/sparse-checkout <<-\EOF &&
+		/*
+		!one/hideme
+		EOF
+		git config core.sparsecheckout true &&
+		git checkout &&
+		test_path_is_missing one/hideme &&
+		test_path_is_file    one/showme &&
+		test_path_is_file    two/showme
+	)
+'
+
 test_done
-- 
2.8.0.rc0.210.gd302cd2

  reply	other threads:[~2016-03-17 12:47 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-03-17  0:09 bug: sparse config interpretation incorrectness in 2.8.0-rc2 Durham Goode
2016-03-17  0:56 ` Duy Nguyen
2016-03-17  6:49   ` Durham Goode
2016-03-17  7:51   ` Junio C Hamano
2016-03-17 10:17     ` Duy Nguyen
2016-03-17 13:04       ` Johannes Schindelin
2016-03-17 13:20         ` Duy Nguyen
2016-03-17 13:46           ` Johannes Schindelin
2016-03-17 14:00             ` Duy Nguyen
2016-03-18 15:49               ` Johannes Schindelin
2016-03-17  7:22 ` Junio C Hamano
2016-03-17 17:51   ` Durham Goode
2016-03-17 12:45 ` [PATCH 1/2] dir.c: fix bug in 'nd/exclusion-regression-fix' topic Nguyễn Thái Ngọc Duy
2016-03-17 12:45   ` Nguyễn Thái Ngọc Duy [this message]
2016-03-17 12:54     ` [PATCH 3/2] dir.c: fix dir re-inclusion rules with "NODIR" and "MUSTBEDIR" Nguyễn Thái Ngọc Duy
2016-03-17 23:49       ` Junio C Hamano
2016-03-18  0:15         ` Duy Nguyen
2016-03-18  5:40           ` Junio C Hamano
2016-03-18  5:51             ` Duy Nguyen
2016-03-18  5:58             ` Eric Sunshine
2016-03-18  4:51         ` Durham Goode
2016-03-18  5:40           ` Duy Nguyen
2016-03-18  6:21             ` Durham Goode
2016-03-18  6:28               ` Duy Nguyen
2016-03-18 18:00             ` Junio C Hamano
2016-03-18 18:37               ` Extending this cycle by a week and reverting !reinclusion topic Junio C Hamano
2016-03-19  1:03               ` [PATCH 3/2] dir.c: fix dir re-inclusion rules with "NODIR" and "MUSTBEDIR" Duy Nguyen
2016-03-17 12:45   ` [PATCH 2/2] dir.c: correct "stuck" logging logic Nguyễn Thái Ngọc Duy
2016-03-17 12:45   ` Nguyễn Thái Ngọc Duy
2016-03-18 17:38   ` [PATCH 1/2] dir.c: fix bug in 'nd/exclusion-regression-fix' topic Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1458218744-15810-2-git-send-email-pclouds@gmail.com \
    --to=pclouds@gmail.com \
    --cc=durham@fb.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=mitrandir@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).