Merge branch 'rs/dir-skip-nested-repo-fix'

The directory traversal logic has been updated to correctly evaluate
pathspecs for ignored directories containing nested repositories,
and has been fortified to gracefully handle null pathspecs during
checkout operations.

* rs/dir-skip-nested-repo-fix:
  dir: skip excluded directory with nested repo on prefix match
This commit is contained in:
Junio C Hamano committed 2026-10-05 13:52:29 -07:00
commit 053d5d2365
3 files changed
+32 -7

No files matched your search

+20 -7
View File
@@ -1935,6 +1935,16 @@ static enum exist_status directory_exists_in_index(struct index_state *istate,
return index_nonexistent;
}
static int dir_match(struct index_state *istate,
const struct pathspec *pathspec,
const char *dirname, int len)
{
return match_pathspec_with_flags(istate, pathspec, dirname, len,
0 /* prefix */,
NULL /* seen */,
DO_MATCH_LEADING_PATHSPEC);
}
/*
* When we find a directory when traversing the filesystem, we
* have three distinct cases:
@@ -2001,11 +2011,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
* for matching patterns.
*/
if (pathspec && !excluded) {
matches_how = match_pathspec_with_flags(istate, pathspec,
dirname, len,
0 /* prefix */,
NULL /* seen */,
DO_MATCH_LEADING_PATHSPEC);
matches_how = dir_match(istate, pathspec, dirname, len);
if (!matches_how)
return path_none;
}
@@ -2039,8 +2045,15 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
strbuf_release(&sb);
if (nested_repo) {
if ((dir->flags & DIR_SKIP_NESTED_GIT) ||
(matches_how == MATCHED_RECURSIVELY_LEADING_PATHSPEC))
if (dir->flags & DIR_SKIP_NESTED_GIT)
return path_none;
if (pathspec && !matches_how) {
matches_how = dir_match(istate, pathspec,
dirname, len);
if (!matches_how)
return path_none;
}
if (matches_how == MATCHED_RECURSIVELY_LEADING_PATHSPEC)
return path_none;
return excluded ? path_excluded : path_untracked;
}
+7
View File
@@ -79,4 +79,11 @@ test_expect_success 'checkout --overwrite-ignore should succeed if only ignored
test_path_is_file some_dir
'
test_expect_success 'checkout must not overwrite untracked nested repo' '
git checkout -f start &&
rm -rf some_dir &&
git init some_dir &&
test_must_fail git checkout df_conflict
'
test_done
+5
View File
@@ -340,4 +340,9 @@ test_expect_success 'status ignores submodule in excluded directory' '
test_cmp expected actual
'
test_expect_success 'status omits excluded directory with submodule on prefix match' '
git status --porcelain --ignored -u tracke >actual &&
test_must_be_empty actual
'
test_done