Skip to content

Commit 08d5771

Browse files
committed
feat: add Repository::merge_base_octopus()
1 parent 60a089c commit 08d5771

File tree

3 files changed

+67
-1
lines changed

3 files changed

+67
-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: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::prelude::ObjectIdExt;
2+
use crate::repository::{merge_base_octopus, merge_base_octopus_with_graph};
13
use crate::revision;
24
#[cfg(feature = "revision")]
35
use crate::{bstr::BStr, Id};
@@ -104,6 +106,38 @@ impl crate::Repository {
104106
.collect())
105107
}
106108

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

0 commit comments

Comments
 (0)