Skip to content

Commit 64efa11

Browse files
committed
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
2 parents 9906d5f + f1f061e commit 64efa11

File tree

2 files changed

+66
-17
lines changed

2 files changed

+66
-17
lines changed

dir.c

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,8 @@ static int match_pathspec_item(const struct index_state *istate,
364364
return MATCHED_FNMATCH;
365365

366366
/* Perform checks to see if "name" is a leading string of the pathspec */
367-
if (flags & DO_MATCH_LEADING_PATHSPEC) {
367+
if ( (flags & DO_MATCH_LEADING_PATHSPEC) &&
368+
!(flags & DO_MATCH_EXCLUDE)) {
368369
/* name is a literal prefix of the pathspec */
369370
int offset = name[namelen-1] == '/' ? 1 : 0;
370371
if ((namelen < matchlen) &&
@@ -401,6 +402,10 @@ static int match_pathspec_item(const struct index_state *istate,
401402
}
402403

403404
/*
405+
* do_match_pathspec() is meant to ONLY be called by
406+
* match_pathspec_with_flags(); calling it directly risks pathspecs
407+
* like ':!unwanted_path' being ignored.
408+
*
404409
* Given a name and a list of pathspecs, returns the nature of the
405410
* closest (i.e. most specific) match of the name to any of the
406411
* pathspecs.
@@ -486,13 +491,12 @@ static int do_match_pathspec(const struct index_state *istate,
486491
return retval;
487492
}
488493

489-
int match_pathspec(const struct index_state *istate,
490-
const struct pathspec *ps,
491-
const char *name, int namelen,
492-
int prefix, char *seen, int is_dir)
494+
static int match_pathspec_with_flags(const struct index_state *istate,
495+
const struct pathspec *ps,
496+
const char *name, int namelen,
497+
int prefix, char *seen, unsigned flags)
493498
{
494499
int positive, negative;
495-
unsigned flags = is_dir ? DO_MATCH_DIRECTORY : 0;
496500
positive = do_match_pathspec(istate, ps, name, namelen,
497501
prefix, seen, flags);
498502
if (!(ps->magic & PATHSPEC_EXCLUDE) || !positive)
@@ -503,6 +507,16 @@ int match_pathspec(const struct index_state *istate,
503507
return negative ? 0 : positive;
504508
}
505509

510+
int match_pathspec(const struct index_state *istate,
511+
const struct pathspec *ps,
512+
const char *name, int namelen,
513+
int prefix, char *seen, int is_dir)
514+
{
515+
unsigned flags = is_dir ? DO_MATCH_DIRECTORY : 0;
516+
return match_pathspec_with_flags(istate, ps, name, namelen,
517+
prefix, seen, flags);
518+
}
519+
506520
/**
507521
* Check if a submodule is a superset of the pathspec
508522
*/
@@ -511,11 +525,11 @@ int submodule_path_match(const struct index_state *istate,
511525
const char *submodule_name,
512526
char *seen)
513527
{
514-
int matched = do_match_pathspec(istate, ps, submodule_name,
515-
strlen(submodule_name),
516-
0, seen,
517-
DO_MATCH_DIRECTORY |
518-
DO_MATCH_LEADING_PATHSPEC);
528+
int matched = match_pathspec_with_flags(istate, ps, submodule_name,
529+
strlen(submodule_name),
530+
0, seen,
531+
DO_MATCH_DIRECTORY |
532+
DO_MATCH_LEADING_PATHSPEC);
519533
return matched;
520534
}
521535

@@ -1757,9 +1771,11 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
17571771
* for matching patterns.
17581772
*/
17591773
if (pathspec && !excluded) {
1760-
matches_how = do_match_pathspec(istate, pathspec, dirname, len,
1761-
0 /* prefix */, NULL /* seen */,
1762-
DO_MATCH_LEADING_PATHSPEC);
1774+
matches_how = match_pathspec_with_flags(istate, pathspec,
1775+
dirname, len,
1776+
0 /* prefix */,
1777+
NULL /* seen */,
1778+
DO_MATCH_LEADING_PATHSPEC);
17631779
if (!matches_how)
17641780
return path_none;
17651781
}
@@ -2191,9 +2207,9 @@ static enum path_treatment treat_path(struct dir_struct *dir,
21912207
if (excluded)
21922208
return path_excluded;
21932209
if (pathspec &&
2194-
!do_match_pathspec(istate, pathspec, path->buf, path->len,
2195-
0 /* prefix */, NULL /* seen */,
2196-
0 /* flags */))
2210+
!match_pathspec(istate, pathspec, path->buf, path->len,
2211+
0 /* prefix */, NULL /* seen */,
2212+
0 /* is_dir */))
21972213
return path_none;
21982214
return path_untracked;
21992215
}

t/t6132-pathspec-exclude.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,37 @@ test_expect_success 't_e_i() exclude case #8' '
211211
)
212212
'
213213

214+
test_expect_success 'grep --untracked PATTERN' '
215+
# This test is not an actual test of exclude patterns, rather it
216+
# is here solely to ensure that if any tests are inserted, deleted, or
217+
# changed above, that we still have untracked files with the expected
218+
# contents for the NEXT two tests.
219+
cat <<-\EOF >expect-grep &&
220+
actual
221+
expect
222+
sub/actual
223+
sub/expect
224+
EOF
225+
git grep -l --untracked file -- >actual-grep &&
226+
test_cmp expect-grep actual-grep
227+
'
228+
229+
test_expect_success 'grep --untracked PATTERN :(exclude)DIR' '
230+
cat <<-\EOF >expect-grep &&
231+
actual
232+
expect
233+
EOF
234+
git grep -l --untracked file -- ":(exclude)sub" >actual-grep &&
235+
test_cmp expect-grep actual-grep
236+
'
237+
238+
test_expect_success 'grep --untracked PATTERN :(exclude)*FILE' '
239+
cat <<-\EOF >expect-grep &&
240+
actual
241+
sub/actual
242+
EOF
243+
git grep -l --untracked file -- ":(exclude)*expect" >actual-grep &&
244+
test_cmp expect-grep actual-grep
245+
'
246+
214247
test_done

0 commit comments

Comments
 (0)