Skip to content

Narrow git fetch origin to branch-specific fetches#642

Merged
ittaiz merged 4 commits into
mainfrom
chore/dev3-research-git-fetch-pull
Jun 11, 2026
Merged

Narrow git fetch origin to branch-specific fetches#642
ittaiz merged 4 commits into
mainfrom
chore/dev3-research-git-fetch-pull

Conversation

@ittaiz

@ittaiz ittaiz commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Replace git fetch origin (full fetch of all remote branches) with git fetch origin <branch> in every call site that only needs the base branch ref. On repos with thousands of remote branches this makes each background fetch orders of magnitude faster.
  • Add a per-repo serialization queue (fetchProjectQueue) so concurrent branch-specific fetches for the same repo don't race on .git/packed-refs.lock.
  • The branch picker's explicit "fetch & list" remains a full fetch — it genuinely needs all remote refs.

What changed

src/bun/git.ts

  • fetchOrigin(projectPath, branch?) — new optional branch arg; runs git fetch origin <branch> when provided
  • Cache key changed from projectPath to projectPath:branch (or projectPath:* for full fetch)
  • fetchProjectQueue serializes concurrent git subprocesses per repo to avoid lock contention
  • removeFetchCache and pullOrigin's cache invalidation updated to match new key format
  • _resetFetchState clears fetchProjectQueue for test isolation

src/bun/rpc-handlers/git-operations.ts — all narrowed call sites:

  • createWorktree → fetches baseBranch
  • getBranchStatusImpl → fetches baseBranch + compareRefBranch (if different) + branchForPush (task branch, for unpushed count freshness)
  • getTaskDiff → fetches baseBranch + compareRefBranch (if different)
  • mergeTask → fetches baseBranch
  • checkMergedBranches → fetches all distinct base branches across the task set (parallel, serialized by queue)
  • Rebase shell script → git fetch origin <fetchBranch> derived from the actual rebase target ref

Test plan

  • Open a task in a large repo — branch status panel loads without a long git fetch origin blocking
  • Rebase on main — tmux pane shows git fetch origin main (or your base branch), not a full fetch
  • With a custom "Diff Comparison Default" set to a non-base branch — ahead/behind counts and diff reflect the current remote state
  • Create a new task — worktree creation completes, worktree starts from the latest base branch commit
  • Click the branch fetch/refresh button in the Create Task modal — still does a full fetch (all remote branches visible in picker)
  • Move a task to completed with an open PR — merge detection fires correctly

🤖 Generated with Claude Code

ittaiz added 4 commits June 10, 2026 08:33
All six fetchOrigin call sites (createWorktree, getBranchStatus, getTaskDiff,
mergeTask, checkMergedBranches, rebase script) only ever compare against
origin/<baseBranch>. Pass that branch to fetchOrigin so the fetch is
git fetch origin <branch> instead of a full-repo fetch.

The fetch cache key changes from projectPath to projectPath:branch so
different branches cache independently. pullOrigin's cache invalidation
and removeFetchCache are updated accordingly.

The fetchBranches (branch picker) path retains the full fetch since it
populates a branch list and needs all remote refs.
rebaseTask: derive the fetch target from rebaseTarget (which may be a
custom compareRef like origin/develop), not just baseBranch.

getBranchStatusImpl / getTaskDiff: when params.compareRef points at a
different origin branch, fetch that branch too so ahead/behind counts
and diffs are computed against a fresh ref.

checkMergedBranches: fetch every distinct baseBranch used by the task
set, not only project.defaultBaseBranch, so per-task merge detection
does not silently compare against a stale remote-tracking ref.
…queue

Switching the dedup key from projectPath to projectPath:branch removed the
implicit serializer that prevented concurrent git fetch processes for the same
repo. Multiple parallel fetches (different branches) race on .git/packed-refs.lock
on repos with packed refs (common on large repos where this optimization matters
most).

fetchProjectQueue chains each new fetch promise off the previous tail for that
projectPath so at most one git fetch subprocess runs per repo at a time. Same-branch
callers still coalesce via fetchInFlight before reaching the queue, so this only
adds sequencing for different-branch concurrent fetches.
… clear

getBranchStatusImpl: also fetch origin/<task-branch> (branchForPush) so
getUnpushedCount sees out-of-band remote pushes to the task branch. The
old full fetch refreshed this ref as a side effect; the narrowed fetch did not.

_resetFetchState: add fetchProjectQueue.clear() to prevent cross-test
isolation issues from stale queue tails (test-only helper).
@ittaiz ittaiz merged commit 7e28e5d into main Jun 11, 2026
4 checks passed
@ittaiz ittaiz deleted the chore/dev3-research-git-fetch-pull branch June 11, 2026 05:59
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