Deep down wildmatch() sees "**" as "*" that can also match slashes. On the surface, it may be confusing to users as the above pattern can match "abcdef", "abcxyzdef", "abc/def", "abc/x/def", "abc/x/y/def"... For now we just forbid it. Users can only do "**/def", "abc/**" or "abc/**/def". The syntax may be re-enabled in future. There's a minor problem with this particular approach. "**" inside square brackets are mistaken as the wildcard while they are not. Git shows a confusing message when users do that. Note that this patch hides a potential problem that if "abc**def" is ever supported, EXC_FLAG_NODIR flag should be turned off or only the base name is matched against the pattern, which makes no sense. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- Documentation/gitignore.txt | 6 ++++-- dir.c | 12 +++++++++--- t/t0003-attributes.sh | 5 +++++ t/t3001-ls-files-others-exclude.sh | 5 +++++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt index eb81d31..ad9fc2f 100644 --- a/Documentation/gitignore.txt +++ b/Documentation/gitignore.txt @@ -94,8 +94,10 @@ PATTERN FORMAT "Documentation/git.html" but not "Documentation/ppc/ppc.html" or "tools/perf/Documentation/perf.html". + -Contrary to fnmatch(3), git matches "**" to anything including -slashes, similar to rsync(1). +In addition to fnmatch(3) syntax, "**" can be used to match one or +more directories. For example, "abc/**/def" matches "abc/x/def", +"abc/x/y/def", "abc/x/y/z/def" and so on. "**" must be wrapped by +slashes. - A leading slash matches the beginning of the pathname. For example, "/{asterisk}.c" matches "cat-file.c" but not diff --git a/dir.c b/dir.c index cb78273..f30117f 100644 --- a/dir.c +++ b/dir.c @@ -327,12 +327,18 @@ void parse_exclude_pattern(const char **pattern, len--; *flags |= EXC_FLAG_MUSTBEDIR; } + *flags |= EXC_FLAG_NODIR; for (i = 0; i < len; i++) { if (p[i] == '/') - break; + *flags &= ~EXC_FLAG_NODIR; + if ((p[i] == '*' && p[i + 1] == '*' && + (i == 0 || p[i - 1] != '\\')) && + !((i == 0 || p[i - 1] == '/') && + (p[i + 2] == '\0' || + p[i + 2] == '/' || + (p[i + 2] == '\\' && p[i + 3] == '/')))) + die(_("** in .gitignore or .gitattributes must be wrapped by slashes")); } - if (i == len) - *flags |= EXC_FLAG_NODIR; *nowildcardlen = simple_length(p); /* * we should have excluded the trailing slash from 'p' too, diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh index 6c3c554..ddeb321 100755 --- a/t/t0003-attributes.sh +++ b/t/t0003-attributes.sh @@ -249,4 +249,9 @@ EOF test_line_count = 0 err ' +test_expect_success '"**" with no slashes test' ' + echo "a**f foo=bar" >.gitattributes && + test_must_fail git check-attr foo -- "f" +' + test_done diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index 67c8bcf..f5c62d0 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -225,4 +225,9 @@ EOF test_cmp expect actual ' + +test_expect_success 'ls-files with "**" patterns and no slashes' ' + test_must_fail git ls-files -o -i --exclude "one**a.1" +' + test_done -- 1.7.12.1.405.gb727dc9 -- 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