Shared fetch state 2#727
Conversation
Add a repo-level fetch cache keyed by repo path so that when multiple branches share the same local .git directory, a single git fetch satisfies all of them within the TTL window. Implements "Option C" from the plan: the repo-level TTL gates the "did we recently talk to the remote?" decision, while per-branch refspec tracking ensures any new refspecs get a cheap narrow fetch (without --prune) when the repo is already fresh. Remote projects continue using per-branch caching unchanged. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
Cover normal Unix path, Windows-style path with colons, branch==base edge case, non-local prefix rejection, and too-few-segments rejection to lock in the double rsplit_once parsing invariant. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
On a full fetch (TTL expired, --prune), replace the repo-level fetched_refspecs set with exactly the needed refspecs rather than extending the existing set. This prevents unbounded growth from branches that were opened and later closed. Narrow fetches (within TTL, filling gaps) continue to extend additively as before. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aa9d89e59b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| let repo_key = repo_key_from_local_cache_key(cache_key); | ||
| let to_fetch = refspecs_to_fetch(repo_key.as_deref(), &needed, fetch_mode, now); |
There was a problem hiding this comment.
Derive the shared key from the git common dir
When local branches are stored as separate git worktrees, cache_key is built from the per-branch worktree path (compute_local_branch_git_state passes repo.display() for that worktree), so deriving the repo-level key from this string still produces a different key for every branch. In that common local-project flow the new repo cache never gets shared, and each branch can still perform its own network fetch inside the TTL instead of reusing the fetch done for the shared .git common dir. Consider keying this cache from git rev-parse --git-common-dir (or the original clone path) rather than the worktree path.
Useful? React with 👍 / 👎.
| if let Err(error) = run_git(&args) { | ||
| if is_missing_remote_ref(&error) { | ||
| upstream_known_missing = true; |
There was a problem hiding this comment.
Treat missing single base ref separately
When the repo cache is fresh and the only uncovered refspec is the base branch, fetch_refspecs.len() == 1; if that base ref is missing on the remote, this branch marks upstream_known_missing = true and returns a fresh fetch instead of reporting the base fetch problem. In that scenario an existing upstream branch is shown as missing because compute_upstream_state skips resolving it whenever this flag is set. This missing-ref handling should only set upstream_known_missing when the failed single refspec is the branch refspec, not the base refspec.
Useful? React with 👍 / 👎.
Summary
Adds a repo-level fetch cache so that when multiple branches share the same local .git directory, only one network fetch is needed per TTL window
New branches that appear after a repo-wide fetch trigger a cheap narrow fetch for just the missing refspecs (without --prune)
Fixes needs_fetch to consult the repo-level cache so timeline's two-stream decision stays consistent
Fixes a bug where fetched_refspecs was being extended on full fetches instead of reset
Test plan
Unit tests for repo_key_from_local_cache_key covering normal paths, Windows paths, same branch/base, non-local keys, and too-few segments
CI passes (crates-fmt, crates-test, crates-lint, staged-ci, differ-ci)
🤖 Generated with Claude Code