Files
dirigent/crates/dirigent_projects/src/git/worktree.rs
T
2026-05-08 01:59:04 +02:00

63 lines
2.0 KiB
Rust

//! Worktree workflow implementations.
//!
//! - **follow**: Hard-reset a work branch to track a target branch (e.g. main)
//! - **take**: Squash-merge changes from a worktree branch into a target branch
use crate::error::{ProjectError, Result};
use crate::git::runner::GitRunner;
/// Follow workflow: hard-reset work_branch to match target_branch.
///
/// This is used when a worktree's work branch needs to catch up with
/// the main branch. After this operation, work_branch HEAD will be
/// identical to target_branch HEAD.
///
/// **Destructive**: Discards any uncommitted changes on work_branch.
pub async fn follow(runner: &GitRunner, work_branch: &str, target_branch: &str) -> Result<()> {
// Ensure we're on the work branch
let current = runner.current_branch().await?;
if current != work_branch {
runner.checkout(work_branch).await?;
}
runner.reset_hard(target_branch).await?;
Ok(())
}
/// Take workflow: squash-merge changes from source_branch into target_branch.
///
/// This brings all the work from source_branch into target_branch as a
/// single commit. If `auto_commit` is true, the squash is committed
/// automatically with a generated message.
///
/// Returns the commit hash if auto_commit is true, None otherwise
/// (leaving the changes staged for manual commit).
pub async fn take(
runner: &GitRunner,
source_branch: &str,
target_branch: &str,
auto_commit: bool,
) -> Result<Option<String>> {
// Switch to target branch
let current = runner.current_branch().await?;
if current != target_branch {
runner.checkout(target_branch).await?;
}
// Squash-merge
runner.merge_squash(source_branch).await.map_err(|e| {
ProjectError::Validation(format!(
"squash-merge from '{}' into '{}' failed: {}",
source_branch, target_branch, e
))
})?;
if auto_commit {
let message = format!("Squash merge from {}", source_branch);
let hash = runner.commit(&message).await?;
Ok(Some(hash))
} else {
Ok(None)
}
}