Skip to content

Commit

Permalink
Finish the entire merge implementation and cover everything with tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Oct 22, 2024
1 parent 37bc21b commit 0fce40d
Show file tree
Hide file tree
Showing 8 changed files with 1,145 additions and 180 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crate-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,11 @@ Check out the [performance discussion][gix-diff-performance] as well.

* [x] three-way merge analysis of **blobs** with choice of how to resolve conflicts
- [ ] choose how to resolve conflicts on the data-structure
- [ ] produce a new blob based on data-structure containing possible resolutions
- [x] produce a new blob based on data-structure containing possible resolutions
- [x] `merge` style
- [x] `diff3` style
- [x] `zdiff` style
- [ ] various newlines-related options during the merge (see https://git-scm.com/docs/git-merge#Documentation/git-merge.txt-ignore-space-change).
- [ ] a way to control inter-hunk merging based on proximity (maybe via `gix-diff` feature which could use the same)
* [ ] diff-heuristics match Git perfectly
* [x] API documentation
Expand Down
2 changes: 2 additions & 0 deletions gix-merge/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ document-features = { version = "0.2.0", optional = true }
[dev-dependencies]
gix-testtools = { path = "../tests/tools" }
gix-odb = { path = "../gix-odb" }
gix-utils = { version = "^0.1.12", path = "../gix-utils" }
termtree = "0.5.1"
pretty_assertions = "1.4.0"

[package.metadata.docs.rs]
Expand Down
25 changes: 17 additions & 8 deletions gix-merge/src/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ pub enum Error {
}

/// A way to configure [`commit()`](crate::commit()).
#[derive(Default, Debug, Copy, Clone)]
#[derive(Default, Debug, Clone)]
pub struct Options {
/// If `true`, merging unrelated commits is allowed, with the merge-base being assumed as empty tree.
pub allow_missing_merge_base: bool,
/// Options to define how trees should be merged.
pub tree_merge: crate::tree::Options,
/// Options to define how to merge blobs.
///
/// Note that these are temporarily overwritten if multiple merge-bases are merged into one.
pub blob_merge: crate::blob::platform::merge::Options,
/// If `true`, do not merge multiple merge-bases into one. Instead, just use the first one.
// TODO: test
#[doc(alias = "no_recursive", alias = "git2")]
pub use_first_merge_base: bool,
}

pub(super) mod function {
Expand All @@ -51,21 +51,29 @@ pub(super) mod function {
///
/// Note that `objects` *should* have an object cache to greatly accelerate tree-retrieval.
#[allow(clippy::too_many_arguments)]
pub fn commit<'objects>(
pub fn commit<'objects, E>(
our_commit: gix_hash::ObjectId,
their_commit: gix_hash::ObjectId,
mut labels: crate::blob::builtin_driver::text::Labels<'_>,
graph: &mut gix_revwalk::Graph<'_, '_, gix_revwalk::graph::Commit<gix_revision::merge_base::Flags>>,
diff_resource_cache: &mut gix_diff::blob::Platform,
blob_merge: &mut crate::blob::Platform,
objects: &'objects impl gix_object::FindObjectOrHeader,
write_blob_to_odb: impl FnMut(&[u8]) -> Result<gix_hash::ObjectId, E>,
options: Options,
) -> Result<crate::tree::Outcome<'objects>, Error> {
) -> Result<crate::tree::Outcome<'objects>, Error>
where
E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
{
let merge_bases_commit_ids = gix_revision::merge_base(our_commit, &[their_commit], graph)?;
let (merge_base_commit_id, ancestor_name) = match merge_bases_commit_ids {
Some(base_commit) if base_commit.len() == 1 => (base_commit[0], None),
Some(base_commits) => {
let virtual_base_tree = *base_commits.first().expect("TODO: merge multiple bases into one");
let virtual_base_tree = if options.use_first_merge_base {
*base_commits.first().expect("TODO: merge multiple bases into one")
} else {
todo!("merge multiple merge bases")
};
(virtual_base_tree, Some("merged common ancestors".into()))
}
None => {
Expand Down Expand Up @@ -97,6 +105,7 @@ pub(super) mod function {
&their_tree_id,
labels,
objects,
write_blob_to_odb,
&mut state,
diff_resource_cache,
blob_merge,
Expand Down
Loading

0 comments on commit 0fce40d

Please sign in to comment.