From 106ff20de7d227f01571a59d48a3d73572acef85 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Fri, 10 Apr 2026 08:44:18 -0700 Subject: [PATCH] Fix squash error handling and exit codes Skip unnecessary rollback when reset never happened, show fallback notice when AI commit message generation fails, and exit non-zero when squash produces no changes. --- src/commands/squash.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/commands/squash.ts b/src/commands/squash.ts index 443ced9..0236081 100644 --- a/src/commands/squash.ts +++ b/src/commands/squash.ts @@ -22,9 +22,11 @@ export async function action(branch: string) { const originalHead = await git.headRef(worktree) const spin = spinner("Squashing", branch) + let didReset = false try { await git.resetSoft(base, worktree) + didReset = true spin.text = "Starting container" await vm.ensure((msg) => { spin.text = msg }) @@ -35,7 +37,7 @@ export async function action(branch: string) { if (!diff.trim()) { await git.resetSoft(originalHead, worktree) spin.fail("No changes after squash") - return + process.exit(1) } const gen = await vm.claudePipe( @@ -43,16 +45,23 @@ export async function action(branch: string) { "Write a commit message summarizing all changes. Subject line: imperative mood, max 72 characters, no period. Add a blank line then a concise body with the key changes as bullet points. Output only the raw commit message, no quotes or markdown.", ) + if (gen.exitCode !== 0 || !gen.stdout.trim()) { + spin.text = "AI commit message failed, using fallback" + } const msg = (gen.exitCode === 0 && gen.stdout.trim()) || `squash ${branch}` await git.commit(msg, worktree) spin.succeed(`Squashed ${branch} into a single commit`) } catch (err) { - const restored = await git.resetSoft(originalHead, worktree).then(() => true).catch(() => false) const message = err instanceof Error ? err.message : String(err) - spin.fail(restored - ? `Squash failed, changes restored: ${message}` - : `Squash failed and rollback failed — check "git reflog" in the worktree: ${message}`) + if (!didReset) { + spin.fail(`Squash failed: ${message}`) + } else { + const restored = await git.resetSoft(originalHead, worktree).then(() => true).catch(() => false) + spin.fail(restored + ? `Squash failed, changes restored: ${message}` + : `Squash failed and rollback failed — check "git reflog" in the worktree: ${message}`) + } process.exit(1) } }