Revert "dir.c: don't exclude whole dir prematurely if neg pattern may match"
This reverts commit 57534ee77d22e725d971ee89c77dc6aad61c573f. The feature added in that commit requires that patterns behave the same way from anywhere. But some patterns can behave differently depending on current "working" directory. The conditions to catch and avoid these patterns are too loose. The untracked listing[1] and sparse-checkout selection[2] can become incorrect as a result. [1] http://article.gmane.org/gmane.comp.version-control.git/283520 [2] http://article.gmane.org/gmane.comp.version-control.git/283532 Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Jan 8, 2016 at 19:05 UTC
8c722360d1277259d4baec951e1488086f775214
3 files changed
+5
-117
Documentation/gitignore.txt
+4
-19
@@ -82,12 +82,12 @@ PATTERN FORMAT
82
83
- An optional prefix "`!`" which negates the pattern; any
84
matching file excluded by a previous pattern will become
85
- included again.
85
+ included again. It is not possible to re-include a file if a parent
86
+ directory of that file is excluded. Git doesn't list excluded
87
+ directories for performance reasons, so any patterns on contained
88
+ files have no effect, no matter where they are defined.
89
Put a backslash ("`\`") in front of the first "`!`" for patterns
90
that begin with a literal "`!`", for example, "`\!important!.txt`".
88
- It is possible to re-include a file if a parent directory of that
89
- file is excluded if certain conditions are met. See section NOTES
90
- for detail.
91
92
- If the pattern ends with a slash, it is removed for the
93
purpose of the following description, but it would only find
@@ -141,21 +141,6 @@ not tracked by Git remain untracked.
141
To stop tracking a file that is currently tracked, use
142
'git rm --cached'.
143
144
-To re-include files or directories when their parent directory is
145
-excluded, the following conditions must be met:
146
-
147
- - The rules to exclude a directory and re-include a subset back must
148
- be in the same .gitignore file.
149
-
150
- - The directory part in the re-include rules must be literal (i.e. no
151
- wildcards)
152
-
153
- - The rules to exclude the parent directory must not end with a
154
- trailing slash.
155
-
156
- - The rules to exclude the parent directory must have at least one
157
- slash.
158
-
144
EXAMPLES
145
--------
146
dir.c
+1
-73
@@ -733,25 +733,6 @@ int match_pathname(const char *pathname, int pathlen,
733
*/
734
if (!patternlen && !namelen)
735
return 1;
736
- /*
737
- * This can happen when we ignore some exclude rules
738
- * on directories in other to see if negative rules
739
- * may match. E.g.
740
- *
741
- * /abc
742
- * !/abc/def/ghi
743
- *
744
- * The pattern of interest is "/abc". On the first
745
- * try, we should match path "abc" with this pattern
746
- * in the "if" statement right above, but the caller
747
- * ignores it.
748
- *
749
- * On the second try with paths within "abc",
750
- * e.g. "abc/xyz", we come here and try to match it
751
- * with "/abc".
752
- */
753
- if (!patternlen && namelen && *name == '/')
754
- return 1;
736
}
737
738
return fnmatch_icase_mem(pattern, patternlen,
@@ -759,48 +740,6 @@ int match_pathname(const char *pathname, int pathlen,
740
WM_PATHNAME) == 0;
741
}
742
762
-/*
763
- * Return non-zero if pathname is a directory and an ancestor of the
764
- * literal path in a (negative) pattern. This is used to keep
765
- * descending in "foo" and "foo/bar" when the pattern is
766
- * "!foo/bar/.gitignore". "foo/notbar" will not be descended however.
767
- */
768
-static int match_neg_path(const char *pathname, int pathlen, int *dtype,
769
- const char *base, int baselen,
770
- const char *pattern, int prefix, int patternlen,
771
- int flags)
772
-{
773
- assert((flags & EXC_FLAG_NEGATIVE) && !(flags & EXC_FLAG_NODIR));
774
-
775
- if (*dtype == DT_UNKNOWN)
776
- *dtype = get_dtype(NULL, pathname, pathlen);
777
- if (*dtype != DT_DIR)
778
- return 0;
779
-
780
- if (*pattern == '/') {
781
- pattern++;
782
- patternlen--;
783
- prefix--;
784
- }
785
-
786
- if (baselen) {
787
- if (((pathlen < baselen && base[pathlen] == '/') ||
788
- pathlen == baselen) &&
789
- !strncmp_icase(pathname, base, pathlen))
790
- return 1;
791
- pathname += baselen + 1;
792
- pathlen -= baselen + 1;
793
- }
794
-
795
-
796
- if (prefix &&
797
- ((pathlen < prefix && pattern[pathlen] == '/') &&
798
- !strncmp_icase(pathname, pattern, pathlen)))
799
- return 1;
800
-
801
- return 0;
802
-}
803
-
743
/*
744
* Scan the given exclude list in reverse to see whether pathname
745
* should be ignored. The first match (i.e. the last on the list), if
@@ -814,7 +753,7 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
753
struct exclude_list *el)
754
{
755
struct exclude *exc = NULL; /* undecided */
817
- int i, matched_negative_path = 0;
756
+ int i;
757
758
if (!el->nr)
759
return NULL; /* undefined */
@@ -849,18 +788,7 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
788
exc = x;
789
break;
790
}
852
-
853
- if ((x->flags & EXC_FLAG_NEGATIVE) && !matched_negative_path &&
854
- match_neg_path(pathname, pathlen, dtype, x->base,
855
- x->baselen ? x->baselen - 1 : 0,
856
- exclude, prefix, x->patternlen, x->flags))
857
- matched_negative_path = 1;
791
}
859
- if (exc &&
860
- !(exc->flags & EXC_FLAG_NEGATIVE) &&
861
- !(exc->flags & EXC_FLAG_NODIR) &&
862
- matched_negative_path)
863
- exc = NULL;
792
return exc;
793
}
794
t/t3001-ls-files-others-exclude.sh
-25
@@ -305,29 +305,4 @@ test_expect_success 'ls-files with "**" patterns and no slashes' '
305
test_cmp expect actual
306
'
307
308
-test_expect_success 'negative patterns' '
309
- git init reinclude &&
310
- (
311
- cd reinclude &&
312
- cat >.gitignore <<-\EOF &&
313
- /fooo
314
- /foo
315
- !foo/bar/bar
316
- EOF
317
- mkdir fooo &&
318
- cat >fooo/.gitignore <<-\EOF &&
319
- !/*
320
- EOF
321
- mkdir -p foo/bar &&
322
- touch abc foo/def foo/bar/ghi foo/bar/bar &&
323
- git ls-files -o --exclude-standard >../actual &&
324
- cat >../expected <<-\EOF &&
325
- .gitignore
326
- abc
327
- foo/bar/bar
328
- EOF
329
- test_cmp ../expected ../actual
330
- )
331
-'
332
-
308
test_done