use crate::bare::GitBare; use crate::error::GitResult; use crate::pb::{CheckMergeRequest, MergeResult, merge_result}; impl GitBare { pub fn check_merge(&self, request: CheckMergeRequest) -> GitResult { let target = match request.target.and_then(|s| s.selector) { Some(crate::pb::object_selector::Selector::Oid(oid)) => oid.hex, Some(crate::pb::object_selector::Selector::Revision(name)) => name.revision, None => "HEAD".into(), }; let source = match request.source.and_then(|s| s.selector) { Some(crate::pb::object_selector::Selector::Oid(oid)) => oid.hex, Some(crate::pb::object_selector::Selector::Revision(name)) => name.revision, None => "HEAD".into(), }; let repo = self.gix_repo()?; let target_id = repo.rev_parse_single(target.as_str())?; let source_id = repo.rev_parse_single(source.as_str())?; if target_id == source_id { return Ok(MergeResult { status: merge_result::Status::MergeResultStatusAlreadyUpToDate as i32, commit: None, merge_base: Some(self.oid_to_pb(target_id.to_string())), conflicts: vec![], stats: None, message: String::from("Already up to date"), }); } let merge_base = repo .merge_base(target_id.detach(), source_id.detach()) .ok() .map(|id| id.to_string()); if let Some(ref base) = merge_base { if *base == target_id.to_string() { return Ok(MergeResult { status: merge_result::Status::MergeResultStatusFastForward as i32, commit: None, merge_base: Some(self.oid_to_pb(base.clone())), conflicts: vec![], stats: None, message: String::from("Fast-forward"), }); } if *base == source_id.to_string() { return Ok(MergeResult { status: merge_result::Status::MergeResultStatusAlreadyUpToDate as i32, commit: None, merge_base: Some(self.oid_to_pb(base.clone())), conflicts: vec![], stats: None, message: String::from("Already up to date"), }); } } let merge_base_oid = merge_base.as_ref().map(|b| self.oid_to_pb(b.clone())); let result = duct::cmd( "git", [ "--git-dir", self.bare_dir.to_string_lossy().as_ref(), "merge-tree", "--write-tree", "--no-messages", "-z", &target, &source, ], ) .stdout_capture() .stderr_capture() .unchecked() .run()?; let stdout = String::from_utf8_lossy(&result.stdout).into_owned(); if result.status.success() { Ok(MergeResult { status: merge_result::Status::MergeResultStatusMerged as i32, commit: None, merge_base: merge_base_oid, conflicts: vec![], stats: None, message: stdout.trim().to_string(), }) } else { let conflicts = stdout .split('\0') .filter(|s| !s.is_empty()) .map(|path| crate::pb::MergeConflict { path: path.to_string(), ..Default::default() }) .collect(); Ok(MergeResult { status: merge_result::Status::MergeResultStatusConflicts as i32, commit: None, merge_base: merge_base_oid, conflicts, stats: None, message: String::from("Merge conflicts detected"), }) } } }