-
Notifications
You must be signed in to change notification settings - Fork 542
Description
Summary
The worktree branch switching endpoint incorrectly blocks switching when there are untracked files (?? status). It should only block when there are modifications to tracked files that could be lost during checkout.
Steps to Reproduce
- Create a new project with
ensureInitialCommit()(empty initial commit) - Have untracked directories like
.automaker/,.claude/, etc. - Generate features with
branchNamefields (creates worktrees) - Try to switch to a worktree branch via the UI
Expected Behavior
Branch switch succeeds. Untracked files are safe - git leaves them alone during checkout.
Actual Behavior
Error: Cannot switch branches: you have uncommitted changes (?? .automaker/, ?? .claude/, ?? .cursor/, ...). Please commit your changes first.
Root Cause
In apps/server/src/routes/worktree/routes/switch-branch.ts, the hasUncommittedChanges() function (lines 23-39) treats ALL git status --porcelain output as blocking changes:
async function hasUncommittedChanges(cwd: string): Promise<boolean> {
const { stdout } = await execAsync('git status --porcelain', { cwd });
const lines = stdout.trim().split('\n').filter((line) => {
if (!line.trim()) return false;
if (line.includes('.worktrees/')) return false; // Only excludes .worktrees/
return true;
});
return lines.length > 0; // ANY remaining output = blocked
}The code doesn't distinguish between:
??(untracked files) - safe to switchM,A,D, etc. (modifications to tracked files) - should block
Suggested Fix
Filter out untracked files from the check:
const lines = stdout.trim().split('\n').filter((line) => {
if (!line.trim()) return false;
if (line.startsWith('??')) return false; // Untracked files are safe
if (line.includes('.worktrees/')) return false;
return true;
});Alternatively, use git status --porcelain --untracked-files=no to exclude untracked files from the output entirely.