Skip to content

Shared fetch state 2#727

Merged
matt2e merged 3 commits into
mainfrom
shared-fetch-state-2
May 14, 2026
Merged

Shared fetch state 2#727
matt2e merged 3 commits into
mainfrom
shared-fetch-state-2

Conversation

@matt2e
Copy link
Copy Markdown
Contributor

@matt2e matt2e commented May 14, 2026

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

matt2e and others added 3 commits May 14, 2026 15:45
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>
@matt2e matt2e requested review from baxen and wesbillman as code owners May 14, 2026 07:30
@matt2e matt2e merged commit a97fa8d into main May 14, 2026
3 checks passed
@matt2e matt2e deleted the shared-fetch-state-2 branch May 14, 2026 07:30
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 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".

Comment on lines +281 to +282
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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

Comment on lines +389 to +391
if let Err(error) = run_git(&args) {
if is_missing_remote_ref(&error) {
upstream_known_missing = true;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant