Skip to content

Commit b146b27

Browse files
committed
feat: Repository::merge_trees() now has a fully-wrapped outcome.
That way, more attached types are used for greater convenience.
1 parent 1f9556a commit b146b27

File tree

6 files changed

+62
-9
lines changed

6 files changed

+62
-9
lines changed

gix/src/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,6 @@ pub use gix_ignore as ignore;
120120
#[cfg(feature = "index")]
121121
pub use gix_index as index;
122122
pub use gix_lock as lock;
123-
#[cfg(feature = "blob-merge")]
124-
pub use gix_merge as merge;
125123
#[cfg(feature = "credentials")]
126124
pub use gix_negotiate as negotiate;
127125
pub use gix_object as objs;
@@ -204,6 +202,9 @@ pub mod push;
204202
///
205203
pub mod diff;
206204

205+
///
206+
pub mod merge;
207+
207208
/// See [`ThreadSafeRepository::discover()`], but returns a [`Repository`] instead.
208209
///
209210
/// # Note

gix/src/merge.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#[cfg(feature = "blob-merge")]
2+
pub use gix_merge as plumbing;
3+
4+
///
5+
pub mod tree {
6+
use gix_merge::tree::UnresolvedConflict;
7+
8+
/// The outcome produced by [`Repository::merge_trees()`](crate::Repository::merge_trees()).
9+
#[derive(Clone)]
10+
pub struct Outcome<'repo> {
11+
/// The ready-made (but unwritten) *base* tree, including all non-conflicting changes, and the changes that had
12+
/// conflicts which could be resolved automatically.
13+
///
14+
/// This means, if all of their changes were conflicting, this will be equivalent to the *base* tree.
15+
pub tree: crate::object::tree::Editor<'repo>,
16+
/// The set of conflicts we encountered. Can be empty to indicate there was no conflict.
17+
/// Note that conflicts might have been auto-resolved, but they are listed here for completeness.
18+
/// Use [`has_unresolved_conflicts()`](Outcome::has_unresolved_conflicts()) to see if any action is needed
19+
/// before using [`tree`](Outcome::tree).
20+
pub conflicts: Vec<gix_merge::tree::Conflict>,
21+
/// `true` if `conflicts` contains only a single *unresolved* conflict in the last slot, but possibly more resolved ones.
22+
/// This also makes this outcome a very partial merge that cannot be completed.
23+
/// Only set if [`fail_on_conflict`](Options::fail_on_conflict) is `true`.
24+
pub failed_on_first_unresolved_conflict: bool,
25+
}
26+
27+
impl Outcome<'_> {
28+
/// Return `true` if there is any conflict that would still need to be resolved as they would yield undesirable trees.
29+
/// This is based on `how` to determine what should be considered unresolved.
30+
pub fn has_unresolved_conflicts(&self, how: UnresolvedConflict) -> bool {
31+
self.conflicts.iter().any(|c| c.is_unresolved(how))
32+
}
33+
}
34+
}

gix/src/object/tree/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ use crate::{object::find, Id, ObjectDetached, Tree};
66

77
/// All state needed to conveniently edit a tree, using only [update-or-insert](Editor::upsert()) and [removals](Editor::remove()).
88
#[cfg(feature = "tree-editor")]
9+
#[derive(Clone)]
910
pub struct Editor<'repo> {
10-
inner: gix_object::tree::Editor<'repo>,
11-
validate: gix_validate::path::component::Options,
12-
repo: &'repo crate::Repository,
11+
pub(crate) inner: gix_object::tree::Editor<'repo>,
12+
pub(crate) validate: gix_validate::path::component::Options,
13+
pub(crate) repo: &'repo crate::Repository,
1314
}
1415

1516
/// Initialization

gix/src/repository/diff.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl Repository {
4949
old_tree: impl Into<Option<&'a Tree<'old_repo>>>,
5050
new_tree: impl Into<Option<&'a Tree<'new_repo>>>,
5151
options: impl Into<Option<crate::diff::Options>>,
52-
) -> Result<Vec<gix_diff::tree_with_rewrites::Change>, diff_tree_to_tree::Error> {
52+
) -> Result<Vec<crate::object::tree::diff::ChangeDetached>, diff_tree_to_tree::Error> {
5353
let mut cache = self.diff_resource_cache(gix_diff::blob::pipeline::Mode::ToGit, Default::default())?;
5454
let opts = options
5555
.into()

gix/src/repository/merge.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,14 @@ impl Repository {
124124
their_tree: impl AsRef<gix_hash::oid>,
125125
labels: gix_merge::blob::builtin_driver::text::Labels<'_>,
126126
options: gix_merge::tree::Options,
127-
) -> Result<gix_merge::tree::Outcome<'_>, merge_trees::Error> {
127+
) -> Result<crate::merge::tree::Outcome<'_>, merge_trees::Error> {
128128
let mut diff_cache = self.diff_resource_cache_for_tree_diff()?;
129129
let mut blob_merge = self.merge_resource_cache(Default::default())?;
130-
Ok(gix_merge::tree(
130+
let gix_merge::tree::Outcome {
131+
tree,
132+
conflicts,
133+
failed_on_first_unresolved_conflict,
134+
} = gix_merge::tree(
131135
ancestor_tree.as_ref(),
132136
our_tree.as_ref(),
133137
their_tree.as_ref(),
@@ -138,6 +142,17 @@ impl Repository {
138142
&mut diff_cache,
139143
&mut blob_merge,
140144
options,
141-
)?)
145+
)?;
146+
147+
let validate = self.config.protect_options()?;
148+
Ok(crate::merge::tree::Outcome {
149+
tree: crate::object::tree::Editor {
150+
inner: tree,
151+
validate,
152+
repo: self,
153+
},
154+
conflicts,
155+
failed_on_first_unresolved_conflict,
156+
})
142157
}
143158
}

gix/src/repository/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ pub mod merge_trees {
125125
DiffResourceCache(#[from] super::diff_resource_cache::Error),
126126
#[error(transparent)]
127127
TreeMerge(#[from] gix_merge::tree::Error),
128+
#[error(transparent)]
129+
ValidationOptions(#[from] crate::config::boolean::Error),
128130
}
129131
}
130132

0 commit comments

Comments
 (0)