dir: also check directories for matching pathspecs

Even if a directory doesn't match a pathspec, it is possible, depending on the precise pathspecs, that some file underneath it might. So we special case and recurse into the directory for such situations. However, we previously always added any untracked directory that we recursed into to the list of untracked paths, regardless of whether the directory itself matched the pathspec. For the case of git-clean and a set of pathspecs of "dir/file" and "more", this caused a problem because we'd end up with dir entries for both of "dir" "dir/file" Then correct_untracked_entries() would try to helpfully prune duplicates for us by removing "dir/file" since it's under "dir", leaving us with "dir" Since the original pathspec only had "dir/file", the only entry left doesn't match and leaves nothing to be removed. (Note that if only one pathspec was specified, e.g. only "dir/file", then the common_prefix_len optimizations in fill_directory would cause us to bypass this problem, making it appear in simple tests that we could correctly remove manually specified pathspecs.) Fix this by actually checking whether the directory we are about to add to the list of dir entries actually matches the pathspec; only do this matching check after we have already returned from recursing into the directory. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Sep 17, 2019 at 09:34 UTC 404ebceda01c5af68926c3ee78934cd95bda2602
2 files changed +7 -2
dir.c
+5
@@ -1951,6 +1951,11 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
1951 check_only, stop_at_first_file, pathspec);
1952 if (subdir_state > dir_state)
1953 dir_state = subdir_state;
1954 +
1955 + if (!match_pathspec(istate, pathspec, path.buf, path.len,
1956 + 0 /* prefix */, NULL,
1957 + 0 /* do NOT special case dirs */))
1958 + state = path_none;
1959 }
1960
1961 if (check_only) {
t/t7300-clean.sh
+2 -2
@@ -699,7 +699,7 @@ test_expect_failure 'git clean handles being told what to clean' '
699 test_path_is_missing d2/ut
700 '
701
702 -test_expect_failure 'git clean handles being told what to clean, with -d' '
702 +test_expect_success 'git clean handles being told what to clean, with -d' '
703 mkdir -p d1 d2 &&
704 touch d1/ut d2/ut &&
705 git clean -ffd */ut &&
@@ -715,7 +715,7 @@ test_expect_failure 'git clean works if a glob is passed without -d' '
715 test_path_is_missing d2/ut
716 '
717
718 -test_expect_failure 'git clean works if a glob is passed with -d' '
718 +test_expect_success 'git clean works if a glob is passed with -d' '
719 mkdir -p d1 d2 &&
720 touch d1/ut d2/ut &&
721 git clean -ffd "*ut" &&