Skip to content

Commit f25a428

Browse files
committed
Add bindings for git_merge_analysis_for_ref
This is a slightly generalised version of git_merge_analysis that allows specifying the ref to analyse against instead of using the repository's current HEAD.
1 parent c7492df commit f25a428

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

libgit2-sys/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -3116,6 +3116,15 @@ extern "C" {
31163116
their_heads_len: usize,
31173117
) -> c_int;
31183118

3119+
pub fn git_merge_analysis_for_ref(
3120+
analysis_out: *mut git_merge_analysis_t,
3121+
pref_out: *mut git_merge_preference_t,
3122+
repo: *mut git_repository,
3123+
git_reference: *mut git_reference,
3124+
their_heads: *mut *const git_annotated_commit,
3125+
their_heads_len: usize,
3126+
) -> c_int;
3127+
31193128
// notes
31203129
pub fn git_note_author(note: *const git_note) -> *const git_signature;
31213130
pub fn git_note_committer(note: *const git_note) -> *const git_signature;

src/repo.rs

+66
Original file line numberDiff line numberDiff line change
@@ -1964,6 +1964,35 @@ impl Repository {
19641964
}
19651965
}
19661966

1967+
/// Analyzes the given branch(es) and determines the opportunities for
1968+
/// merging them into a reference.
1969+
pub fn merge_analysis_for_ref(
1970+
&self,
1971+
our_ref: &Reference<'_>,
1972+
their_heads: &[&AnnotatedCommit<'_>],
1973+
) -> Result<(MergeAnalysis, MergePreference), Error> {
1974+
unsafe {
1975+
let mut raw_merge_analysis = 0 as raw::git_merge_analysis_t;
1976+
let mut raw_merge_preference = 0 as raw::git_merge_preference_t;
1977+
let mut their_heads = their_heads
1978+
.iter()
1979+
.map(|v| v.raw() as *const _)
1980+
.collect::<Vec<_>>();
1981+
try_call!(raw::git_merge_analysis_for_ref(
1982+
&mut raw_merge_analysis,
1983+
&mut raw_merge_preference,
1984+
self.raw,
1985+
our_ref.raw(),
1986+
their_heads.as_mut_ptr() as *mut _,
1987+
their_heads.len()
1988+
));
1989+
Ok((
1990+
MergeAnalysis::from_bits_truncate(raw_merge_analysis as u32),
1991+
MergePreference::from_bits_truncate(raw_merge_preference as u32),
1992+
))
1993+
}
1994+
}
1995+
19671996
/// Initializes a rebase operation to rebase the changes in `branch`
19681997
/// relative to `upstream` onto another branch. To begin the rebase process,
19691998
/// call `next()`.
@@ -3639,4 +3668,41 @@ mod tests {
36393668

36403669
assert!(!config.get_bool("commit.gpgsign").unwrap());
36413670
}
3671+
3672+
#[test]
3673+
fn smoke_merge_analysis_for_ref() -> Result<(), crate::Error> {
3674+
let (_td, repo) = graph_repo_init();
3675+
3676+
// Set up this repo state:
3677+
// * second (their-branch)
3678+
// * initial (HEAD -> main)
3679+
//
3680+
// We expect that their-branch can be fast-forward merged into main.
3681+
3682+
// git checkout --detach HEAD
3683+
let head_commit = repo.head()?.peel_to_commit()?;
3684+
repo.set_head_detached(head_commit.id())?;
3685+
3686+
// git branch their-branch HEAD
3687+
let their_branch = repo.branch("their-branch", &head_commit, false)?;
3688+
3689+
// git branch -f main HEAD~
3690+
let mut parents_iter = head_commit.parents();
3691+
let parent = parents_iter.next().unwrap();
3692+
assert!(parents_iter.next().is_none());
3693+
3694+
let main = repo.branch("main", &parent, true)?;
3695+
3696+
// git checkout main
3697+
repo.set_head(main.get().name().expect("should be utf-8"))?;
3698+
3699+
let (merge_analysis, _merge_preference) = repo.merge_analysis_for_ref(
3700+
main.get(),
3701+
&[&repo.reference_to_annotated_commit(their_branch.get())?],
3702+
)?;
3703+
3704+
assert!(merge_analysis.contains(crate::MergeAnalysis::ANALYSIS_FASTFORWARD));
3705+
3706+
Ok(())
3707+
}
36423708
}

0 commit comments

Comments
 (0)