Merge branch 'en/do-match-pathspec-fix'

Use of negative pathspec, while collecting paths including
untracked ones in the working tree, was broken.

* en/do-match-pathspec-fix:
  dir: fix treatment of negated pathspecs
This commit is contained in:
Junio C Hamano 2020-06-17 21:54:03 -07:00
commit 64efa11e6b
2 changed files with 66 additions and 17 deletions

50
dir.c
View file

@ -364,7 +364,8 @@ static int match_pathspec_item(const struct index_state *istate,
return MATCHED_FNMATCH;
/* Perform checks to see if "name" is a leading string of the pathspec */
if (flags & DO_MATCH_LEADING_PATHSPEC) {
if ( (flags & DO_MATCH_LEADING_PATHSPEC) &&
!(flags & DO_MATCH_EXCLUDE)) {
/* name is a literal prefix of the pathspec */
int offset = name[namelen-1] == '/' ? 1 : 0;
if ((namelen < matchlen) &&
@ -401,6 +402,10 @@ static int match_pathspec_item(const struct index_state *istate,
}
/*
* do_match_pathspec() is meant to ONLY be called by
* match_pathspec_with_flags(); calling it directly risks pathspecs
* like ':!unwanted_path' being ignored.
*
* Given a name and a list of pathspecs, returns the nature of the
* closest (i.e. most specific) match of the name to any of the
* pathspecs.
@ -486,13 +491,12 @@ static int do_match_pathspec(const struct index_state *istate,
return retval;
}
int match_pathspec(const struct index_state *istate,
const struct pathspec *ps,
const char *name, int namelen,
int prefix, char *seen, int is_dir)
static int match_pathspec_with_flags(const struct index_state *istate,
const struct pathspec *ps,
const char *name, int namelen,
int prefix, char *seen, unsigned flags)
{
int positive, negative;
unsigned flags = is_dir ? DO_MATCH_DIRECTORY : 0;
positive = do_match_pathspec(istate, ps, name, namelen,
prefix, seen, flags);
if (!(ps->magic & PATHSPEC_EXCLUDE) || !positive)
@ -503,6 +507,16 @@ int match_pathspec(const struct index_state *istate,
return negative ? 0 : positive;
}
int match_pathspec(const struct index_state *istate,
const struct pathspec *ps,
const char *name, int namelen,
int prefix, char *seen, int is_dir)
{
unsigned flags = is_dir ? DO_MATCH_DIRECTORY : 0;
return match_pathspec_with_flags(istate, ps, name, namelen,
prefix, seen, flags);
}
/**
* Check if a submodule is a superset of the pathspec
*/
@ -511,11 +525,11 @@ int submodule_path_match(const struct index_state *istate,
const char *submodule_name,
char *seen)
{
int matched = do_match_pathspec(istate, ps, submodule_name,
strlen(submodule_name),
0, seen,
DO_MATCH_DIRECTORY |
DO_MATCH_LEADING_PATHSPEC);
int matched = match_pathspec_with_flags(istate, ps, submodule_name,
strlen(submodule_name),
0, seen,
DO_MATCH_DIRECTORY |
DO_MATCH_LEADING_PATHSPEC);
return matched;
}
@ -1757,9 +1771,11 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
* for matching patterns.
*/
if (pathspec && !excluded) {
matches_how = do_match_pathspec(istate, pathspec, dirname, len,
0 /* prefix */, NULL /* seen */,
DO_MATCH_LEADING_PATHSPEC);
matches_how = match_pathspec_with_flags(istate, pathspec,
dirname, len,
0 /* prefix */,
NULL /* seen */,
DO_MATCH_LEADING_PATHSPEC);
if (!matches_how)
return path_none;
}
@ -2191,9 +2207,9 @@ static enum path_treatment treat_path(struct dir_struct *dir,
if (excluded)
return path_excluded;
if (pathspec &&
!do_match_pathspec(istate, pathspec, path->buf, path->len,
0 /* prefix */, NULL /* seen */,
0 /* flags */))
!match_pathspec(istate, pathspec, path->buf, path->len,
0 /* prefix */, NULL /* seen */,
0 /* is_dir */))
return path_none;
return path_untracked;
}

View file

@ -211,4 +211,37 @@ test_expect_success 't_e_i() exclude case #8' '
)
'
test_expect_success 'grep --untracked PATTERN' '
# This test is not an actual test of exclude patterns, rather it
# is here solely to ensure that if any tests are inserted, deleted, or
# changed above, that we still have untracked files with the expected
# contents for the NEXT two tests.
cat <<-\EOF >expect-grep &&
actual
expect
sub/actual
sub/expect
EOF
git grep -l --untracked file -- >actual-grep &&
test_cmp expect-grep actual-grep
'
test_expect_success 'grep --untracked PATTERN :(exclude)DIR' '
cat <<-\EOF >expect-grep &&
actual
expect
EOF
git grep -l --untracked file -- ":(exclude)sub" >actual-grep &&
test_cmp expect-grep actual-grep
'
test_expect_success 'grep --untracked PATTERN :(exclude)*FILE' '
cat <<-\EOF >expect-grep &&
actual
sub/actual
EOF
git grep -l --untracked file -- ":(exclude)*expect" >actual-grep &&
test_cmp expect-grep actual-grep
'
test_done