//! Cherry-pick operations. use crate::commit::types::*; use crate::{GitDomain, GitError, GitResult}; impl GitDomain { pub fn commit_cherry_pick( &self, cherrypick_oid: &CommitOid, author: &CommitSignature, committer: &CommitSignature, message: Option<&str>, mainline: u32, update_ref: Option<&str>, ) -> GitResult { let cherrypick_commit = self .repo() .find_commit(cherrypick_oid.to_oid()?) .map_err(|_e| GitError::ObjectNotFound(cherrypick_oid.to_string()))?; let head_oid = self .repo() .head() .ok() .and_then(|r| r.target()) .ok_or_else(|| GitError::Internal("HEAD is not attached".to_string()))?; let our_commit = self .repo() .find_commit(head_oid) .map_err(|e| GitError::Internal(e.to_string()))?; let mut index = self .repo() .cherrypick_commit(&cherrypick_commit, &our_commit, mainline, None) .map_err(|e| GitError::Internal(e.to_string()))?; let tree_oid = index .write_tree_to(&*self.repo()) .map_err(|e| GitError::Internal(e.to_string()))?; let tree = self .repo() .find_tree(tree_oid) .map_err(|e| GitError::Internal(e.to_string()))?; let msg = message.map(String::from).unwrap_or_else(|| { format!( "cherry-pick commit {}", &cherrypick_oid.to_string()[..8.min(cherrypick_oid.to_string().len())] ) }); let author = self.commit_signature_to_git2(author)?; let committer = self.commit_signature_to_git2(committer)?; let oid = self .repo() .commit(update_ref, &author, &committer, &msg, &tree, &[&our_commit]) .map_err(|e| GitError::Internal(e.to_string()))?; Ok(CommitOid::from_git2(oid)) } pub fn commit_cherry_pick_sequence( &self, cherrypick_oids: &[CommitOid], author: &CommitSignature, committer: &CommitSignature, update_ref: Option<&str>, ) -> GitResult { let mut last_oid: Option = None; for oid in cherrypick_oids { last_oid = Some(self.commit_cherry_pick(oid, author, committer, None, 0, update_ref)?); } last_oid.ok_or_else(|| GitError::Internal("no commits to cherry-pick".to_string())) } pub fn commit_cherry_pick_abort(&self, reset_type: &str) -> GitResult<()> { let kind = match reset_type { "soft" => git2::ResetType::Soft, "mixed" => git2::ResetType::Mixed, "hard" => git2::ResetType::Hard, _ => { return Err(GitError::Internal(format!( "unknown reset type: {}", reset_type ))); } }; let head_oid = self .repo() .head() .ok() .and_then(|r| r.target()) .ok_or_else(|| GitError::Internal("HEAD is not attached".to_string()))?; let obj = self .repo() .find_object(head_oid, None) .map_err(|e| GitError::Internal(e.to_string()))?; self.repo .reset(&obj, kind, None) .map_err(|e| GitError::Internal(e.to_string())) } }