From f1825c65da7ef0b38d46b3ecd5fc0451d0c4b8e1 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Fri, 10 Apr 2026 08:19:58 -0700 Subject: [PATCH] Move reset into try block so rollback covers all failure paths Hoist mainBranch lookup before the new-commits check to avoid a duplicate call, and report clearly when rollback itself fails so the user knows to consult git reflog. --- src/commands/squash.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/commands/squash.ts b/src/commands/squash.ts index 6ab91c5..443ced9 100644 --- a/src/commands/squash.ts +++ b/src/commands/squash.ts @@ -12,20 +12,20 @@ export async function action(branch: string) { die(`Branch "${branch}" has unsaved changes. Run "sandlot save ${branch}" first.`) } + const main = await git.mainBranch(worktree) + if (!await git.hasNewCommits(worktree)) { - const main = await git.mainBranch(worktree) die(`Branch "${branch}" has no commits beyond ${main}.`) } - const main = await git.mainBranch(worktree) const base = await git.mergeBase(main, "HEAD", worktree) const originalHead = await git.headRef(worktree) const spin = spinner("Squashing", branch) - await git.resetSoft(base, worktree) - try { + await git.resetSoft(base, worktree) + spin.text = "Starting container" await vm.ensure((msg) => { spin.text = msg }) @@ -43,17 +43,16 @@ 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()) { - await git.commit(gen.stdout.trim(), worktree) - } else { - await git.commit(`squash ${branch}`, worktree) - } + 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) { - await git.resetSoft(originalHead, worktree).catch(() => {}) + const restored = await git.resetSoft(originalHead, worktree).then(() => true).catch(() => false) const message = err instanceof Error ? err.message : String(err) - spin.fail(`Squash failed, changes restored: ${message}`) + spin.fail(restored + ? `Squash failed, changes restored: ${message}` + : `Squash failed and rollback failed — check "git reflog" in the worktree: ${message}`) process.exit(1) } }