Fix gitignore negation in child files not overriding parent/global rules#300613
Merged
dmitrivMS merged 3 commits intoMay 9, 2026
Merged
Conversation
Contributor
Author
|
@microsoft-github-policy-service agree |
When a child .gitignore contains a negation pattern (e.g., `!.claude/`), it should override a matching positive pattern from a parent or global .gitignore (e.g., `.claude`). Previously, negation patterns in the current file were only checked against the current file's own positive patterns. If the current file had no matching positive pattern, the negation was ignored and the parent's positive pattern took effect. This fix adds explicit checks: if a negation pattern in the current file matches the path, return false (not ignored) without delegating to the parent. This matches git's actual behavior where the last matching rule wins and child gitignore files take precedence over parent/global ones. Fixes microsoft#156077
5b56791 to
d131c2c
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes .gitignore precedence handling in VS Code’s ignore parser so that negation rules in a more specific/child ignore file can override matching positive rules coming from parent/global ignore files, aligning behavior more closely with git check-ignore.
Changes:
- Update
IgnoreFile.parseIgnoreFile()to short-circuit to “not ignored” when the current ignore file contains a matching negation rule, instead of delegating to the parent. - Add regression tests covering child negation overriding parent ignore for both directories and files.
Show a summary per file
| File | Description |
|---|---|
| src/vs/workbench/services/search/common/ignoreFile.ts | Ensures matching negation rules in the current ignore file override parent/global ignore decisions. |
| src/vs/workbench/services/search/test/common/ignoreFile.test.ts | Adds tests validating that child negation patterns override parent ignore patterns for directories and files. |
Copilot's findings
- Files reviewed: 2/2 changed files
- Comments generated: 1
Review feedback: - Cache isDirIncluded/isFileIncluded results to avoid duplicate matcher evaluations - Defer fileIncluded computation past the dir-ignore short-circuit - Fix test that misused a directory path with isDir=false; use a real file path under the ignored directory instead
Contributor
|
Made some cleanup for perf + test fixes. |
Contributor
|
Linked issue that will be fixed by this, verified fix manually. |
dmitrivMS
approved these changes
May 9, 2026
alexdima
approved these changes
May 9, 2026
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.
Problem
When
explorer.excludeGitIgnoreis enabled, negation patterns (e.g.,!.myconfig/) in a project's.gitignoredo not override matching positive patterns from parent.gitignorefiles (e.g., a root.gitignorefor a nested workspace folder, or a chained ignore tree).Reproduction (from #291157):
.gitignorecontainstest.txt.gitignorecontains!test.txt"explorer.excludeGitIgnore": true, the subfolder'stest.txtis hidden, even though git considers it not ignoredRoot Cause
In
IgnoreFile.parseIgnoreFile(), theisPathIgnoredfunction only uses negation patterns to counteract positive patterns within the same file. When the current file has no positive pattern for a path, it falls through to the parent'sisPathIgnored()without checking whether the current file has a negation that should override the parent.In git's actual behavior, the last matching rule wins, and rules in more-specific
.gitignorefiles (child directories) take precedence over less-specific ones (parent directories).Fix
Before delegating to the parent, check if the current file has a negation pattern that matches the path. If so, return
false(not ignored) without consulting the parent. This correctly implements git's precedence semantics.Also caches
isDirIncluded/isFileIncludedmatcher results within a singleisPathIgnoredinvocation so they are not evaluated twice.Testing
Added two test cases:
*.log/!important.logacross parent/childFixes #291157
Relates to #156077