Skip to content

Commit

Permalink
feat: add Repository::virtual_merge_base() and `Repository::virtual…
Browse files Browse the repository at this point in the history
…_merge_base_with_graph()`.
  • Loading branch information
Byron committed Nov 7, 2024
1 parent 5f3f63a commit 7aee32a
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 1 deletion.
18 changes: 18 additions & 0 deletions gix/src/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@ pub use gix_merge as plumbing;

pub use gix_merge::blob;

///
pub mod virtual_merge_base {
use crate::Id;

/// The outcome produced by [`Repository::virtual_merge_base()`](crate::Repository::virtual_merge_base()).
pub struct Outcome<'repo> {
/// The commit ids of all the virtual merge bases we have produced in the process of recursively merging the merge-bases.
/// As they have been written to the object database, they are still available until they are garbage collected.
/// The last one is the most recently produced and the one returned as `commit_id`.
/// If this list is empty, this means that there was only one merge-base, which itself is already suitable the final merge-base.
pub virtual_merge_bases: Vec<Id<'repo>>,
/// The id of the commit that was created to hold the merged tree.
pub commit_id: Id<'repo>,
/// The hash of the merged tree.
pub tree_id: Id<'repo>,
}
}

///
pub mod commit {
/// The outcome produced by [`Repository::merge_commits()`](crate::Repository::merge_commits()).
Expand Down
70 changes: 69 additions & 1 deletion gix/src/repository/merge.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::config::cache::util::ApplyLeniencyDefault;
use crate::config::tree;
use crate::prelude::ObjectIdExt;
use crate::repository::{blob_merge_options, merge_commits, merge_resource_cache, merge_trees, tree_merge_options};
use crate::repository::{
blob_merge_options, merge_commits, merge_resource_cache, merge_trees, tree_merge_options, virtual_merge_base,
virtual_merge_base_with_graph,
};
use crate::Repository;
use gix_merge::blob::builtin_driver::text;
use gix_object::Write;
Expand Down Expand Up @@ -223,4 +226,69 @@ impl Repository {
virtual_merge_bases,
})
}

/// Create a single virtual merge-base by merging all `merge_bases` into one.
/// If the list is empty, an error will be returned as the histories are then unrelated.
/// If there is only one commit in the list, it is returned directly with this case clearly marked in the outcome.
///
/// 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.
// TODO: test
pub fn virtual_merge_base(
&self,
merge_bases: impl IntoIterator<Item = impl Into<gix_hash::ObjectId>>,
options: crate::merge::tree::Options,
) -> Result<crate::merge::virtual_merge_base::Outcome<'_>, virtual_merge_base::Error> {
let commit_graph = self.commit_graph_if_enabled()?;
let mut graph = self.revision_graph(commit_graph.as_ref());
Ok(self.virtual_merge_base_with_graph(merge_bases, &mut graph, options)?)
}

/// Like [`Self::virtual_merge_base()`], but also allows to reuse a `graph` for faster merge-base calculation,
/// particularly if `graph` was used to find the `merge_bases`.
pub fn virtual_merge_base_with_graph(
&self,
merge_bases: impl IntoIterator<Item = impl Into<gix_hash::ObjectId>>,
graph: &mut gix_revwalk::Graph<'_, '_, gix_revwalk::graph::Commit<gix_revision::merge_base::Flags>>,
options: crate::merge::tree::Options,
) -> Result<crate::merge::virtual_merge_base::Outcome<'_>, virtual_merge_base_with_graph::Error> {
let mut merge_bases: Vec<_> = merge_bases.into_iter().map(Into::into).collect();
let first = merge_bases
.pop()
.ok_or(virtual_merge_base_with_graph::Error::MissingCommit)?;
let Some(second) = merge_bases.pop() else {
let tree_id = self.find_commit(first)?.tree_id()?;
let commit_id = first.attach(self);
return Ok(crate::merge::virtual_merge_base::Outcome {
virtual_merge_bases: Vec::new(),
commit_id,
tree_id,
});
};

let mut diff_cache = self.diff_resource_cache_for_tree_diff()?;
let mut blob_merge = self.merge_resource_cache(Default::default())?;

let gix_merge::commit::virtual_merge_base::Outcome {
virtual_merge_bases,
commit_id,
tree_id,
} = gix_merge::commit::virtual_merge_base(
first,
second,
merge_bases,
graph,
&mut diff_cache,
&mut blob_merge,
self,
&mut |id| id.to_owned().attach(self).shorten_or_id().to_string(),
options.into(),
)?;

Ok(crate::merge::virtual_merge_base::Outcome {
virtual_merge_bases: virtual_merge_bases.into_iter().map(|id| id.attach(self)).collect(),
commit_id: commit_id.attach(self),
tree_id: tree_id.attach(self),
})
}
}
36 changes: 36 additions & 0 deletions gix/src/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,42 @@ pub mod merge_commits {
}
}

///
#[cfg(feature = "merge")]
pub mod virtual_merge_base {
/// The error returned by [Repository::virtual_merge_base()](crate::Repository::virtual_merge_base()).
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
OpenCommitGraph(#[from] super::commit_graph_if_enabled::Error),
#[error(transparent)]
VirtualMergeBase(#[from] super::virtual_merge_base_with_graph::Error),
}
}

///
#[cfg(feature = "merge")]
pub mod virtual_merge_base_with_graph {
/// The error returned by [Repository::virtual_merge_base_with_graph()](crate::Repository::virtual_merge_base_with_graph()).
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error("Not commit was provided as merge-base")]
MissingCommit,
#[error(transparent)]
MergeResourceCache(#[from] super::merge_resource_cache::Error),
#[error(transparent)]
DiffResourceCache(#[from] super::diff_resource_cache::Error),
#[error(transparent)]
CommitMerge(#[from] gix_merge::commit::Error),
#[error(transparent)]
FindCommit(#[from] crate::object::find::existing::with_conversion::Error),
#[error(transparent)]
DecodeCommit(#[from] gix_object::decode::Error),
}
}

///
#[cfg(feature = "merge")]
pub mod tree_merge_options {
Expand Down

0 comments on commit 7aee32a

Please sign in to comment.