Skip to content

Commit

Permalink
feat: add merge::tree::TreeFavor similar to *::FileFavor.
Browse files Browse the repository at this point in the history
That way it's possible to control how tree-conflicts should be auto-resolved.
  • Loading branch information
Byron committed Dec 2, 2024
1 parent 1ce37d8 commit 382aff9
Showing 1 changed file with 46 additions and 2 deletions.
48 changes: 46 additions & 2 deletions gix/src/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,15 @@ pub mod tree {
pub struct Options {
inner: gix_merge::tree::Options,
file_favor: Option<FileFavor>,
tree_favor: Option<TreeFavor>,
}

impl From<gix_merge::tree::Options> for Options {
fn from(opts: gix_merge::tree::Options) -> Self {
Options {
inner: opts,
file_favor: None,
tree_favor: None,
}
}
}
Expand All @@ -190,6 +192,7 @@ pub mod tree {
opts.blob_merge.resolve_binary_with = Some(resolve_binary);
opts.blob_merge.text.conflict = resolve_text;
}
opts.tree_conflicts = value.tree_favor.map(Into::into);
opts
}
}
Expand All @@ -202,7 +205,7 @@ pub mod tree {
/// * binary files
/// * symlinks (a form of file after all)
///
/// Note that that union merges aren't available as they aren't available for binaries or symlinks.
/// Note that *union* merges aren't available as they aren't available for binaries or symlinks.
#[derive(Debug, Copy, Clone)]
pub enum FileFavor {
/// Choose *our* side in case of a conflict.
Expand All @@ -215,6 +218,35 @@ pub mod tree {
Theirs,
}

/// Control how irreconcilable changes to trees should be resolved.
///
/// Examples for such issues are:
///
/// * *we*: delete, *they*: modify
/// * *we*: rename, *they*: rename to something else
/// * *we*: delete, *they*: rename
///
/// Use this to control which entries are visible to in the resulting tree.
/// Also note that this does not apply to the many tree-related changes are reconcilable.
#[derive(Debug, Copy, Clone)]
pub enum TreeFavor {
/// Choose *our* side in case of a conflict.
/// Note that content-merges are *still* performed according to the [FileFavor].
Ours,
/// Choose the state of the shared common ancestor, dropping both *ours* and *their* changes.
/// Content merges are not performed here.
Ancestor,
}

impl From<TreeFavor> for gix_merge::tree::ResolveWith {
fn from(value: TreeFavor) -> Self {
match value {
TreeFavor::Ours => gix_merge::tree::ResolveWith::Ours,
TreeFavor::Ancestor => gix_merge::tree::ResolveWith::Ancestor,
}
}
}

/// Builder
impl Options {
/// If *not* `None`, rename tracking will be performed when determining the changes of each side of the merge.
Expand All @@ -233,10 +265,22 @@ pub mod tree {

/// When `None`, the default, both sides will be treated equally, and in case of conflict an unbiased representation
/// is chosen both for content and for trees, causing a conflict.
/// When `Some(favor)` one can choose a side to prefer in order to automatically resolve a conflict meaningfully.
///
/// With `Some(favor)` one can choose a side to prefer in order to forcefully resolve an otherwise irreconcilable conflict,
/// loosing information in the process.
pub fn with_file_favor(mut self, file_favor: Option<FileFavor>) -> Self {
self.file_favor = file_favor;
self
}

/// When `None`, the default, both sides will be treated equally, trying to keep both conflicting changes in the tree, possibly
/// by renaming one side to move it out of the way.
///
/// With `Some(favor)` one can choose a side to prefer in order to forcefully resolve an otherwise irreconcilable conflict,
/// loosing information in the process.
pub fn with_tree_favor(mut self, tree_favor: Option<TreeFavor>) -> Self {
self.tree_favor = tree_favor;
self
}
}
}

0 comments on commit 382aff9

Please sign in to comment.