Fall back to local base ref when worktree-create refresh fails (#7335)

Creating a workspace hard-failed with "Could not refresh base ref …"
whenever the pre-create git fetch of a remote-tracking base (e.g.
origin/main) failed — offline, transient, or (common on Linux GUI) the
Electron process lacking SSH_AUTH_SOCK so `ssh -o BatchMode=yes` cannot
auth. This blocked creation even when a perfectly usable local
origin/main already existed and `git worktree add` from it would succeed.

Regression introduced by #2310 (5c93579e40), which replaced the prior
best-effort fetch + post-create reconcile with a hard network gate.

Fix: at all three create sites (local runtime, local IPC, SSH), only
throw when the refresh failed AND no usable local base ref exists;
otherwise create from the local ref (a possibly stale but valid base).
Also: move the SSH local-ref probe after session.registerRoot so relays
that gate generic git.exec don't false-negative and defeat the fallback.

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Neil
2026-07-04 01:30:01 -07:00
committed by GitHub
co-authored by Orca
parent f215a48064
commit 04046fc4f2
4 changed files with 217 additions and 29 deletions
+49 -3
View File
@@ -2355,10 +2355,21 @@ describe('OrcaRuntimeService', () => {
}
})
it('does not create runtime local worktrees when remote-tracking base refresh fails', async () => {
it('creates a runtime local worktree from an existing local base ref when the refresh fails', async () => {
// Regression: an offline/auth failure while refreshing the remote-tracking
// base must not block creation when a usable local base ref already exists.
const runtime = new OrcaRuntimeService(store)
computeWorktreePathMock.mockReturnValue('/tmp/workspaces/cli-refresh-fails')
ensurePathWithinWorkspaceMock.mockReturnValue('/tmp/workspaces/cli-refresh-fails')
const createdWorktree = {
path: '/tmp/workspaces/cli-refresh-fails',
head: 'base-sha',
branch: 'cli-refresh-fails',
isBare: false,
isMainWorktree: false
}
computeWorktreePathMock.mockReturnValue(createdWorktree.path)
ensurePathWithinWorkspaceMock.mockReturnValue(createdWorktree.path)
vi.mocked(addWorktree).mockResolvedValueOnce({})
vi.mocked(listWorktrees).mockResolvedValue([createdWorktree])
const gitSpy = vi.spyOn(gitRunner, 'gitExecFileAsync').mockImplementation(async (args) => {
if (args[0] === 'remote') {
return { stdout: 'origin\n', stderr: '' }
@@ -2366,6 +2377,7 @@ describe('OrcaRuntimeService', () => {
if (args[0] === 'rev-parse' && args.includes('--git-common-dir')) {
return { stdout: '/tmp/repo/.git\n', stderr: '' }
}
// Local remote-tracking base ref resolves -> usable fallback exists.
if (args[0] === 'rev-parse' && args[1] === '--verify') {
return { stdout: 'base-sha\n', stderr: '' }
}
@@ -2380,6 +2392,40 @@ describe('OrcaRuntimeService', () => {
repoSelector: 'id:repo-1',
name: 'cli-refresh-fails'
})
).resolves.toBeDefined()
expect(addWorktree).toHaveBeenCalled()
} finally {
gitSpy.mockRestore()
}
})
it('does not create a runtime local worktree when the refresh fails and no local base ref exists', async () => {
const runtime = new OrcaRuntimeService(store)
computeWorktreePathMock.mockReturnValue('/tmp/workspaces/cli-refresh-no-local')
ensurePathWithinWorkspaceMock.mockReturnValue('/tmp/workspaces/cli-refresh-no-local')
const gitSpy = vi.spyOn(gitRunner, 'gitExecFileAsync').mockImplementation(async (args) => {
if (args[0] === 'remote') {
return { stdout: 'origin\n', stderr: '' }
}
if (args[0] === 'rev-parse' && args.includes('--git-common-dir')) {
return { stdout: '/tmp/repo/.git\n', stderr: '' }
}
// No local remote-tracking base ref -> nothing to fall back on.
if (args[0] === 'rev-parse' && args[1] === '--verify') {
throw new Error('missing ref')
}
if (args[0] === 'fetch') {
throw new Error('network unavailable')
}
return { stdout: '', stderr: '' }
})
try {
await expect(
runtime.createManagedWorktree({
repoSelector: 'id:repo-1',
name: 'cli-refresh-no-local'
})
).rejects.toThrow(
'Could not refresh base ref "origin/main" from "origin". Check your network and try again.'
)