Skip to content

Commit 049c5aa

Browse files
committed
feat: add Repository::merge_base_octopus()
1 parent 60a089c commit 049c5aa

File tree

3 files changed

+65
-1
lines changed

3 files changed

+65
-1
lines changed

gix/src/repository/merge.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ impl Repository {
233233
///
234234
/// Note that most of `options` are overwritten to match the requirements of a merge-base merge, but they can be useful
235235
/// to control the diff algorithm or rewrite tracking, for example.
236+
///
237+
/// This method is useful in conjunction with [`Self::merge_trees()`], as the ancestor tree can be produced here.
236238
// TODO: test
237239
pub fn virtual_merge_base(
238240
&self,

gix/src/repository/mod.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ pub mod virtual_merge_base_with_graph {
171171
#[derive(Debug, thiserror::Error)]
172172
#[allow(missing_docs)]
173173
pub enum Error {
174-
#[error("Not commit was provided as merge-base")]
174+
#[error("No commit was provided as merge-base")]
175175
MissingCommit,
176176
#[error(transparent)]
177177
MergeResourceCache(#[from] super::merge_resource_cache::Error),
@@ -186,6 +186,36 @@ pub mod virtual_merge_base_with_graph {
186186
}
187187
}
188188

189+
///
190+
#[cfg(feature = "revision")]
191+
pub mod merge_base_octopus_with_graph {
192+
/// The error returned by [Repository::merge_base_octopus_with_graph()](crate::Repository::merge_base_octopus_with_graph()).
193+
#[derive(Debug, thiserror::Error)]
194+
#[allow(missing_docs)]
195+
pub enum Error {
196+
#[error("No commit was provided")]
197+
MissingCommit,
198+
#[error("No merge base was found between the given commits")]
199+
NoMergeBase,
200+
#[error(transparent)]
201+
MergeBase(#[from] gix_revision::merge_base::Error),
202+
}
203+
}
204+
205+
///
206+
#[cfg(feature = "revision")]
207+
pub mod merge_base_octopus {
208+
/// The error returned by [Repository::merge_base_octopus()](crate::Repository::merge_base_octopus()).
209+
#[derive(Debug, thiserror::Error)]
210+
#[allow(missing_docs)]
211+
pub enum Error {
212+
#[error(transparent)]
213+
OpenCache(#[from] crate::repository::commit_graph_if_enabled::Error),
214+
#[error(transparent)]
215+
MergeBaseOctopus(#[from] super::merge_base_octopus_with_graph::Error),
216+
}
217+
}
218+
189219
///
190220
#[cfg(feature = "merge")]
191221
pub mod tree_merge_options {

gix/src/repository/revision.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::repository::{merge_base_octopus, merge_base_octopus_with_graph};
12
use crate::revision;
23
#[cfg(feature = "revision")]
34
use crate::{bstr::BStr, Id};
@@ -104,6 +105,37 @@ impl crate::Repository {
104105
.collect())
105106
}
106107

108+
/// Return the best merge-base among all `commits`, or fail if `commits` yields no commit or no merge-base was found.
109+
///
110+
/// Use `graph` to speed up repeated calls.
111+
#[cfg(feature = "revision")]
112+
pub fn merge_base_octopus_with_graph(
113+
&self,
114+
commits: impl IntoIterator<Item = impl Into<gix_hash::ObjectId>>,
115+
graph: &mut gix_revwalk::Graph<'_, '_, gix_revwalk::graph::Commit<gix_revision::merge_base::Flags>>,
116+
) -> Result<gix_hash::ObjectId, merge_base_octopus_with_graph::Error> {
117+
let commits: Vec<_> = commits.into_iter().map(Into::into).collect();
118+
let first = commits
119+
.first()
120+
.copied()
121+
.ok_or(merge_base_octopus_with_graph::Error::MissingCommit)?;
122+
gix_revision::merge_base::octopus(first, &commits[1..], graph)?
123+
.ok_or(merge_base_octopus_with_graph::Error::NoMergeBase)
124+
}
125+
126+
/// Return the best merge-base among all `commits`, or fail if `commits` yields no commit or no merge-base was found.
127+
///
128+
/// For repeated calls, prefer [`Self::merge_base_octopus_with_graph()`] for cache-reuse.
129+
#[cfg(feature = "revision")]
130+
pub fn merge_base_octopus(
131+
&self,
132+
commits: impl IntoIterator<Item = impl Into<gix_hash::ObjectId>>,
133+
) -> Result<gix_hash::ObjectId, merge_base_octopus::Error> {
134+
let cache = self.commit_graph_if_enabled()?;
135+
let mut graph = self.revision_graph(cache.as_ref());
136+
Ok(self.merge_base_octopus_with_graph(commits, &mut graph)?)
137+
}
138+
107139
/// Create the baseline for a revision walk by initializing it with the `tips` to start iterating on.
108140
///
109141
/// It can be configured further before starting the actual walk.

0 commit comments

Comments
 (0)