You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Sync local git remains in resolveThreadGit / defaultBranch on the PR read paths #228
Split out of #124, which converted the dominant offenders. This is the small honest remainder.
electron/worktrees.js no longer runs any synchronous gh (sync ghTry was deleted). But two helpers still use the synchronous execCommand git wrapper, and they sit on paths that are read-only and user-facing:
resolveThreadGit (~line 1520) — used by prStatus, createPr, mergePr
defaultBranch (~line 187) — used by listPrs, createPr, and the worktree flows
So listPrs and prStatus now have async gh but still make ~2 synchronous local git calls each (remote get-url origin, branch --show-current).
Why this was left
Scale. Measured in #124, local git under concurrency is ~30-50ms p99; the gh calls that were fixed were bounded at 30_000ms and are network-bound. Two local git calls on a PR view is real but roughly three orders of magnitude below what was actually causing the beachball, and converting resolveThreadGit cascades into the worktree write flows (setupWorktree, mergeWorktree, push, commit, revertFile, cleanupWorktree) which are all still deliberately sync.
Deliberately still sync, and fine
The worktree write paths — setupWorktree, mergeInto / mergeWorktree, push, commit, revertFile, cleanupWorktree, unmergedFiles, maybeRenameWorktreeBranch. They fire once per deliberate click and are bounded at 15s by #88. Marked in-file with a ponytail: comment at the sync gitOut helper so the remainder is documented rather than rediscovered.
Worth doing when
If event-loop lag instrumentation (CODER_LOOP_LAG=1, added in #124) shows the PR/Git tab still contributing measurable p99 under concurrent runs. Measure before converting — that is what #124 established as the working method, and it is what stopped the store-stringify work from being a guess.
Async helpers already exist in the file (gitOutAsync, gitOutForDiffAsync, gitTryAsync, gitExecThrowAsync), so this is routing, not new machinery.
Scoping note before implementation: the premise in the issue body is stale against origin/main (7140d2e).
electron/worktrees.js:1122 still defines the synchronousghTry (execFileSync, 30_000ms bound), and listPrs, prStatus, prChecks, createPr, mergePr are all still synchronous functions that use it. Sync gh was not deleted.
So the PR read paths block the main process on network-bound gh (30s ceiling), not just on ~2 local git calls (~30-50ms). Fixing only the local git half while a 30s sync gh sits on the same line would be theatre.
Scope taken:
resolveThreadGit -> async (every caller is a PR path).
new defaultBranchAsync; sync defaultBranch stays for the worktree write flows.
read paths listPrs / prStatus / prChecks -> async, ghTry -> ghTryAsync at the interactive 30s timeout.
createPr / mergePr become async (they await resolveThreadGit) but keep sync ghTry and sync push/commit internals - deliberate-click write paths, unchanged per the issue.
Not doing: CODER_LOOP_LAG instrumentation (not asked for here), and no conversion of the worktree write flows.
Activity
currentbits commentedon Aug 17, 2026
Scoping note before implementation: the premise in the issue body is stale against
origin/main(7140d2e).electron/worktrees.js:1122still defines the synchronousghTry(execFileSync, 30_000ms bound), andlistPrs,prStatus,prChecks,createPr,mergePrare all still synchronous functions that use it. Syncghwas not deleted.CODER_LOOP_LAGdoes not exist anywhere in the tree, so the "measure first" instrumentation App beachballs when multiple threads run concurrently #124 was supposed to leave behind is not available either.So the PR read paths block the main process on network-bound
gh(30s ceiling), not just on ~2 local git calls (~30-50ms). Fixing only the local git half while a 30s syncghsits on the same line would be theatre.Scope taken:
resolveThreadGit-> async (every caller is a PR path).defaultBranchAsync; syncdefaultBranchstays for the worktree write flows.listPrs/prStatus/prChecks-> async,ghTry->ghTryAsyncat the interactive 30s timeout.createPr/mergePrbecome async (they awaitresolveThreadGit) but keep syncghTryand syncpush/commitinternals - deliberate-click write paths, unchanged per the issue.Not doing:
CODER_LOOP_LAGinstrumentation (not asked for here), and no conversion of the worktree write flows.Merge origin/main: #229 landed the gh conversion; keep only the #228 …