Skip linked git worktrees nested in the project - #111
Merged
Merged
Conversation
A linked worktree below the root (e.g. .claude/worktrees/) is a full repo copy; indexing it duplicated every definition. Walkers, the watcher and single-file updates skip dirs whose .git file points into .git/worktrees/. Submodules and Mix git deps stay indexed. FindProjectRoot no longer climbs above a linked worktree to the enclosing checkout's database. Fixes remoteoss#109
Detection - Detect linked worktrees by git's commondir marker instead of matching "/.git/worktrees/" in the gitdir path. This finds worktrees of bare repositories, and a submodule at a path named worktrees/ no longer counts. When git has pruned the admin directory, its place under a worktrees/ directory is the fallback. - Add GitDir, which resolves a .git file to the git directory it names. Index - The incremental sweep removed only stored files that no longer exist on disk, so an index built before worktrees were skipped kept its duplicates. It now also removes stored files inside a nested worktree, checking only the paths the sweep did not see, once per directory. - Find indexed files below a deleted directory with a range query on the path index instead of reading every stored path. Watchers and runtime - A mix.exs or mix.lock change in a nested worktree no longer reindexes the enclosing project. - fsnotify finds worktrees from the directory entries it already reads, watches only a worktree's top for its .git file, drops events from it, and removes the watches below a directory when its .git file appears. The watcher walk no longer opens a .git file per directory or sorts entries. - FSEvents knows worktree tops from git's records and from new .git files, and drops their events with map lookups, so adding or removing a worktree no longer reconciles the whole workspace. - Files indexed before a directory became a worktree (cp -r can copy them before .git) are removed. A top whose .git file goes away while the directory stays is indexed as a plain directory after the retry interval, which lets git worktree remove finish first. HEAD pollers - Both pollers resolve the git directory with GitDir, so branch switches are seen when the project root is a linked worktree or a submodule. Also remove the stray root copy of internal/lsp/beam_server.exs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The only caller is the darwin watcher, so golangci-lint on Linux reported the function as unused. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- git worktree remove deletes a worktree's .git file before the rest of the checkout. A full reconcile in between, which the mass delete triggers by overflowing the watcher, indexed the remaining files. The walkers, the sweep and both watchers now also treat a directory that git records in <common dir>/worktrees/ as a worktree, until git worktree prune. Reading the records costs about 0.2 ms per walk. - git worktree add writes the .git file before commondir, so the fsnotify watcher could miss a new worktree and watch its whole checkout. The admin directory's gitdir backlink now identifies the worktree, and a Write to .git is checked as well as its Create. - The FSEvents watcher now knows a worktree renamed within the project under its new name. - CollectElixirFilesParallel yields a root that is a file, as WalkElixirFiles does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- fsnotify: drop events from below a known top, not only from the top, so queued events from a tree that just became a worktree add no watches. - Both watchers check a top that git still records again after each retry interval, so it is indexed once git worktree prune drops the record instead of staying skipped until a restart. - unwatchBelow reads the watch list in memory instead of walking the checkout on the event loop. - FSEvents: drop the ancestor scan on every directory event; the known tops and the check of the directory itself cover it. - A submodule at worktrees/<name> with a missing git directory is no longer taken for a pruned worktree. - RemoveFilesUnderRoot compares cleaned stored paths again, as editor URIs are stored as sent. - Share ReadDirUnsorted and NestedWorktreeSet from the parser. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- A known top whose path comes back as a plain directory, for example after a deleted worktree's record was pruned, is checked again and indexed instead of being skipped until a restart. - A directory that is removed or moved takes the known tops below it along. - Darwin test callbacks never block their timer goroutine. - The CHANGELOG notes that on macOS a worktree of another repository that exists at startup can still trigger a workspace sweep. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A stale top only lives in a running watcher's memory and needs a deleted, pruned worktree replaced by a plain directory at the same path. That is too rare to pay for on every remove and rename event. Also drop the CHANGELOG note about macOS sweeps, which describes unchanged behaviour. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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 #109.
Skips linked git worktrees nested below the project root (e.g.
.claude/worktrees/<name>), with no config needed.What counts as nested: a directory whose
.gitfile links a worktree, or one that git still records in<common dir>/worktrees/. The record coversgit worktree remove, which deletes the.gitfile before the rest of the checkout. Submodules and Mix git deps stay indexed.Changes
FindProjectRootstops at a linked worktree, so dexter started inside one uses its own index..gitfile, so branch switches are seen when the root is a linked worktree or a submodule.🤖 Generated with Claude Code