fix(core): scope file search gitignore to repository context#13250
Merged
etraut-openai merged 3 commits intoopenai:mainfrom Mar 3, 2026
Merged
fix(core): scope file search gitignore to repository context#13250etraut-openai merged 3 commits intoopenai:mainfrom
etraut-openai merged 3 commits intoopenai:mainfrom
Conversation
Update `codex-file-search` to require a git context before applying `.gitignore` semantics during `@` file discovery. Git itself never reads `.gitignore` from ancestor directories above the repository root. The previous `require_git(false)` setting caused the `ignore` crate to walk parent directories for `.gitignore` files, which could hide valid files like `package.json` and cause false `no matches` results. This prevents parent directories outside the workspace from leaking ignore rules into repository file search.
Rename `whitelist_results` to `nested_file_results` in the no-git-context regression test so the assertion intent is explicit and doesn't imply repo whitelist semantics are being exercised. This aligns the test wording with actual behavior and addresses reviewer feedback while keeping the underlying regression guarantees unchanged.
Contributor
Author
|
@codex review |
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes @ file mention picker’s file-walk behavior to align .gitignore scoping with git’s repository boundary, preventing parent-directory ignore files (e.g. from $HOME) from suppressing valid repo results.
Changes:
- Switch
ignore::WalkBuilderfromrequire_git(false)torequire_git(true)to stop applying ancestor.gitignorefiles above the repo root. - Add/expand documentation explaining the ignore scoping behavior.
- Add regression tests covering (1) leakage from parent
.gitignoreoutside a repo and (2) honoring repo.gitignoreinside an initialized repo.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Contributor
|
Codex Review: Didn't find any major issues. Bravo. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Clarify `respect_gitignore` documentation to reflect that disabling it turns off `.gitignore`, git-global/exclude rules, `.ignore`, and parent-directory ignore scanning. Make git-context tests more hermetic by creating a minimal `.git` directory instead of shelling out to `git init`, and add `!package.json` to fixture rules to reduce flakiness from user global ignore settings.
etraut-openai
approved these changes
Mar 3, 2026
Collaborator
etraut-openai
left a comment
There was a problem hiding this comment.
Good analysis and fix!
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Closes #3493
Problem
When a user's home directory (or any ancestor) contains a broad
.gitignore(e.g.*+!.gitignore), the@file mention picker in Codex silently hides valid repository files likepackage.json. The picker returnsno matchesfor searches that should succeed. This is surprising because manually typed paths still work, making the failure hard to diagnose.Mental model
Git itself never walks above the repository root to assemble its ignore list. Its
.gitignoreresolution is strictly scoped: it reads.gitignorefiles from the repo root downward, the per-repo.git/info/exclude, and the user's global excludes file (viacore.excludesFile). A.gitignoresitting in a parent directory above the repo root has no effect ongit status,git ls-files, or any other git operation. Our file search should replicate this contract exactly.The
ignorecrate'sWalkBuilderhas arequire_gitflag that controls whether it follows this contract:require_git(false)(the previous setting): the walker reads.gitignorefiles from all ancestor directories, even those above or outside the repository root. This is a deliberate divergence from git's behavior in theignorecrate, intended for non-git use cases. It means a~/.gitignorewith*will suppress every file in the walk—something git itself would never do.require_git(true)(this fix): the walker only applies.gitignoresemantics when it detects a.gitdirectory, scoping ignore resolution to the repository boundary. This matches git's own behavior: parent.gitignorefiles above the repo root have no effect.The fix is a one-line change:
require_git(false)becomesrequire_git(true).How
require_git(false)got hereThe setting was introduced in af338cc (#2981, "Improve @ file search: include specific hidden dirs such as .github, .gitlab"). That PR's goal was to make hidden directories like
.githuband.vscodediscoverable by setting.hidden(false)on the walker. Therequire_git(false)was added alongside it with the comment "Don't require git to be present to apply git-related ignore rules"—the author likely intended gitignore rules to still filter results even when no.gitdirectory exists (e.g. searching an extracted tarball that has a.gitignorebut no.git).The unintended consequence: with
require_git(false), theignorecrate walks above the search root to find.gitignorefiles in ancestor directories. This is a side effect the original author almost certainly didn't anticipate. The PR message says "Preserve.gitignoresemantics," butrequire_git(false)actually breaks git's semantics by applying ancestor ignore files that git itself would never read.In short: the intent was "apply gitignore even without
.git" but the effect was "apply gitignore from every ancestor directory." This fix restores git-correct scoping.Non-goals
respect_gitignoreisfalse(that path already disables all git-related ignore rules).parent_gitignore_outside_repo_does_not_hide_repo_files) intentionally omitsgit init. Theignorecrate'srequire_git(true)causes it to skip gitignore processing entirely when no.gitexists, which is the desired behavior for that scenario. A second test (git_repo_still_respects_local_gitignore_when_enabled) covers the complementary case with a real git repo.Tradeoffs
Behavioral shift: With
require_git(true), directories that contain.gitignorefiles but are not inside a git repository will no longer have those ignore rules applied during@search. This is a correctness improvement for the primary use case (searching inside repos), but changes behavior for the edge case of searching non-repo directories that happen to have.gitignorefiles. In practice, Codex is overwhelmingly used inside git repositories, so this tradeoff strongly favors the fix.Two test strategies: The first test omits
git initto verify parent ignore leakage is blocked; the second runsgit initto verify the repo's own.gitignoreis still honored. Together they cover both sides of therequire_git(true)contract.Architecture
The change is in
walker_worker()withincodex-rs/file-search/src/lib.rs, which configures theignore::WalkBuilderused by the file search walker thread. The walker feeds discovered file paths intonucleofor fuzzy matching. Therequire_gitflag controls whether the walker consults.gitignorefiles at all—it sits upstream of all ignore processing.Tests
parent_gitignore_outside_repo_does_not_hide_repo_files: creates a temp directory tree with a parent.gitignorecontaining*, a child "repo" directory withpackage.jsonand.vscode/settings.json, and asserts that both files are discoverable viarun()withrespect_gitignore: true.git_repo_still_respects_local_gitignore_when_enabled: the complementary test—runsgit initinside the child directory and verifies that the repo's own.gitignoreexclusions still work (e.g..vscode/extensions.jsonis excluded while.vscode/settings.jsonis whitelisted). Confirms thatrequire_git(true)does not disable gitignore processing inside actual git repositories.