summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dir.c50
-rwxr-xr-xt/t6132-pathspec-exclude.sh33
2 files changed, 66 insertions, 17 deletions
diff --git a/dir.c b/dir.c
index 2de6491040..8e1ac18680 100644
--- a/dir.c
+++ b/dir.c
@@ -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;
}
@@ -1686,9 +1700,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;
}
@@ -2120,9 +2136,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;
}
diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh
index 2462b19ddd..30328b87f0 100755
--- a/t/t6132-pathspec-exclude.sh
+++ b/t/t6132-pathspec-exclude.sh
@@ -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