58 lines
1.8 KiB
TypeScript
58 lines
1.8 KiB
TypeScript
import { $ } from "bun"
|
|
import * as git from "../git.ts"
|
|
import * as vm from "../vm.ts"
|
|
import { spinner } from "../spinner.ts"
|
|
import { die } from "../fmt.ts"
|
|
import { requireSession, resolveConflicts } from "./helpers.ts"
|
|
|
|
const MAX_REBASE_ROUNDS = 10
|
|
|
|
export async function action(branch: string) {
|
|
const { root, session } = await requireSession(branch)
|
|
const worktree = session.worktree
|
|
|
|
if (await git.isDirty(worktree)) {
|
|
die(`Branch "${branch}" has unsaved changes. Run "sandlot save ${branch}" first.`)
|
|
}
|
|
|
|
const main = await git.mainBranch(root)
|
|
const fetchSpin = spinner("Fetching origin", branch)
|
|
|
|
await $`git -C ${root} fetch origin ${main}`.nothrow().quiet()
|
|
fetchSpin.text = `Rebasing onto origin/${main}`
|
|
|
|
let conflicts = await git.rebase(`origin/${main}`, worktree)
|
|
if (conflicts.length === 0) {
|
|
fetchSpin.succeed(`Rebased ${branch} onto ${main}`)
|
|
return
|
|
}
|
|
|
|
fetchSpin.stop()
|
|
console.log(`◆ Rebase conflicts in ${conflicts.length} file(s). Resolving with Claude...`)
|
|
const resolveSpin = spinner("Starting container", branch)
|
|
|
|
try {
|
|
await vm.ensure((msg) => { resolveSpin.text = msg })
|
|
|
|
let round = 1
|
|
while (conflicts.length > 0) {
|
|
if (round > MAX_REBASE_ROUNDS) {
|
|
throw new Error(`Exceeded ${MAX_REBASE_ROUNDS} conflict resolution rounds — aborting rebase`)
|
|
}
|
|
|
|
await resolveConflicts(conflicts, worktree, (file) => {
|
|
resolveSpin.text = `Resolving ${file} (round ${round})`
|
|
})
|
|
|
|
conflicts = await git.rebaseContinue(worktree)
|
|
round++
|
|
}
|
|
|
|
resolveSpin.succeed(`Rebased ${branch} onto ${main} (resolved ${round - 1} conflict round(s))`)
|
|
} catch (err) {
|
|
resolveSpin.fail(String((err as Error).message ?? err))
|
|
await git.rebaseAbort(worktree)
|
|
process.exit(1)
|
|
}
|
|
}
|