gitdataai/lib/git/cmd/merge/merge_tree.rs
2026-05-30 01:38:40 +08:00

77 lines
2.2 KiB
Rust

use serde::{Deserialize, Serialize};
use crate::{
bare::GitBare,
cmd::{merge::MergeOptions, oid::ObjectId},
errors::{GitError, GitResult},
};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MergeTreeResult {
pub tree_id: ObjectId,
pub has_conflicts: bool,
}
impl GitBare {
pub fn merge_tree(
&self,
ours: ObjectId,
theirs: ObjectId,
options: Option<MergeOptions>,
) -> GitResult<MergeTreeResult> {
let mut args =
vec!["merge-tree".to_string(), "--write-tree".to_string()];
if let Some(opts) = &options {
if opts.find_renames {
args.push("--find-renames".to_string());
if opts.rename_threshold > 0 {
args.push(format!(
"--rename-threshold={}",
opts.rename_threshold
));
}
}
if opts.fail_on_conflict {
args.push("--fail-on-conflict".to_string());
}
if opts.no_recursive {
args.push("--no-recursive".to_string());
}
if opts.target_limit > 0 {
args.push(format!("--target-limit={}", opts.target_limit));
}
}
args.push(ours.as_str().to_string());
args.push(theirs.as_str().to_string());
let output = self.git_command_with(
crate::cmd::command::GitCommandParams::new(args).unchecked(),
)?;
let stdout = output.stdout_lossy();
let mut lines = stdout.lines();
let tree_oid_str = lines.next().unwrap_or("").trim();
if tree_oid_str.is_empty() {
if !output.success {
return Err(GitError::CommandFailed {
status_code: output.status_code,
stderr: output.stderr_lossy(),
});
}
return Err(GitError::ParseError(
"merge-tree produced no tree OID output".to_string(),
));
}
let has_conflicts =
!output.success || lines.any(|l| !l.trim().is_empty());
Ok(MergeTreeResult {
tree_id: ObjectId::new(tree_oid_str),
has_conflicts,
})
}
}