mirror of
https://github.com/stablyai/orca.git
synced 2026-10-16 00:03:09 +00:00
Route git operations by owner host
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -285,3 +285,4 @@ Done means: reviewers and future agents can understand the vision, implementatio
|
||||
- [x] 2026-06-13: Fed desktop-owned GitHub/GitLab preflight into Tasks source availability for local and SSH project sources, so missing `gh`/`glab` or missing CLI auth disables the affected provider with source-tool/auth-specific copy. Runtime-owned sources intentionally skip desktop preflight and continue to rely on runtime capability/fetch ownership. Verified with provider availability tests, Tasks source summary tests, TaskPage source-boundary tests, targeted oxlint, and full `pnpm run typecheck`.
|
||||
- [x] 2026-06-13: Electron-verified a local project with local GitHub credentials: added the local Orca worktree to the running dev app, confirmed `gh` auth for `Jinwoo-H`, fetched 10 GitHub work items through explicit `TaskSourceContext { provider: github, hostId: local }`, verified the local source-scoped cache key, and captured the rendered Tasks page showing GitHub issues for the local project.
|
||||
- [x] 2026-06-13: Snapshotted Source Control PR-generation runtime ownership and reused that owner for generation, cancellation, and post-generation git refresh, preventing async PR generation from following a later focused-host switch. Verified with focused Source Control host-boundary tests, targeted oxlint, and `git diff --check`.
|
||||
- [x] 2026-06-13: Extended Source Control git remote operations and upstream refresh to accept explicit runtime-owner settings, then wired SourceControl and ChecksPanel to pass the repo owner host for push, pull, fetch, sync, fast-forward, rebase, publish, and PR-generation follow-up refreshes. Verified with focused editor/git-status tests, targeted oxlint, `git diff --check`, and full `pnpm run typecheck`.
|
||||
|
||||
@@ -694,8 +694,16 @@ export default function ChecksPanel(): React.JSX.Element {
|
||||
// moved, the embedded composer should push before creating the review.
|
||||
setCreatePrPushFirst(true)
|
||||
const connectionId = activeConnectionId ?? undefined
|
||||
await fetchUpstreamStatus(activeWorktreeId, activeWorktree.path, connectionId)
|
||||
}, [activeConnectionId, activeWorktree?.path, activeWorktreeId, fetchUpstreamStatus])
|
||||
await fetchUpstreamStatus(activeWorktreeId, activeWorktree.path, connectionId, undefined, {
|
||||
runtimeTargetSettings: ownerSettings
|
||||
})
|
||||
}, [
|
||||
activeConnectionId,
|
||||
activeWorktree?.path,
|
||||
activeWorktreeId,
|
||||
fetchUpstreamStatus,
|
||||
ownerSettings
|
||||
])
|
||||
const prCreationDefaults = useMemo(() => {
|
||||
if (!settings) {
|
||||
return DEFAULT_SOURCE_CONTROL_AI_PR_CREATION_DEFAULTS
|
||||
@@ -2528,14 +2536,24 @@ export default function ChecksPanel(): React.JSX.Element {
|
||||
activeWorktree.path,
|
||||
false,
|
||||
connectionId,
|
||||
activeWorktree.pushTarget
|
||||
activeWorktree.pushTarget,
|
||||
{ runtimeTargetSettings: ownerSettings }
|
||||
)
|
||||
await fetchUpstreamStatus(activeWorktreeId, activeWorktree.path, connectionId)
|
||||
await fetchUpstreamStatus(activeWorktreeId, activeWorktree.path, connectionId, undefined, {
|
||||
runtimeTargetSettings: ownerSettings
|
||||
})
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}, [activeConnectionId, activeWorktree, activeWorktreeId, fetchUpstreamStatus, pushBranch])
|
||||
}, [
|
||||
activeConnectionId,
|
||||
activeWorktree,
|
||||
activeWorktreeId,
|
||||
fetchUpstreamStatus,
|
||||
ownerSettings,
|
||||
pushBranch
|
||||
])
|
||||
|
||||
const handlePublishBranch = useCallback(async (): Promise<void> => {
|
||||
if (
|
||||
@@ -2554,13 +2572,15 @@ export default function ChecksPanel(): React.JSX.Element {
|
||||
activeWorktree.path,
|
||||
true,
|
||||
connectionId,
|
||||
activeWorktree.pushTarget
|
||||
activeWorktree.pushTarget,
|
||||
{ runtimeTargetSettings: ownerSettings }
|
||||
)
|
||||
await fetchUpstreamStatus(
|
||||
activeWorktreeId,
|
||||
activeWorktree.path,
|
||||
connectionId,
|
||||
activeWorktree.pushTarget
|
||||
activeWorktree.pushTarget,
|
||||
{ runtimeTargetSettings: ownerSettings }
|
||||
)
|
||||
} catch {
|
||||
// Store remote actions already surface the publish failure toast.
|
||||
@@ -2577,6 +2597,7 @@ export default function ChecksPanel(): React.JSX.Element {
|
||||
fetchUpstreamStatus,
|
||||
isPublishingBranch,
|
||||
isRemoteOperationActive,
|
||||
ownerSettings,
|
||||
pushBranch
|
||||
])
|
||||
|
||||
|
||||
@@ -1631,7 +1631,8 @@ function SourceControlInner(): React.JSX.Element {
|
||||
worktreePath,
|
||||
true,
|
||||
connectionId,
|
||||
activeWorktree?.pushTarget
|
||||
activeWorktree?.pushTarget,
|
||||
{ runtimeTargetSettings: activeRepoSettings }
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -1643,7 +1644,9 @@ function SourceControlInner(): React.JSX.Element {
|
||||
false,
|
||||
connectionId,
|
||||
activeWorktree?.pushTarget,
|
||||
forceWithLease ? { forceWithLease: true } : undefined
|
||||
forceWithLease
|
||||
? { forceWithLease: true, runtimeTargetSettings: activeRepoSettings }
|
||||
: { runtimeTargetSettings: activeRepoSettings }
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -1654,12 +1657,20 @@ function SourceControlInner(): React.JSX.Element {
|
||||
false,
|
||||
connectionId,
|
||||
activeWorktree?.pushTarget,
|
||||
{ forceWithLease: true }
|
||||
{ forceWithLease: true, runtimeTargetSettings: activeRepoSettings }
|
||||
)
|
||||
return
|
||||
}
|
||||
if (kind === 'pull') {
|
||||
await pullBranch(activeWorktreeId, worktreePath, connectionId, activeWorktree?.pushTarget)
|
||||
await pullBranch(
|
||||
activeWorktreeId,
|
||||
worktreePath,
|
||||
connectionId,
|
||||
activeWorktree?.pushTarget,
|
||||
{
|
||||
runtimeTargetSettings: activeRepoSettings
|
||||
}
|
||||
)
|
||||
return
|
||||
}
|
||||
if (kind === 'fast_forward') {
|
||||
@@ -1667,7 +1678,8 @@ function SourceControlInner(): React.JSX.Element {
|
||||
activeWorktreeId,
|
||||
worktreePath,
|
||||
connectionId,
|
||||
activeWorktree?.pushTarget
|
||||
activeWorktree?.pushTarget,
|
||||
{ runtimeTargetSettings: activeRepoSettings }
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -1676,7 +1688,10 @@ function SourceControlInner(): React.JSX.Element {
|
||||
activeWorktreeId,
|
||||
worktreePath,
|
||||
connectionId,
|
||||
activeWorktree?.pushTarget
|
||||
activeWorktree?.pushTarget,
|
||||
{
|
||||
runtimeTargetSettings: activeRepoSettings
|
||||
}
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -1689,11 +1704,14 @@ function SourceControlInner(): React.JSX.Element {
|
||||
worktreePath,
|
||||
effectiveBaseRef,
|
||||
connectionId,
|
||||
activeWorktree?.pushTarget
|
||||
activeWorktree?.pushTarget,
|
||||
{ runtimeTargetSettings: activeRepoSettings }
|
||||
)
|
||||
return
|
||||
}
|
||||
await syncBranch(activeWorktreeId, worktreePath, connectionId, activeWorktree?.pushTarget)
|
||||
await syncBranch(activeWorktreeId, worktreePath, connectionId, activeWorktree?.pushTarget, {
|
||||
runtimeTargetSettings: activeRepoSettings
|
||||
})
|
||||
setRemoteActionErrors((prev) => ({ ...prev, [activeWorktreeId]: null }))
|
||||
} catch (error) {
|
||||
// Why: remote action failures are surfaced by editor-slice actions to keep
|
||||
@@ -1716,6 +1734,7 @@ function SourceControlInner(): React.JSX.Element {
|
||||
}
|
||||
},
|
||||
[
|
||||
activeRepoSettings,
|
||||
activeWorktree?.pushTarget,
|
||||
activeWorktreeId,
|
||||
fetchBranch,
|
||||
@@ -3159,9 +3178,11 @@ function SourceControlInner(): React.JSX.Element {
|
||||
activeWorktreeId,
|
||||
worktreePath,
|
||||
connectionId,
|
||||
activeWorktree?.pushTarget
|
||||
activeWorktree?.pushTarget,
|
||||
{ runtimeTargetSettings: activeRepoSettings }
|
||||
)
|
||||
}, [
|
||||
activeRepoSettings,
|
||||
activeWorktree?.pushTarget,
|
||||
activeWorktreeId,
|
||||
fetchUpstreamStatus,
|
||||
|
||||
@@ -76,7 +76,9 @@ describe('refreshGitStatusForWorktree', () => {
|
||||
})
|
||||
|
||||
expect(deps.setUpstreamStatus).not.toHaveBeenCalled()
|
||||
expect(deps.fetchUpstreamStatus).toHaveBeenCalledWith('wt-1', '/repo', undefined)
|
||||
expect(deps.fetchUpstreamStatus).toHaveBeenCalledWith('wt-1', '/repo', undefined, undefined, {
|
||||
runtimeTargetSettings: undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('falls back to explicit upstream refresh for legacy status payloads', async () => {
|
||||
@@ -103,7 +105,9 @@ describe('refreshGitStatusForWorktree', () => {
|
||||
branch: 'refs/heads/main'
|
||||
})
|
||||
expect(deps.setUpstreamStatus).not.toHaveBeenCalled()
|
||||
expect(deps.fetchUpstreamStatus).toHaveBeenCalledWith('wt-2', '/repo', 'ssh-2')
|
||||
expect(deps.fetchUpstreamStatus).toHaveBeenCalledWith('wt-2', '/repo', 'ssh-2', undefined, {
|
||||
runtimeTargetSettings: undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('leaves ignored-file discovery to the File Explorer instead of status polling', async () => {
|
||||
|
||||
@@ -17,7 +17,8 @@ export type GitStatusRefreshDeps = {
|
||||
worktreeId: string,
|
||||
worktreePath: string,
|
||||
connectionId?: string,
|
||||
pushTarget?: GitPushTarget
|
||||
pushTarget?: GitPushTarget,
|
||||
options?: { runtimeTargetSettings?: Pick<GlobalSettings, 'activeRuntimeEnvironmentId'> | null }
|
||||
) => Promise<void>
|
||||
}
|
||||
|
||||
@@ -56,7 +57,9 @@ export async function refreshGitStatusForWorktree({
|
||||
// Why: porcelain status reports Git's configured upstream. Source Control
|
||||
// actions for PR-created worktrees must instead reconcile with Orca's
|
||||
// explicit publish target.
|
||||
await deps.fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget)
|
||||
await deps.fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget, {
|
||||
runtimeTargetSettings: settings
|
||||
})
|
||||
return
|
||||
}
|
||||
if (status.upstreamStatus) {
|
||||
@@ -68,11 +71,15 @@ export async function refreshGitStatusForWorktree({
|
||||
// Why: porcelain status has counts but cannot tell stale post-rebase
|
||||
// upstream commits from real remote work. Writing it first makes the
|
||||
// primary action flicker between Sync and Force Push on every poll.
|
||||
await deps.fetchUpstreamStatus(worktreeId, worktreePath, connectionId)
|
||||
await deps.fetchUpstreamStatus(worktreeId, worktreePath, connectionId, undefined, {
|
||||
runtimeTargetSettings: settings
|
||||
})
|
||||
return
|
||||
}
|
||||
deps.setUpstreamStatus(worktreeId, status.upstreamStatus)
|
||||
return
|
||||
}
|
||||
await deps.fetchUpstreamStatus(worktreeId, worktreePath, connectionId)
|
||||
await deps.fetchUpstreamStatus(worktreeId, worktreePath, connectionId, undefined, {
|
||||
runtimeTargetSettings: settings
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2098,6 +2098,28 @@ describe('createEditorSlice remote branch actions', () => {
|
||||
expect(toastErrorMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('routes git operations through the explicit runtime owner instead of ambient focus', async () => {
|
||||
const store = createEditorStore()
|
||||
store.setState({ settings: { activeRuntimeEnvironmentId: 'focused-runtime' } as never })
|
||||
|
||||
await store.getState().pushBranch('wt-1', '/repo', false, undefined, undefined, {
|
||||
runtimeTargetSettings: { activeRuntimeEnvironmentId: null }
|
||||
})
|
||||
|
||||
expect(gitPushMock).toHaveBeenCalledWith({
|
||||
worktreePath: '/repo',
|
||||
publish: false,
|
||||
connectionId: undefined,
|
||||
pushTarget: undefined,
|
||||
forceWithLease: undefined
|
||||
})
|
||||
expect(gitUpstreamStatusMock).toHaveBeenCalledWith({
|
||||
worktreePath: '/repo',
|
||||
connectionId: undefined,
|
||||
pushTarget: undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('runs rebase from base and refreshes upstream on success', async () => {
|
||||
const store = createEditorStore()
|
||||
const pushTarget = { remoteName: 'fork', branchName: 'feature' }
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
GitConflictOperation,
|
||||
GitConflictResolutionStatus,
|
||||
GitConflictStatusSource,
|
||||
GlobalSettings,
|
||||
GitPushTarget,
|
||||
GitStatusEntry,
|
||||
GitStatusResult,
|
||||
@@ -240,6 +241,10 @@ type EditorOpenTargetOptions = {
|
||||
runtimeEnvironmentId?: string | null
|
||||
}
|
||||
|
||||
type GitRuntimeOperationOptions = {
|
||||
runtimeTargetSettings?: Pick<GlobalSettings, 'activeRuntimeEnvironmentId'> | null
|
||||
}
|
||||
|
||||
export type PendingEditorReveal = {
|
||||
filePath: string
|
||||
fileId?: string
|
||||
@@ -512,7 +517,8 @@ export type EditorSlice = {
|
||||
worktreeId: string,
|
||||
worktreePath: string,
|
||||
connectionId?: string,
|
||||
pushTarget?: GitPushTarget
|
||||
pushTarget?: GitPushTarget,
|
||||
options?: GitRuntimeOperationOptions
|
||||
) => Promise<void>
|
||||
pushBranch: (
|
||||
worktreeId: string,
|
||||
@@ -520,38 +526,43 @@ export type EditorSlice = {
|
||||
publish?: boolean,
|
||||
connectionId?: string,
|
||||
pushTarget?: GitPushTarget,
|
||||
options?: { forceWithLease?: boolean }
|
||||
options?: GitRuntimeOperationOptions & { forceWithLease?: boolean }
|
||||
) => Promise<void>
|
||||
pullBranch: (
|
||||
worktreeId: string,
|
||||
worktreePath: string,
|
||||
connectionId?: string,
|
||||
pushTarget?: GitPushTarget
|
||||
pushTarget?: GitPushTarget,
|
||||
options?: GitRuntimeOperationOptions
|
||||
) => Promise<void>
|
||||
fastForwardBranch: (
|
||||
worktreeId: string,
|
||||
worktreePath: string,
|
||||
connectionId?: string,
|
||||
pushTarget?: GitPushTarget
|
||||
pushTarget?: GitPushTarget,
|
||||
options?: GitRuntimeOperationOptions
|
||||
) => Promise<void>
|
||||
syncBranch: (
|
||||
worktreeId: string,
|
||||
worktreePath: string,
|
||||
connectionId?: string,
|
||||
pushTarget?: GitPushTarget
|
||||
pushTarget?: GitPushTarget,
|
||||
options?: GitRuntimeOperationOptions
|
||||
) => Promise<void>
|
||||
rebaseFromBase: (
|
||||
worktreeId: string,
|
||||
worktreePath: string,
|
||||
baseRef: string,
|
||||
connectionId?: string,
|
||||
pushTarget?: GitPushTarget
|
||||
pushTarget?: GitPushTarget,
|
||||
options?: GitRuntimeOperationOptions
|
||||
) => Promise<void>
|
||||
fetchBranch: (
|
||||
worktreeId: string,
|
||||
worktreePath: string,
|
||||
connectionId?: string,
|
||||
pushTarget?: GitPushTarget
|
||||
pushTarget?: GitPushTarget,
|
||||
options?: GitRuntimeOperationOptions
|
||||
) => Promise<void>
|
||||
gitBranchChangesByWorktree: Record<string, GitBranchChangeEntry[]>
|
||||
gitBranchCompareSummaryByWorktree: Record<string, GitBranchCompareSummary | null>
|
||||
@@ -3385,11 +3396,12 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
||||
inFlightRemoteOpKind: next > 0 ? s.inFlightRemoteOpKind : null
|
||||
}
|
||||
}),
|
||||
fetchUpstreamStatus: async (worktreeId, worktreePath, connectionId, pushTarget) => {
|
||||
fetchUpstreamStatus: async (worktreeId, worktreePath, connectionId, pushTarget, options) => {
|
||||
try {
|
||||
const runtimeSettings = options?.runtimeTargetSettings ?? get().settings
|
||||
const status = await getRuntimeGitUpstreamStatus(
|
||||
{
|
||||
settings: get().settings,
|
||||
settings: runtimeSettings,
|
||||
worktreeId,
|
||||
worktreePath,
|
||||
connectionId
|
||||
@@ -3428,9 +3440,10 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
||||
publish ? 'publish' : options.forceWithLease === true ? 'force_push' : 'push'
|
||||
)
|
||||
let shouldRefreshAfterRejectedPush = false
|
||||
const runtimeSettings = options.runtimeTargetSettings ?? get().settings
|
||||
try {
|
||||
await pushRuntimeGit(
|
||||
{ settings: get().settings, worktreeId, worktreePath, connectionId },
|
||||
{ settings: runtimeSettings, worktreeId, worktreePath, connectionId },
|
||||
{ publish, pushTarget, forceWithLease: options.forceWithLease }
|
||||
)
|
||||
} catch (error) {
|
||||
@@ -3446,26 +3459,33 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
||||
} finally {
|
||||
get().endRemoteOperation()
|
||||
if (shouldRefreshAfterRejectedPush) {
|
||||
const context = { settings: get().settings, worktreeId, worktreePath, connectionId }
|
||||
const context = { settings: runtimeSettings, worktreeId, worktreePath, connectionId }
|
||||
// Why: the rejected push proved the publish branch moved. Fetch first
|
||||
// so legacy base-tracking worktrees can discover origin/<branch>, then
|
||||
// refresh ahead/behind so Pull/Sync become actionable immediately.
|
||||
void fetchRuntimeGit(context, pushTarget)
|
||||
.catch(() => undefined)
|
||||
.then(() => get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget))
|
||||
.then(() =>
|
||||
get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget, {
|
||||
runtimeTargetSettings: runtimeSettings
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget)
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget, {
|
||||
runtimeTargetSettings: runtimeSettings
|
||||
})
|
||||
const refreshGitHubForWorktree = get().refreshGitHubForWorktree
|
||||
if (typeof refreshGitHubForWorktree === 'function') {
|
||||
refreshGitHubForWorktree(worktreeId)
|
||||
}
|
||||
},
|
||||
pullBranch: async (worktreeId, worktreePath, connectionId, pushTarget) => {
|
||||
pullBranch: async (worktreeId, worktreePath, connectionId, pushTarget, options) => {
|
||||
get().beginRemoteOperation('pull')
|
||||
const runtimeSettings = options?.runtimeTargetSettings ?? get().settings
|
||||
try {
|
||||
await pullRuntimeGit(
|
||||
{ settings: get().settings, worktreeId, worktreePath, connectionId },
|
||||
{ settings: runtimeSettings, worktreeId, worktreePath, connectionId },
|
||||
pushTarget
|
||||
)
|
||||
} catch (error) {
|
||||
@@ -3474,17 +3494,20 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
||||
} finally {
|
||||
get().endRemoteOperation()
|
||||
}
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget)
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget, {
|
||||
runtimeTargetSettings: runtimeSettings
|
||||
})
|
||||
const refreshGitHubForWorktree = get().refreshGitHubForWorktree
|
||||
if (typeof refreshGitHubForWorktree === 'function') {
|
||||
refreshGitHubForWorktree(worktreeId)
|
||||
}
|
||||
},
|
||||
fastForwardBranch: async (worktreeId, worktreePath, connectionId, pushTarget) => {
|
||||
fastForwardBranch: async (worktreeId, worktreePath, connectionId, pushTarget, options) => {
|
||||
get().beginRemoteOperation('fast_forward')
|
||||
const runtimeSettings = options?.runtimeTargetSettings ?? get().settings
|
||||
try {
|
||||
await fastForwardRuntimeGit(
|
||||
{ settings: get().settings, worktreeId, worktreePath, connectionId },
|
||||
{ settings: runtimeSettings, worktreeId, worktreePath, connectionId },
|
||||
pushTarget
|
||||
)
|
||||
} catch (error) {
|
||||
@@ -3493,13 +3516,15 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
||||
} finally {
|
||||
get().endRemoteOperation()
|
||||
}
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget)
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget, {
|
||||
runtimeTargetSettings: runtimeSettings
|
||||
})
|
||||
const refreshGitHubForWorktree = get().refreshGitHubForWorktree
|
||||
if (typeof refreshGitHubForWorktree === 'function') {
|
||||
refreshGitHubForWorktree(worktreeId)
|
||||
}
|
||||
},
|
||||
syncBranch: async (worktreeId, worktreePath, connectionId, pushTarget) => {
|
||||
syncBranch: async (worktreeId, worktreePath, connectionId, pushTarget, options) => {
|
||||
// Why: same shape as pushBranch / pullBranch — fire-and-forget the
|
||||
// post-op upstream refresh after the busy flag clears so the primary
|
||||
// button label rotates immediately when the IPC resolves.
|
||||
@@ -3510,8 +3535,9 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
||||
// outer catch must then skip toasting to avoid a double-toast.
|
||||
let pushStageToastShown = false
|
||||
let pushed = false
|
||||
const runtimeSettings = options?.runtimeTargetSettings ?? get().settings
|
||||
try {
|
||||
const context = { settings: get().settings, worktreeId, worktreePath, connectionId }
|
||||
const context = { settings: runtimeSettings, worktreeId, worktreePath, connectionId }
|
||||
await fetchRuntimeGit(context, pushTarget)
|
||||
const upstreamStatusBeforePull = await getRuntimeGitUpstreamStatus(context, pushTarget)
|
||||
if (shouldForcePushWithLeaseForUpstream(upstreamStatusBeforePull)) {
|
||||
@@ -3556,7 +3582,9 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
||||
} finally {
|
||||
get().endRemoteOperation()
|
||||
}
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget)
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget, {
|
||||
runtimeTargetSettings: runtimeSettings
|
||||
})
|
||||
if (pushed) {
|
||||
const refreshGitHubForWorktree = get().refreshGitHubForWorktree
|
||||
if (typeof refreshGitHubForWorktree === 'function') {
|
||||
@@ -3564,11 +3592,12 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
||||
}
|
||||
}
|
||||
},
|
||||
rebaseFromBase: async (worktreeId, worktreePath, baseRef, connectionId, pushTarget) => {
|
||||
rebaseFromBase: async (worktreeId, worktreePath, baseRef, connectionId, pushTarget, options) => {
|
||||
get().beginRemoteOperation('rebase')
|
||||
const runtimeSettings = options?.runtimeTargetSettings ?? get().settings
|
||||
try {
|
||||
await rebaseRuntimeGitFromBase(
|
||||
{ settings: get().settings, worktreeId, worktreePath, connectionId },
|
||||
{ settings: runtimeSettings, worktreeId, worktreePath, connectionId },
|
||||
baseRef
|
||||
)
|
||||
} catch (error) {
|
||||
@@ -3577,21 +3606,24 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
||||
} finally {
|
||||
get().endRemoteOperation()
|
||||
}
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget)
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget, {
|
||||
runtimeTargetSettings: runtimeSettings
|
||||
})
|
||||
const refreshGitHubForWorktree = get().refreshGitHubForWorktree
|
||||
if (typeof refreshGitHubForWorktree === 'function') {
|
||||
refreshGitHubForWorktree(worktreeId)
|
||||
}
|
||||
},
|
||||
fetchBranch: async (worktreeId, worktreePath, connectionId, pushTarget) => {
|
||||
fetchBranch: async (worktreeId, worktreePath, connectionId, pushTarget, options) => {
|
||||
// Why: same shape as pushBranch / pullBranch — fire-and-forget the
|
||||
// upstream refresh after the busy flag clears. Fetch updates the
|
||||
// remote refs only, so the visible signal we want is the new
|
||||
// ahead/behind counts on the upstream-status payload.
|
||||
get().beginRemoteOperation('fetch')
|
||||
const runtimeSettings = options?.runtimeTargetSettings ?? get().settings
|
||||
try {
|
||||
await fetchRuntimeGit(
|
||||
{ settings: get().settings, worktreeId, worktreePath, connectionId },
|
||||
{ settings: runtimeSettings, worktreeId, worktreePath, connectionId },
|
||||
pushTarget
|
||||
)
|
||||
} catch (error) {
|
||||
@@ -3600,7 +3632,9 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
||||
} finally {
|
||||
get().endRemoteOperation()
|
||||
}
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget)
|
||||
void get().fetchUpstreamStatus(worktreeId, worktreePath, connectionId, pushTarget, {
|
||||
runtimeTargetSettings: runtimeSettings
|
||||
})
|
||||
},
|
||||
gitBranchChangesByWorktree: {},
|
||||
gitBranchCompareSummaryByWorktree: {},
|
||||
|
||||
Reference in New Issue
Block a user