use std::cell::RefCell;
use git2::{build::CheckoutBuilder, Repository};
use crate::error::{CheckoutError, Result};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CheckoutOutcome {
Clean,
Conflict { paths: Vec<String> },
}
pub fn checkout_branch_in_worktree(wt_repo: &Repository, branch: &str) -> Result<CheckoutOutcome> {
let branch_ref = wt_repo
.find_branch(branch, git2::BranchType::Local)
.map_err(|_| CheckoutError::BranchNotFound {
branch: branch.to_string(),
})?;
let target_commit = branch_ref
.get()
.peel_to_commit()
.map_err(CheckoutError::Git)?;
let target_tree = target_commit.tree().map_err(CheckoutError::Git)?;
let conflicts: RefCell<Vec<String>> = RefCell::new(Vec::new());
let mut builder = CheckoutBuilder::new();
builder.safe();
builder.notify_on(git2::CheckoutNotificationType::CONFLICT);
builder.notify(|_kind, path, _baseline, _target, _workdir| {
if let Some(p) = path {
if let Some(s) = p.to_str() {
conflicts.borrow_mut().push(s.to_string());
}
}
true });
match wt_repo.checkout_tree(target_tree.as_object(), Some(&mut builder)) {
Ok(()) => {}
Err(e) if e.code() == git2::ErrorCode::Conflict => {
return Ok(CheckoutOutcome::Conflict {
paths: conflicts.take(),
});
}
Err(e) => return Err(CheckoutError::Git(e).into()),
}
wt_repo
.set_head(&format!("refs/heads/{}", branch))
.map_err(CheckoutError::Git)?;
Ok(CheckoutOutcome::Clean)
}