feat: detect git worktrees (opt-in toggle, #24)#25
Open
steven-pribilinskiy wants to merge 3 commits into
Open
Conversation
Linked git worktrees were previously skipped because the scanner only matched on `.git` directories — a worktree's `.git` is a regular file containing a `gitdir:` pointer. This change adds opt-in support so worktree-heavy workflows can see them in the dashboard alongside regular repos. - config: `includeWorktrees: false` (default) in config.yml - CLI: `--worktrees` flag for one-shot enable - TUI: uppercase `W` toggles live; flips visibility AND totals together - model: new `is_worktree` field on `Repo` (omitempty) - TUI: worktrees render with a `⎇` marker in the Repository column, and the stats bar shows `📁 N repos (M wt)` when the toggle is on - scan: filters submodules out (gitdir under `.git/modules/`); only `gitdir:` paths under `.git/worktrees/` are accepted - cache: include the toggle in the cache key so flipping it forces a fresh scan instead of returning the wrong set
|
Kilo Code Review could not run — your account is out of credits. Add credits or switch to a free model to enable reviews on this change. |
Two changes that together make the W toggle feel snappy. 1) Parallel git status during scan. The scanner walked roots in parallel but ran `git status --porcelain=v2 -b` and `git log -1` serially within each root. On a 1058-repo tree that's ~2,100 subprocess forks on a sequential path — measured at 3.6s on a typical config. Split scan into two phases: - Walk: discover repos in parallel by root (cheap; just dir traversal). - Resolve: fan out gitstatus.Status across runtime.NumCPU()*2 workers. Same tree now scans in ~1.1s — ~3x faster, bounded by fork/IO contention rather than serialisation. No correctness change; results are unordered but the TUI sorts separately. 2) Instant in-memory worktree toggle. Previously every `W` press triggered a full rescan, paying the cold-scan cost (~1s now, was ~3.6s) every time — even when toggling OFF, where the data we already have is a strict superset of what we want to display. Track whether the last scan included worktrees on the model. On toggle: - Fast path (in-memory filter): we already have the data we need — either we're hiding worktrees we already scanned, or we don't need worktrees at all. Instant. - Slow path (rescan): only when we need worktrees and the current scan doesn't have them. Once paid, all subsequent toggles in this session are instant. `applyFilter` and `renderStats` now treat the worktree toggle as part of the base set, so totals + dirty/clean counts stay consistent with the table when you flip it.
The W toggle was forgotten on relaunch — startup always read cfg.IncludeWorktrees from config.yml, so any in-session toggle was lost. Add a small JSON state file at ~/.config/git-scope/state.json that holds the runtime toggle. Resolution order, low → high precedence: 1. Config file (`includeWorktrees:` in config.yml) 2. State file (last W toggle from previous session) 3. CLI flag (`--worktrees` for one-shot override) Kept separate from config.yml on purpose — yaml.Marshal would clobber the user's comments on every toggle. State writes are best-effort; a permission failure doesn't break the in-session toggle.
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.
Closes #24.
Summary
Adds opt-in support for linked git worktrees. Today the scanner only matches
.gitdirectories, so worktrees (where.gitis a file containing agitdir:pointer) are silently skipped — including any uncommitted changes in them.A single keybinding controls everything: visibility, the
📁 N reposcount, and the dirty/clean totals all flip together so the table and stats bar stay consistent.Changes
config.yml): newincludeWorktrees: false(default).--worktreesflag for one-shot enable. Overrides the config value when set.Wtoggles live (lowercasewalready does workspace switch). Toggle re-runs the scan and updates totals atomically.internal/model.Repo): newIsWorktree boolfield (omitempty in JSON for back-compat with downstreamgit-scope scanconsumers).internal/scan):ScanRootsWithOptions(roots, ignore, includeWorktrees). The oldScanRootsis kept as a thin wrapper..gitfiles are read; only entries whosegitdir:path contains/worktrees/are accepted. Submodules (gitdir:under.git/modules/) are filtered out — including them would inflate the dashboard with content already nested under a parent repo.⎇marker in the Repository column. Stats bar shows📁 N repos (M wt)when the toggle is on.internal/cache): cache validity now considers the toggle, so flipping it forces a fresh scan instead of serving the stale opposite set.Unreleasedentry.Why opt-in
Test plan
Tested against
~/projects/cloudbeds/toolswhich contains anautomation-hub.worktrees/directory with 21 worktrees alongside 10 regular repos.Each worktree's
branchfield is correctly resolved bygit status --porcelain=v2from inside the worktree path — no changes needed ininternal/gitstatus.Manual TUI checks (run before/after):
scanoutput.W→ status line shows "Including worktrees — rescanning…", table grows,📁badge shows(N wt), dirty/clean counts include worktrees.Wagain → reverts cleanly. Cache check catches the toggle change so the rescan is real, not a cached return.--worktreesflag andincludeWorktrees: truein config both produce the same starting state;Wstill flips at runtime.Notes
git statusunderstands, and they do.⎇marker is one rune wide and reuses the existing 18-char Repository column; existing layout is preserved.