From 2b25170c0c2fb654febc761ac738f2c2dc0793b5 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Fri, 20 Mar 2026 22:02:52 -0700 Subject: [PATCH] Handle rebase-in-progress detection via state directories and catch rebase errors REBASE_HEAD can linger after an interrupted rebase, causing false positives. Checking rebase-merge/ and rebase-apply/ directories matches how git itself determines rebase state. Also surface rebase failures in the CLI spinner instead of letting them propagate as unhandled exceptions. --- src/commands/rebase.ts | 8 +++++++- src/git.ts | 7 ++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/commands/rebase.ts b/src/commands/rebase.ts index ff8dda1..bb4a764 100644 --- a/src/commands/rebase.ts +++ b/src/commands/rebase.ts @@ -21,7 +21,13 @@ export async function action(branch: string) { await $`git -C ${root} fetch origin ${main}`.nothrow().quiet() fetchSpin.text = `Rebasing onto origin/${main}` - let conflicts = await git.rebase(`origin/${main}`, worktree) + let conflicts: string[] + try { + conflicts = await git.rebase(`origin/${main}`, worktree) + } catch (err) { + fetchSpin.fail(String((err as Error).message ?? err)) + process.exit(1) + } if (conflicts.length === 0) { fetchSpin.succeed(`Rebased ${branch} onto ${main}`) return diff --git a/src/git.ts b/src/git.ts index 6afb717..06c7928 100644 --- a/src/git.ts +++ b/src/git.ts @@ -153,9 +153,10 @@ export async function abortMerge(cwd: string): Promise { /** Rebase the current branch onto another. Returns conflicted file paths, or empty array if clean. */ export async function rebase(onto: string, cwd: string): Promise { - // Bail early if a rebase is already in progress - const inProgress = await $`git -C ${cwd} rev-parse --verify --quiet REBASE_HEAD`.nothrow().quiet() - if (inProgress.exitCode === 0) { + // Bail early if a rebase is already in progress (check for rebase state directories, not REBASE_HEAD which can be stale) + const rebaseMerge = (await $`git -C ${cwd} rev-parse --git-path rebase-merge`.nothrow().quiet().text()).trim() + const rebaseApply = (await $`git -C ${cwd} rev-parse --git-path rebase-apply`.nothrow().quiet().text()).trim() + if (existsSync(rebaseMerge) || existsSync(rebaseApply)) { throw new Error(`A rebase is already in progress. Run "git -C ${cwd} rebase --abort" to cancel it first.`) }