fix(desktop): handle workspace creation for local-only repos#1059
Conversation
- Fix worktree creation failing for repos without a remote - Skip checking origin/* refs when no remote is configured - Add fallback to common branch names (main, master, develop, trunk) when the requested base branch doesn't exist locally - Only use fallback for auto-derived base branches, not explicit ones - Update workspace metadata when fallback branch is used - Show user-friendly progress messages when using fallback - Make error text selectable in workspace init failure view
📝 WalkthroughWalkthroughThe changes enhance workspace initialization by introducing a fallback branch resolution mechanism that attempts multiple sources (origin tracking refs, local branches, common defaults) when the base branch isn't found, with database persistence for selected fallbacks. A minor UI improvement makes error messages more user-friendly. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts`:
- Around line 357-399: When a fetch fails but the remote tracking ref exists
locally (the fetchError branch that checks refExistsLocally(originRef)), add a
progress update so the user is informed we couldn't fetch and are using the
local cached ref; specifically call manager.updateProgress(workspaceId,
"warning" or "fetching", a short title like `Using cached
"${effectiveBaseBranch}"`, and a message that includes a sanitized error from
sanitizeGitError(fetchError) and explains that the local
origin/${effectiveBaseBranch} will be used until a manual git fetch succeeds).
Place this update inside the catch after confirming refExistsLocally and before
continuing to use startPoint (and before any resolveLocalStartPoint logic) so
callers of applyFallbackBranch/startPoint see the warning.
🧹 Nitpick comments (2)
apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts (2)
187-190: Consider moving the type to module scope.Defining
LocalStartPointResultinside the function limits visibility and makes it harder to unit testresolveLocalStartPointseparately if needed later. Moving it to the top of the file improves discoverability.
192-195: Consider using a params object for clarity.Per coding guidelines, functions with 2+ parameters should use a named params object. The
checkOriginRefsboolean also creates slight "boolean blindness" at call sites (e.g.,resolveLocalStartPoint("...", true)).Additionally, the
commonBranchesarray could be extracted to a module-level constant.♻️ Suggested refactor
+const COMMON_DEFAULT_BRANCHES = ["main", "master", "develop", "trunk"] as const; + // Inside the function: -const resolveLocalStartPoint = async ( - reason: string, - checkOriginRefs: boolean, -): Promise<LocalStartPointResult> => { +const resolveLocalStartPoint = async ({ + reason, + checkOriginRefs, +}: { + reason: string; + checkOriginRefs: boolean; +}): Promise<LocalStartPointResult> => { // ... - const commonBranches = ["main", "master", "develop", "trunk"]; + for (const branch of COMMON_DEFAULT_BRANCHES) {As per coding guidelines: "Functions with 2+ parameters should accept a single params object with named properties instead of positional arguments".
Also applies to: 224-224
| } catch (fetchError) { | ||
| // Fetch failed - verify local tracking ref exists before proceeding | ||
| const originRef = `origin/${effectiveBaseBranch}`; | ||
| if (!(await refExistsLocally(mainRepoPath, originRef))) { | ||
| console.warn( | ||
| `[workspace-init] Fetch failed and local ref "${originRef}" doesn't exist. Attempting local fallback.`, | ||
| ); | ||
| const localResult = await resolveLocalStartPoint( | ||
| "Fetch failed and remote tracking ref unavailable", | ||
| true, | ||
| ); | ||
| if (!localResult) { | ||
| const sanitizedError = sanitizeGitError( | ||
| fetchError instanceof Error | ||
| ? fetchError.message | ||
| : String(fetchError), | ||
| ); | ||
| manager.updateProgress( | ||
| workspaceId, | ||
| "failed", | ||
| "Cannot fetch branch", | ||
| baseBranchWasExplicit | ||
| ? `Failed to fetch "${effectiveBaseBranch}" and it doesn't exist locally. ` + | ||
| `Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` + | ||
| `Error: ${sanitizedError}` | ||
| : `Failed to fetch "${effectiveBaseBranch}" and no local reference exists. ` + | ||
| `Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` + | ||
| `Error: ${sanitizedError}`, | ||
| ); | ||
| return; | ||
| } | ||
| if (localResult.fallbackBranch) { | ||
| applyFallbackBranch(localResult.fallbackBranch); | ||
| manager.updateProgress( | ||
| workspaceId, | ||
| "fetching", | ||
| `Using "${localResult.fallbackBranch}" branch`, | ||
| `Could not fetch "${baseBranch}". Using local "${localResult.fallbackBranch}" branch instead.`, | ||
| ); | ||
| } | ||
| startPoint = localResult.ref; | ||
| } | ||
| } |
There was a problem hiding this comment.
Silent continuation when fetch fails but local ref exists.
When fetchDefaultBranch fails but originRef exists locally, the code silently continues using the potentially stale local ref. The user sees "Fetching latest changes..." but isn't informed that fetch failed and they're working from cached data.
Consider adding a progress message to warn users, similar to the fallback paths:
🛠️ Suggested improvement
} catch (fetchError) {
// Fetch failed - verify local tracking ref exists before proceeding
const originRef = `origin/${effectiveBaseBranch}`;
if (!(await refExistsLocally(mainRepoPath, originRef))) {
// ... existing fallback logic
+ } else {
+ const sanitizedError = sanitizeGitError(
+ fetchError instanceof Error ? fetchError.message : String(fetchError),
+ );
+ console.warn(
+ `[workspace-init] Fetch failed but local ref "${originRef}" exists. Proceeding with local ref. Error: ${sanitizedError}`,
+ );
+ manager.updateProgress(
+ workspaceId,
+ "fetching",
+ "Using cached reference",
+ `Could not fetch latest changes. Using local "${effectiveBaseBranch}" reference.`,
+ );
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| } catch (fetchError) { | |
| // Fetch failed - verify local tracking ref exists before proceeding | |
| const originRef = `origin/${effectiveBaseBranch}`; | |
| if (!(await refExistsLocally(mainRepoPath, originRef))) { | |
| console.warn( | |
| `[workspace-init] Fetch failed and local ref "${originRef}" doesn't exist. Attempting local fallback.`, | |
| ); | |
| const localResult = await resolveLocalStartPoint( | |
| "Fetch failed and remote tracking ref unavailable", | |
| true, | |
| ); | |
| if (!localResult) { | |
| const sanitizedError = sanitizeGitError( | |
| fetchError instanceof Error | |
| ? fetchError.message | |
| : String(fetchError), | |
| ); | |
| manager.updateProgress( | |
| workspaceId, | |
| "failed", | |
| "Cannot fetch branch", | |
| baseBranchWasExplicit | |
| ? `Failed to fetch "${effectiveBaseBranch}" and it doesn't exist locally. ` + | |
| `Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` + | |
| `Error: ${sanitizedError}` | |
| : `Failed to fetch "${effectiveBaseBranch}" and no local reference exists. ` + | |
| `Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` + | |
| `Error: ${sanitizedError}`, | |
| ); | |
| return; | |
| } | |
| if (localResult.fallbackBranch) { | |
| applyFallbackBranch(localResult.fallbackBranch); | |
| manager.updateProgress( | |
| workspaceId, | |
| "fetching", | |
| `Using "${localResult.fallbackBranch}" branch`, | |
| `Could not fetch "${baseBranch}". Using local "${localResult.fallbackBranch}" branch instead.`, | |
| ); | |
| } | |
| startPoint = localResult.ref; | |
| } | |
| } | |
| } catch (fetchError) { | |
| // Fetch failed - verify local tracking ref exists before proceeding | |
| const originRef = `origin/${effectiveBaseBranch}`; | |
| if (!(await refExistsLocally(mainRepoPath, originRef))) { | |
| console.warn( | |
| `[workspace-init] Fetch failed and local ref "${originRef}" doesn't exist. Attempting local fallback.`, | |
| ); | |
| const localResult = await resolveLocalStartPoint( | |
| "Fetch failed and remote tracking ref unavailable", | |
| true, | |
| ); | |
| if (!localResult) { | |
| const sanitizedError = sanitizeGitError( | |
| fetchError instanceof Error | |
| ? fetchError.message | |
| : String(fetchError), | |
| ); | |
| manager.updateProgress( | |
| workspaceId, | |
| "failed", | |
| "Cannot fetch branch", | |
| baseBranchWasExplicit | |
| ? `Failed to fetch "${effectiveBaseBranch}" and it doesn't exist locally. ` + | |
| `Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` + | |
| `Error: ${sanitizedError}` | |
| : `Failed to fetch "${effectiveBaseBranch}" and no local reference exists. ` + | |
| `Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` + | |
| `Error: ${sanitizedError}`, | |
| ); | |
| return; | |
| } | |
| if (localResult.fallbackBranch) { | |
| applyFallbackBranch(localResult.fallbackBranch); | |
| manager.updateProgress( | |
| workspaceId, | |
| "fetching", | |
| `Using "${localResult.fallbackBranch}" branch`, | |
| `Could not fetch "${baseBranch}". Using local "${localResult.fallbackBranch}" branch instead.`, | |
| ); | |
| } | |
| startPoint = localResult.ref; | |
| } else { | |
| const sanitizedError = sanitizeGitError( | |
| fetchError instanceof Error ? fetchError.message : String(fetchError), | |
| ); | |
| console.warn( | |
| `[workspace-init] Fetch failed but local ref "${originRef}" exists. Proceeding with local ref. Error: ${sanitizedError}`, | |
| ); | |
| manager.updateProgress( | |
| workspaceId, | |
| "fetching", | |
| "Using cached reference", | |
| `Could not fetch latest changes. Using local "${effectiveBaseBranch}" reference.`, | |
| ); | |
| } | |
| } |
🤖 Prompt for AI Agents
In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts` around
lines 357 - 399, When a fetch fails but the remote tracking ref exists locally
(the fetchError branch that checks refExistsLocally(originRef)), add a progress
update so the user is informed we couldn't fetch and are using the local cached
ref; specifically call manager.updateProgress(workspaceId, "warning" or
"fetching", a short title like `Using cached "${effectiveBaseBranch}"`, and a
message that includes a sanitized error from sanitizeGitError(fetchError) and
explains that the local origin/${effectiveBaseBranch} will be used until a
manual git fetch succeeds). Place this update inside the catch after confirming
refExistsLocally and before continuing to use startPoint (and before any
resolveLocalStartPoint logic) so callers of applyFallbackBranch/startPoint see
the warning.
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
Summary
origin/*refs when no remote is configuredProblem
When creating a workspace for a local-only git repository (no remote configured), the workspace initialization would fail with:
This happened because the code was trying to use
origin/<branch>as the start point even when no origin remote existed.Solution
checkOriginRefsparameter toresolveLocalStartPoint()to skiporigin/*refs when there's no remoteTest plan
masterbranch (no remote)masterbranchSummary by CodeRabbit
Release Notes
Bug Fixes
UI/UX
✏️ Tip: You can customize this high-level summary in your review settings.