use anyhow::Context;
use color_print::cformat;
use worktrunk::git::{ErrorExt, Repository};
use worktrunk::styling::{eprintln, progress_message, success_message};
use super::super::repository_ext::RepositoryCliExt;
pub enum RebaseResult {
Rebased { target: String, fast_forward: bool },
UpToDate(String),
}
pub fn handle_rebase(target: Option<&str>) -> anyhow::Result<RebaseResult> {
let repo = Repository::current()?;
let integration_target = repo.require_target_ref(target)?;
if repo.is_rebased_onto(&integration_target)? {
return Ok(RebaseResult::UpToDate(integration_target));
}
let merge_base = repo
.merge_base("HEAD", &integration_target)?
.context("Cannot rebase: no common ancestor with target branch")?;
let head_sha = repo.run_command(&["rev-parse", "HEAD"])?.trim().to_string();
let is_fast_forward = merge_base == head_sha;
if !is_fast_forward {
eprintln!(
"{}",
progress_message(cformat!("Rebasing onto <bold>{integration_target}</>..."))
);
}
let rebase_result = repo.run_command(&["rebase", &integration_target]);
if let Err(e) = rebase_result {
let is_rebasing = repo
.worktree_state()?
.is_some_and(|s| s.starts_with("REBASING"));
let detail = e.display_message();
if is_rebasing {
return Err(worktrunk::git::GitError::RebaseConflict {
target_branch: integration_target,
git_output: detail,
}
.into());
}
return Err(worktrunk::git::GitError::Other {
message: cformat!(
"Failed to rebase onto <bold>{}</>: {}",
integration_target,
detail
),
}
.into());
}
if repo.worktree_state()?.is_some() {
return Err(worktrunk::git::GitError::RebaseConflict {
target_branch: integration_target,
git_output: String::new(),
}
.into());
}
let msg = if is_fast_forward {
cformat!("Fast-forwarded to <bold>{integration_target}</>")
} else {
cformat!("Rebased onto <bold>{integration_target}</>")
};
eprintln!("{}", success_message(msg));
Ok(RebaseResult::Rebased {
target: integration_target,
fast_forward: is_fast_forward,
})
}