Skip to content

Commit

Permalink
feat: add Repository::merge_base_octopus()
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Nov 7, 2024
1 parent 0d64f3a commit 65ae68e
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 1 deletion.
2 changes: 2 additions & 0 deletions gix/src/repository/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ impl Repository {
///
/// Note that most of `options` are overwritten to match the requirements of a merge-base merge, but they can be useful
/// to control the diff algorithm or rewrite tracking, for example.
///
/// This method is useful in conjunction with [`Self::merge_trees()`], as the ancestor tree can be produced here.
// TODO: test
pub fn virtual_merge_base(
&self,
Expand Down
32 changes: 31 additions & 1 deletion gix/src/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ pub mod virtual_merge_base_with_graph {
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error("Not commit was provided as merge-base")]
#[error("No commit was provided as merge-base")]
MissingCommit,
#[error(transparent)]
MergeResourceCache(#[from] super::merge_resource_cache::Error),
Expand All @@ -186,6 +186,36 @@ pub mod virtual_merge_base_with_graph {
}
}

///
#[cfg(feature = "revision")]
pub mod merge_base_octopus_with_graph {
/// The error returned by [Repository::merge_base_octopus_with_graph()](crate::Repository::merge_base_octopus_with_graph()).
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error("No commit was provided")]
MissingCommit,
#[error("No merge base was found between the given commits")]
NoMergeBase,
#[error(transparent)]
MergeBase(#[from] gix_revision::merge_base::Error),
}
}

///
#[cfg(feature = "revision")]
pub mod merge_base_octopus {
/// The error returned by [Repository::merge_base_octopus()](crate::Repository::merge_base_octopus()).
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
OpenCache(#[from] crate::repository::commit_graph_if_enabled::Error),
#[error(transparent)]
MergeBaseOctopus(#[from] super::merge_base_octopus_with_graph::Error),
}
}

///
#[cfg(feature = "merge")]
pub mod tree_merge_options {
Expand Down
34 changes: 34 additions & 0 deletions gix/src/repository/revision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,40 @@ impl crate::Repository {
.collect())
}

/// Return the best merge-base among all `commits`, or fail if `commits` yields no commit or no merge-base was found.
///
/// Use `graph` to speed up repeated calls.
#[cfg(feature = "revision")]
pub fn merge_base_octopus_with_graph(
&self,
commits: impl IntoIterator<Item = impl Into<gix_hash::ObjectId>>,
graph: &mut gix_revwalk::Graph<'_, '_, gix_revwalk::graph::Commit<gix_revision::merge_base::Flags>>,
) -> Result<Id<'_>, crate::repository::merge_base_octopus_with_graph::Error> {
use crate::prelude::ObjectIdExt;
use crate::repository::merge_base_octopus_with_graph;
let commits: Vec<_> = commits.into_iter().map(Into::into).collect();
let first = commits
.first()
.copied()
.ok_or(merge_base_octopus_with_graph::Error::MissingCommit)?;
gix_revision::merge_base::octopus(first, &commits[1..], graph)?
.ok_or(merge_base_octopus_with_graph::Error::NoMergeBase)
.map(|id| id.attach(self))
}

/// Return the best merge-base among all `commits`, or fail if `commits` yields no commit or no merge-base was found.
///
/// For repeated calls, prefer [`Self::merge_base_octopus_with_graph()`] for cache-reuse.
#[cfg(feature = "revision")]
pub fn merge_base_octopus(
&self,
commits: impl IntoIterator<Item = impl Into<gix_hash::ObjectId>>,
) -> Result<Id<'_>, crate::repository::merge_base_octopus::Error> {
let cache = self.commit_graph_if_enabled()?;
let mut graph = self.revision_graph(cache.as_ref());
Ok(self.merge_base_octopus_with_graph(commits, &mut graph)?)
}

/// Create the baseline for a revision walk by initializing it with the `tips` to start iterating on.
///
/// It can be configured further before starting the actual walk.
Expand Down

0 comments on commit 65ae68e

Please sign in to comment.