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, ) -> GitResult { 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, }) } }