99 lines
2.8 KiB
Rust
99 lines
2.8 KiB
Rust
use anyhow::Result;
|
|
|
|
use crate::git;
|
|
use crate::spinner::Spinner;
|
|
use crate::vm;
|
|
|
|
use super::helpers::{require_session, resolve_conflicts};
|
|
|
|
const MAX_REBASE_ROUNDS: usize = 10;
|
|
|
|
pub async fn action(branch: &str) -> Result<()> {
|
|
let (root, session) = require_session(branch).await;
|
|
let worktree = &session.worktree;
|
|
|
|
if git::is_dirty(worktree).await {
|
|
crate::fmt::die(&format!(
|
|
"Branch \"{branch}\" has unsaved changes. Run \"sandlot save {branch}\" first."
|
|
));
|
|
}
|
|
|
|
let main = git::main_branch(Some(&root)).await?;
|
|
let fetch_spin = Spinner::new("Fetching origin", Some(branch));
|
|
|
|
// Fetch origin main
|
|
let _ = tokio::process::Command::new("git")
|
|
.args(["-C", &root, "fetch", "origin", &main])
|
|
.stdout(std::process::Stdio::null())
|
|
.stderr(std::process::Stdio::null())
|
|
.output()
|
|
.await;
|
|
|
|
fetch_spin.set_text(&format!("Rebasing onto origin/{main}"));
|
|
|
|
let onto = format!("origin/{main}");
|
|
let mut conflicts = match git::rebase(&onto, worktree).await {
|
|
Ok(c) => c,
|
|
Err(e) => {
|
|
fetch_spin.fail(&e.to_string());
|
|
std::process::exit(1);
|
|
}
|
|
};
|
|
|
|
if conflicts.is_empty() {
|
|
fetch_spin.succeed(&format!("Rebased {branch} onto {main}"));
|
|
return Ok(());
|
|
}
|
|
|
|
fetch_spin.stop();
|
|
println!(
|
|
"\u{25C6} Rebase conflicts in {} file(s). Resolving with Claude...",
|
|
conflicts.len()
|
|
);
|
|
let resolve_spin = Spinner::new("Starting container", Some(branch));
|
|
|
|
let result: Result<()> = async {
|
|
vm::ensure(&|msg| resolve_spin.set_text(msg)).await?;
|
|
vm::set_activity(worktree, branch).await;
|
|
|
|
let mut round = 1usize;
|
|
while !conflicts.is_empty() {
|
|
if round > MAX_REBASE_ROUNDS {
|
|
anyhow::bail!(
|
|
"Exceeded {MAX_REBASE_ROUNDS} conflict resolution rounds \u{2014} aborting rebase"
|
|
);
|
|
}
|
|
|
|
resolve_conflicts(&conflicts, worktree, &|file, i, total| {
|
|
if total > 1 {
|
|
resolve_spin
|
|
.set_text(&format!("({i}/{total}) Resolving {file} (round {round})"));
|
|
} else {
|
|
resolve_spin.set_text(&format!("Resolving {file} (round {round})"));
|
|
}
|
|
})
|
|
.await?;
|
|
|
|
conflicts = git::rebase_continue(worktree).await?;
|
|
round += 1;
|
|
}
|
|
|
|
resolve_spin.succeed(&format!(
|
|
"Rebased {branch} onto {main} (resolved {} conflict round(s))",
|
|
round - 1
|
|
));
|
|
Ok(())
|
|
}
|
|
.await;
|
|
|
|
if let Err(e) = result {
|
|
resolve_spin.fail(&e.to_string());
|
|
git::rebase_abort(worktree).await;
|
|
std::process::exit(1);
|
|
}
|
|
|
|
vm::clear_activity(worktree, branch).await;
|
|
|
|
Ok(())
|
|
}
|