use crate::bare::GitBare; use crate::error::{GitError, GitResult}; use crate::pb::{CompareBranchRequest, CompareBranchResponse}; impl GitBare { pub fn compare_branch( &self, request: CompareBranchRequest, ) -> GitResult { crate::sanitize::validate_ref_name(&request.source_branch)?; crate::sanitize::validate_ref_name(&request.target_branch)?; let repo = self.gix_repo()?; let source_ref = format!("refs/heads/{}", request.source_branch); let target_ref = format!("refs/heads/{}", request.target_branch); let source_id = repo.find_reference(source_ref.as_str())?.peel_to_id()?; let target_id = repo.find_reference(target_ref.as_str())?.peel_to_id()?; let source_hex = source_id.to_string(); let target_hex = target_id.to_string(); let merge_base = repo .merge_base(source_id.detach(), target_id.detach()) .ok() .map(|id| self.oid_to_pb(id.to_string())); let result = duct::cmd( "git", [ "--git-dir", self.bare_dir.to_string_lossy().as_ref(), "rev-list", "--left-right", "--count", &format!("{}...{}", source_hex, target_hex), ], ) .stdout_capture() .stderr_capture() .unchecked() .run()?; if !result.status.success() { return Err(GitError::CommandFailed { status_code: result.status.code(), stderr: String::from_utf8_lossy(&result.stderr).into_owned(), }); } let output = String::from_utf8_lossy(&result.stdout); let parts: Vec<&str> = output.split_whitespace().collect(); let ahead_by = parts.first().and_then(|s| s.parse().ok()).unwrap_or(0); let behind_by = parts.get(1).and_then(|s| s.parse().ok()).unwrap_or(0); Ok(CompareBranchResponse { ahead: ahead_by > 0, behind: behind_by > 0, ahead_by, behind_by, merge_base, }) } }