Ignore-file search walks past a linked worktree's root, so the enclosing checkout's info/exclude skips every file
- Dominant language
- Rust
- Stars
- 7k
- Forks
- 516
- PR merge metrics
- No merged PRs in 30d
Description
### Describe the Bug
Split out of #4401 at @kinto0's request — this is the ignore-file half. The hidden-directory-filter half is filed separately as #4526.
The upward search for ignore files (`.gitignore`, `.ignore`, `.git/info/exclude`) in `crates/pyrefly_util/src/globs.rs` treats the directory tree as a single hierarchy: it walks from the project root towards the filesystem root and takes the nearest of each file. A **linked git worktree**'s `.git` is a `gitdir: …` pointer *file*, not a directory, so the search walks straight past the working-tree root, finds the **enclosing checkout's** `.git/info/exclude`, and applies its patterns rooted at that enclosing checkout.
Several agent tools register their worktrees by adding a pattern like `**/.claude/worktrees/` to the main checkout's `.git/info/exclude`, to keep them out of `git status`. That pattern then matches every file inside the worktree, and the check finds nothing:
```
ignore files [/.gitignore, /path/to/main-checkout/.git/info/exclude]
No Python files matched patterns …
```
git's own semantics differ in two ways:
- A directory carrying a `.git` entry — file **or** directory — is a working-tree root. An outer repository's ignore rules never apply inside it.
- A repository's shared `info/exclude` does apply inside each linked worktree, but **relative to that worktree's own root**, reached through the `gitdir` pointer and `commondir`.
`git -C check-ignore -v src/m.py` confirms the files are not ignored.
### Reproduction
```sh
git init main && cd main
printf '**/wt/\n' >> .git/info/exclude
git worktree add .claude/worktrees/wt
cd .claude/worktrees/wt
printf '[tool.pyrefly]\nproject-includes = ["src"]\n' > pyproject.toml
mkdir src && touch src/m.py
pyrefly check # No Python files matched patterns …
```
(`git -C . check-ignore -v src/m.py` exits 1 here: git does not consider the file ignored.)
### Expected behavior
The worktree checks like any other checkout: the upward ignore-file search stops at the working-tree boundary, and the repository's shared `info/exclude` applies relative to the worktree's own root — matching `git check-ignore`'s verdicts.
I have a fix and will open a PR against this issue.
Contributor guide
Assessment
This issue has not been assessed yet.