Skip to content

Comments

WIP Cache GetWorktreePath result to avoid repeated git commands#473

Open
evisdren wants to merge 2 commits intomainfrom
commit_optimizations
Open

WIP Cache GetWorktreePath result to avoid repeated git commands#473
evisdren wants to merge 2 commits intomainfrom
commit_optimizations

Conversation

@evisdren
Copy link
Contributor

Uses the same cwd-keyed caching pattern as paths.RepoRoot() to eliminate redundant git rev-parse --show-toplevel calls.

Entire-Checkpoint: c79e31160fd3

Uses the same cwd-keyed caching pattern as paths.RepoRoot() to
eliminate redundant `git rev-parse --show-toplevel` calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: c79e31160fd3
@evisdren evisdren requested a review from a team as a code owner February 24, 2026 05:30
Copilot AI review requested due to automatic review settings February 24, 2026 05:30
@cursor
Copy link

cursor bot commented Feb 24, 2026

PR Summary

Low Risk
Small, localized performance change with straightforward locking; main risk is stale cache if the process changes directories or worktree state unexpectedly.

Overview
Reduces repeated git rev-parse --show-toplevel executions by caching GetWorktreePath() results keyed by current working directory, using an RWMutex for concurrent access.

Adds ClearWorktreePathCache() to explicitly reset the cache (primarily for tests that change directories).

Written by Cursor Bugbot for commit c04fc78. Configure here.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a working-directory-keyed cache for strategy.GetWorktreePath() to reduce repeated git rev-parse --show-toplevel subprocess calls, following the same caching approach used elsewhere in the CLI for git path discovery.

Changes:

  • Add an RWMutex-protected cache for GetWorktreePath() keyed by current working directory.
  • Add ClearWorktreePathCache() helper intended for tests that change directories.

Comment on lines 669 to 672
cwd, err := os.Getwd() //nolint:forbidigo // needed for cache key
if err != nil {
cwd = ""
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If os.Getwd() fails, cwd is set to "" and the function can still populate/consult the cache under an empty key. That can return a stale worktree path in later calls where Getwd continues to fail (e.g., deleted/unreadable CWD), potentially pointing operations at the wrong repo. Consider skipping both cache read and cache write when Getwd fails (treat it as an uncachable call), or return an explicit error instead of using "" as a cache key.

Copilot uses AI. Check for mistakes.
Comment on lines 657 to 663
// worktreePathCache caches the worktree path to avoid repeated git commands.
// The cache is keyed by the current working directory to handle directory changes.
var (
worktreePathMu sync.RWMutex
worktreePathCache string
worktreePathCacheDir string
)
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces a second, independent cache for git rev-parse --show-toplevel even though paths.RepoRoot() already implements the same cwd-keyed caching and is already used in this package (e.g., OpenRepository). To avoid duplicated logic/state (and avoid running the same git command once per cache), consider implementing GetWorktreePath in terms of paths.RepoRoot (wrapping the error message if needed) and removing this separate cache.

Copilot uses AI. Check for mistakes.
Comment on lines 665 to 699
// GetWorktreePath returns the absolute path to the current worktree root.
// This is the working directory path, not the git directory.
// The result is cached per working directory.
func GetWorktreePath() (string, error) {
cwd, err := os.Getwd() //nolint:forbidigo // needed for cache key
if err != nil {
cwd = ""
}

// Check cache with read lock first
worktreePathMu.RLock()
if worktreePathCache != "" && worktreePathCacheDir == cwd {
cached := worktreePathCache
worktreePathMu.RUnlock()
return cached, nil
}
worktreePathMu.RUnlock()

// Cache miss - get worktree path and update cache with write lock
ctx := context.Background()
cmd := exec.CommandContext(ctx, "git", "rev-parse", "--show-toplevel")
output, err := cmd.Output()
if err != nil {
return "", fmt.Errorf("failed to get worktree path: %w", err)
}
return strings.TrimSpace(string(output)), nil

result := strings.TrimSpace(string(output))

worktreePathMu.Lock()
worktreePathCache = result
worktreePathCacheDir = cwd
worktreePathMu.Unlock()

return result, nil
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new caching behavior in GetWorktreePath isn't covered by tests. Since this file already has unit tests, it would be useful to add one that proves the second call is served from cache (e.g., call once in a temp repo, then modify PATH so invoking git would fail, and verify the second call still succeeds; use ClearWorktreePathCache for isolation).

Copilot generated this review using guidance from repository custom instructions.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

worktreePathMu.Lock()
worktreePathCache = ""
worktreePathCacheDir = ""
worktreePathMu.Unlock()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exported ClearWorktreePathCache function is never called anywhere

Low Severity

ClearWorktreePathCache is a new exported function that is never called anywhere in the codebase. The analogous ClearRepoRootCache is called in 6 places across benchmarks and tests, but ClearWorktreePathCache has zero callers. If any benchmarks or tests change directories and then invoke code paths that call GetWorktreePath, the stale cache won't be cleared, potentially leading to subtle test failures in the future.

Fix in Cursor Fix in Web

Addresses three review findings:
- Removes separate cwd-keyed cache that could return stale results when
  os.Getwd() fails (empty-key bug)
- Eliminates duplicate cache/git-command since both functions run the
  same `git rev-parse --show-toplevel`
- Adds tests proving cache behavior and correct worktree resolution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: f4df4a730588
@evisdren evisdren changed the title Cache GetWorktreePath result to avoid repeated git commands WIP Cache GetWorktreePath result to avoid repeated git commands Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant