fix(git): validate refs before worktree creation and improve main branch detection#61
Conversation
…tion validation Introduced a new function to check for the existence of local branches. Enhanced the worktree creation process by validating the start-point reference and handling cases for empty repositories and non-existent branches more gracefully.
There was a problem hiding this comment.
Pull request overview
Improves git-related robustness in the Electron IPC layer by making default-branch detection work in repos without remotes and by validating the start-point ref before creating a new worktree, so users get clearer errors.
Changes:
- Add
localBranchExists()to detectmain/masterviarefs/heads/*when no remote-tracking refs exist. - Update
detectMainBranchUncached()to try remote-tracking refs first, then local branch refs. - Add preflight start-point validation in
createWorktree()with friendlier errors for empty repos and missing base branches.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const isEmptyRepo = await exec('git', ['rev-list', '-n1', '--all'], { cwd: repoRoot }) | ||
| .then(({ stdout }) => !stdout.trim()) | ||
| .catch(() => true); |
There was a problem hiding this comment.
The isEmptyRepo detection treats any failure of git rev-list -n1 --all as an empty repository (catch(() => true)), which can mask other problems (e.g., repoRoot not being a git repo, missing permissions, or git not available) and surface a misleading “no commits” error. Consider only classifying as empty when the command succeeds and returns no output; otherwise rethrow (or throw a more specific “not a git repository”/original git error).
| const isEmptyRepo = await exec('git', ['rev-list', '-n1', '--all'], { cwd: repoRoot }) | |
| .then(({ stdout }) => !stdout.trim()) | |
| .catch(() => true); | |
| let isEmptyRepo = false; | |
| try { | |
| const { stdout } = await exec('git', ['rev-list', '-n1', '--all'], { cwd: repoRoot }); | |
| isEmptyRepo = !stdout.trim(); | |
| } catch (err) { | |
| throw err; | |
| } |
| // Check common default branch names (remote-tracking first, then local) | ||
| for (const candidate of ['main', 'master']) { | ||
| if (await remoteTrackingRefExists(repoRoot, candidate)) return candidate; | ||
| } | ||
| for (const candidate of ['main', 'master']) { | ||
| if (await localBranchExists(repoRoot, candidate)) return candidate; | ||
| } |
There was a problem hiding this comment.
New behavior is introduced in detectMainBranchUncached() (fallback to local refs/heads/*) and createWorktree() (start-point ref validation + custom error messages), but there are no tests in this PR exercising these paths. Since electron/ipc/git.test.ts already mocks git commands, add targeted tests for: (1) no-remote + local main exists => returns main; (2) createWorktree with missing baseBranch in a non-empty repo => throws the new “Branch … does not exist” error; (3) empty repo => throws the new “no commits” error.
|
Thank you very much Generated by Claude Code |
Problem
detectMainBranch()only checks remote-tracking refs (refs/remotes/origin/*) when looking formain/master. In repositories without a remote (or before the first fetch), this causes the detection to fail even though a localmainormasterbranch exists.createWorktree()does not validate that the start-point ref exists before runninggit worktree add. When the ref is missing (e.g. in an empty repo or with a typo), Git produces a cryptic error message that is hard for users to diagnose.Solution
localBranchExists()helper that checksrefs/heads/<branch>.detectMainBranch()to fall back to local branch refs when no remote-tracking ref is found.createWorktree()before attemptinggit worktree add, with clear error messages for: