Skip to content

fix(desktop): handle workspace creation for local-only repos#1059

Merged
Kitenite merged 1 commit into
mainfrom
new-ws-issue
Jan 31, 2026
Merged

fix(desktop): handle workspace creation for local-only repos#1059
Kitenite merged 1 commit into
mainfrom
new-ws-issue

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Jan 29, 2026

Summary

  • Fix worktree creation failing for repos without a remote configured
  • 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 user-specified ones
  • Update workspace metadata when a fallback branch is used
  • Show user-friendly progress messages when using fallback branch
  • Make error text selectable in workspace init failure view

Problem

When creating a workspace for a local-only git repository (no remote configured), the workspace initialization would fail with:

fatal: invalid reference: origin/main^{commit}

This happened because the code was trying to use origin/<branch> as the start point even when no origin remote existed.

Solution

  • Added a checkOriginRefs parameter to resolveLocalStartPoint() to skip origin/* refs when there's no remote
  • When no remote exists, directly use the local branch as the start point
  • Fallback logic only triggers for auto-derived base branches to avoid silently changing explicitly user-specified branches

Test plan

  • Create a local-only repo with master branch (no remote)
  • Import the repo and create a workspace
  • Verify workspace creates successfully using local master branch

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved workspace initialization with enhanced branch resolution and fallback handling to reduce setup failures.
    • Strengthened error handling for fetch failures during workspace setup.
  • UI/UX

    • Error messages are now selectable and display with improved text wrapping for better readability.

✏️ Tip: You can customize this high-level summary in your review settings.

- 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
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 29, 2026

📝 Walkthrough

Walkthrough

The 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

Cohort / File(s) Summary
Workspace Initialization Logic
apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts
Introduces LocalStartPointResult type and applyFallbackBranch helper. Extends resolution flow with fallback sequence: origin tracking refs → local base branch → common defaults (main, master, develop, trunk). Updates multiple code paths for remote-unavailable, remote-configured, and no-remote scenarios. Enhances error handling for fetch failures with fallback support and persists selected fallback to database.
UI Error Display
apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceInitializingView/WorkspaceInitializingView.tsx
Adds CSS classes (select-text, cursor-text, break-words) to error message paragraph for improved text selectability and wrapping.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 A fallback path for every need,
When branches hide, we plant a seed!
Main, master, develop—all in line,
Origins checked, persistence divine.
Now errors shine with selectable grace! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fixing workspace creation for local-only repositories, which is the primary issue being addressed in this pull request.
Description check ✅ Passed The description provides a comprehensive summary of changes, clearly identifies the problem and solution, and includes a test plan, though it deviates from the repository's template structure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 LocalStartPointResult inside the function limits visibility and makes it harder to unit test resolveLocalStartPoint separately 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 checkOriginRefs boolean also creates slight "boolean blindness" at call sites (e.g., resolveLocalStartPoint("...", true)).

Additionally, the commonBranches array 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

Comment on lines +357 to 399
} 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;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
} 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.

@Kitenite Kitenite merged commit ebdc2ee into main Jan 31, 2026
5 checks passed
@Kitenite Kitenite deleted the new-ws-issue branch January 31, 2026 00:44
@github-actions
Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ⚠️ Neon database branch
  • ⚠️ Electric Fly.io app

Thank you for your contribution! 🎉

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