Honor .gitignore negations of directories (#3694) - #5306
Open
l46983284-cpu wants to merge 1 commit into
Open
Conversation
l46983284-cpu
force-pushed
the
fix-3694-gitignore-dir-negation
branch
from
August 12, 2026 16:23
0440d8d to
0f51642
Compare
pathspec's GitIgnoreSpec gives file-pattern matches precedence over directory-pattern matches regardless of order, so `!*/` never re-included a directory ignored by `*`. Black then pruned the directory and silently skipped every file below it. Use check_file() plus a last-match-wins scan over later patterns for trailing-slash paths, matching what git check-ignore does. Signed-off-by: Alex Chen <l46983284@gmail.com>
l46983284-cpu
force-pushed
the
fix-3694-gitignore-dir-negation
branch
from
August 12, 2026 16:25
09266d3 to
bebbb16
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3694.
pathspec's
GitIgnoreSpecgives file-pattern matches precedence overdirectory-pattern matches regardless of their order in the .gitignore
file, and its directory patterns match whole subtrees. Git instead
lets the last matching pattern decide and matches directory patterns
only against the directory itself. Because of that, a negated
directory pattern like
!*/never re-included a directory ignored byan earlier
*, and Black pruned the directory and silently skippedevery tracked file below it.
Use
check_file()for the ignore decision, and for trailing-slashpaths apply a last-match-wins scan over the later patterns with an
end-of-path match criterion, reproducing git's exact-directory
semantics. A regression test uses the exact fixture from the issue.
One pre-existing divergence is intentionally left as-is: a negation in
a nested .gitignore cannot re-include a file under a directory ignored
at the root (root-decides-first traversal), which Black already did
not do before this change. Getting that right likely belongs in
pathspec/traversal upstream and is a separate follow-up.