diff --git a/src/commands/new.ts b/src/commands/new.ts index 2d85e7e..2cbee53 100644 --- a/src/commands/new.ts +++ b/src/commands/new.ts @@ -96,6 +96,7 @@ export async function action( die(`Session "${branch}" already exists. Use "sandlot open ${branch}" to re-enter it.`) } + const branchExisted = await git.branchExists(branch, root) const spin = spinner("Creating worktree", branch) try { await git.createWorktree(branch, worktreeAbs, root) diff --git a/src/git.ts b/src/git.ts index 02ecfa1..9a11c51 100644 --- a/src/git.ts +++ b/src/git.ts @@ -49,16 +49,15 @@ export async function createWorktree(branch: string, worktreePath: string, cwd: const exists = await branchExists(branch, cwd, { fetch: true }) let result + let switchedFromBranch = false if (exists === "local") { // If the branch is checked out in the main worktree, switch it to main first if (await currentBranch(cwd) === branch) { - await checkout(await mainBranch(cwd), cwd) - result = await $`git worktree add ${worktreePath} ${branch}`.cwd(cwd).nothrow().quiet() - if (result.exitCode !== 0) { - await $`git checkout ${branch}`.cwd(cwd).nothrow().quiet() - throw new Error(`Failed to create worktree for "${branch}": ${result.stderr.toString().trim()}`) + if (await isDirty(cwd)) { + throw new Error(`Cannot move branch "${branch}" to a worktree: the main worktree has uncommitted changes. Commit or stash them first.`) } - return + await checkout(await mainBranch(cwd), cwd) + switchedFromBranch = true } result = await $`git worktree add ${worktreePath} ${branch}`.cwd(cwd).nothrow().quiet() } else if (exists === "remote") { @@ -68,6 +67,7 @@ export async function createWorktree(branch: string, worktreePath: string, cwd: result = await $`git worktree add -b ${branch} ${worktreePath}`.cwd(cwd).nothrow().quiet() } if (result.exitCode !== 0) { + if (switchedFromBranch) await checkout(branch, cwd).catch(() => {}) throw new Error(`Failed to create worktree for "${branch}": ${result.stderr.toString().trim()}`) } } @@ -238,6 +238,9 @@ export async function branchDiff(branch: string, main: string, cwd: string): Pro /** Detect the main branch name (main or master). */ export async function mainBranch(cwd?: string): Promise { const dir = cwd ?? "." - const result = await $`git -C ${dir} rev-parse --verify --quiet refs/heads/main`.nothrow().quiet() - return result.exitCode === 0 ? "main" : "master" + const main = await $`git -C ${dir} rev-parse --verify --quiet refs/heads/main`.nothrow().quiet() + if (main.exitCode === 0) return "main" + const master = await $`git -C ${dir} rev-parse --verify --quiet refs/heads/master`.nothrow().quiet() + if (master.exitCode === 0) return "master" + throw new Error("Could not detect main branch: neither \"main\" nor \"master\" exists.") }