fix(worktree): Cache git detection results to eliminate slowness (bd-7di)

In git worktrees, any bd command was slow with a 2-3s pause because:
- git.IsWorktree() was called 4+ times per command
- Each call spawned 2 git processes (git-dir and git-common-dir)
- git.GetRepoRoot() and git.GetMainRepoRoot() also called multiple times

Fix: Cache results using sync.Once since these values do not change during
a single command execution:
- IsWorktree() - caches worktree detection
- GetRepoRoot() - caches repo root path
- GetMainRepoRoot() - caches main repo root for worktrees

Added ResetCaches() for test cleanup between subtests that change directories.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-25 22:04:40 -08:00
parent df5d4b384c
commit 32c803dd16
3 changed files with 50 additions and 0 deletions

View File

@@ -93,6 +93,13 @@ func isWorktreeUncached() bool {
return absGit != absCommon
}
// mainRepoRootOnce ensures we only get main repo root once per process.
var (
mainRepoRootOnce sync.Once
mainRepoRootResult string
mainRepoRootErr error
)
// GetMainRepoRoot returns the main repository root directory.
// When in a worktree, this returns the main repository root.
// Otherwise, it returns the regular repository root.
@@ -101,7 +108,16 @@ func isWorktreeUncached() bool {
// /project/.worktrees/feature/), this correctly returns the main repo
// root (/project/) by using git rev-parse --git-common-dir which always
// points to the main repo's .git directory. (GH#509)
// The result is cached after the first call.
func GetMainRepoRoot() (string, error) {
mainRepoRootOnce.Do(func() {
mainRepoRootResult, mainRepoRootErr = getMainRepoRootUncached()
})
return mainRepoRootResult, mainRepoRootErr
}
// getMainRepoRootUncached performs the actual main repo root lookup without caching.
func getMainRepoRootUncached() (string, error) {
// Use --git-common-dir which always returns the main repo's .git directory,
// even when running from within a worktree or its subdirectories.
// This is the most reliable method for finding the main repo root.
@@ -190,4 +206,18 @@ func getGitDirNoError(flag string) string {
return ""
}
return strings.TrimSpace(string(out))
}
// ResetCaches resets all cached git information. This is intended for use
// by tests that need to change directory between subtests.
// In production, these caches are safe because the working directory
// doesn't change during a single command execution.
func ResetCaches() {
isWorktreeOnce = sync.Once{}
isWorktreeResult = false
mainRepoRootOnce = sync.Once{}
mainRepoRootResult = ""
mainRepoRootErr = nil
repoRootOnce = sync.Once{}
repoRootResult = ""
}