mirror of
https://github.com/martinvonz/jj.git
synced 2025-02-04 18:56:49 +00:00
merge: add Merge constructor that accepts interleaved values
Also migrated some callers of 3-way merge, where [left, base, right] order looks okay.
This commit is contained in:
parent
803b41c426
commit
dd26b7be40
6 changed files with 38 additions and 31 deletions
|
@ -722,13 +722,11 @@ mod tests {
|
|||
}
|
||||
}
|
||||
}
|
||||
let merge = Merge::new(
|
||||
vec![to_file_id(base_tree.path_value(&path))],
|
||||
vec![
|
||||
to_file_id(left_tree.path_value(&path)),
|
||||
to_file_id(right_tree.path_value(&path)),
|
||||
],
|
||||
);
|
||||
let merge = Merge::from_vec(vec![
|
||||
to_file_id(left_tree.path_value(&path)),
|
||||
to_file_id(base_tree.path_value(&path)),
|
||||
to_file_id(right_tree.path_value(&path)),
|
||||
]);
|
||||
let content = extract_as_single_hunk(&merge, store, &path).block_on();
|
||||
let slices = content.map(|ContentHunk(buf)| buf.as_slice());
|
||||
let merge_result = files::merge(&slices);
|
||||
|
|
|
@ -132,6 +132,17 @@ impl<T: Debug> Debug for Merge<T> {
|
|||
}
|
||||
|
||||
impl<T> Merge<T> {
|
||||
/// Creates a `Merge` from the given values, in which positive and negative
|
||||
/// terms alternate.
|
||||
pub fn from_vec(values: impl Into<SmallVec<[T; 1]>>) -> Self {
|
||||
let values = values.into();
|
||||
assert!(
|
||||
values.len() & 1 != 0,
|
||||
"must have one more adds than removes"
|
||||
);
|
||||
Merge { values }
|
||||
}
|
||||
|
||||
/// Creates a new merge object from the given removes and adds.
|
||||
pub fn new(removes: Vec<T>, adds: Vec<T>) -> Self {
|
||||
// TODO: removes and adds can be just IntoIterator.
|
||||
|
@ -335,10 +346,7 @@ impl<T> MergeBuilder<T> {
|
|||
/// Requires that exactly one more "adds" than "removes" have been added to
|
||||
/// this builder.
|
||||
pub fn build(self) -> Merge<T> {
|
||||
assert!(self.values.len() & 1 != 0);
|
||||
Merge {
|
||||
values: self.values,
|
||||
}
|
||||
Merge::from_vec(self.values)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -414,10 +414,7 @@ impl MergedTree {
|
|||
MergedTree::Merge(conflict) => Ok(conflict.clone()),
|
||||
}
|
||||
};
|
||||
let nested = Merge::new(
|
||||
vec![to_merge(base)?],
|
||||
vec![to_merge(self)?, to_merge(other)?],
|
||||
);
|
||||
let nested = Merge::from_vec(vec![to_merge(self)?, to_merge(base)?, to_merge(other)?]);
|
||||
let tree = merge_trees(&nested.flatten().simplify())?;
|
||||
// If the result can be resolved, then `merge_trees()` above would have returned
|
||||
// a resolved merge. However, that function will always preserve the arity of
|
||||
|
|
|
@ -93,10 +93,11 @@ pub fn merge_ref_targets(
|
|||
return resolved.clone();
|
||||
}
|
||||
|
||||
let mut merge = Merge::new(
|
||||
vec![base.as_merge().clone()],
|
||||
vec![left.as_merge().clone(), right.as_merge().clone()],
|
||||
)
|
||||
let mut merge = Merge::from_vec(vec![
|
||||
left.as_merge().clone(),
|
||||
base.as_merge().clone(),
|
||||
right.as_merge().clone(),
|
||||
])
|
||||
.flatten()
|
||||
.simplify();
|
||||
if !merge.is_resolved() {
|
||||
|
|
|
@ -373,10 +373,11 @@ fn merge_tree_value(
|
|||
_ => {
|
||||
// Start by creating a Merge object. Merges can cleanly represent a single
|
||||
// resolved state, the absence of a state, or a conflicted state.
|
||||
let conflict = Merge::new(
|
||||
vec![maybe_base.cloned()],
|
||||
vec![maybe_side1.cloned(), maybe_side2.cloned()],
|
||||
);
|
||||
let conflict = Merge::from_vec(vec![
|
||||
maybe_side1.cloned(),
|
||||
maybe_base.cloned(),
|
||||
maybe_side2.cloned(),
|
||||
]);
|
||||
let filename = dir.join(basename);
|
||||
let expanded = conflict.try_map(|term| match term {
|
||||
Some(TreeValue::Conflict(id)) => store.read_conflict(&filename, id),
|
||||
|
|
|
@ -167,19 +167,21 @@ fn test_merge_ref_targets() {
|
|||
// Left removed, right moved forward
|
||||
assert_eq!(
|
||||
merge_ref_targets(index, RefTarget::absent_ref(), &target1, &target3),
|
||||
RefTarget::from_merge(Merge::new(
|
||||
vec![Some(commit1.id().clone())],
|
||||
vec![None, Some(commit3.id().clone())],
|
||||
))
|
||||
RefTarget::from_merge(Merge::from_vec(vec![
|
||||
None,
|
||||
Some(commit1.id().clone()),
|
||||
Some(commit3.id().clone()),
|
||||
]))
|
||||
);
|
||||
|
||||
// Right removed, left moved forward
|
||||
assert_eq!(
|
||||
merge_ref_targets(index, &target3, &target1, RefTarget::absent_ref()),
|
||||
RefTarget::from_merge(Merge::new(
|
||||
vec![Some(commit1.id().clone())],
|
||||
vec![Some(commit3.id().clone()), None],
|
||||
))
|
||||
RefTarget::from_merge(Merge::from_vec(vec![
|
||||
Some(commit3.id().clone()),
|
||||
Some(commit1.id().clone()),
|
||||
None,
|
||||
]))
|
||||
);
|
||||
|
||||
// Left became conflicted, right moved forward
|
||||
|
|
Loading…
Reference in a new issue