ok/jj
1
0
Fork 0
forked from mirrors/jj

view: move merge_views() onto View

This commit is contained in:
Martin von Zweigbergk 2021-06-02 08:47:33 -07:00
parent ac2530637a
commit 61ffa66fb5
2 changed files with 59 additions and 72 deletions

View file

@ -38,7 +38,7 @@ use crate::simple_op_store::SimpleOpStore;
use crate::store::{CommitId, Store, StoreError};
use crate::store_wrapper::StoreWrapper;
use crate::transaction::Transaction;
use crate::view::{merge_views, View};
use crate::view::View;
use crate::working_copy::WorkingCopy;
use crate::{conflicts, op_store, store};
@ -753,12 +753,7 @@ impl MutableRepo {
self.index.merge_in(&base_repo.index());
self.index.merge_in(&other_repo.index());
let merged_view = merge_views(
self.view.store_view(),
base_repo.view.store_view(),
other_repo.view.store_view(),
);
self.view.set_view(merged_view);
self.view.merge(&base_repo.view, &other_repo.view);
self.enforce_view_invariants();
self.invalidate_evolution();

View file

@ -21,71 +21,6 @@ pub struct View {
data: op_store::View,
}
// TODO: Make a member of View?
pub(crate) fn merge_views(
left: &op_store::View,
base: &op_store::View,
right: &op_store::View,
) -> op_store::View {
let mut result = left.clone();
if right.checkout == base.checkout || right.checkout == left.checkout {
// Keep the left side
} else if left.checkout == base.checkout {
result.checkout = right.checkout.clone();
} else {
// TODO: Return an error here. Or should we just pick one of the sides
// and emit a warning?
}
for removed_head in base.public_head_ids.difference(&right.public_head_ids) {
result.public_head_ids.remove(removed_head);
}
for added_head in right.public_head_ids.difference(&base.public_head_ids) {
result.public_head_ids.insert(added_head.clone());
}
for removed_head in base.head_ids.difference(&right.head_ids) {
result.head_ids.remove(removed_head);
}
for added_head in right.head_ids.difference(&base.head_ids) {
result.head_ids.insert(added_head.clone());
}
// TODO: Should it be considered a conflict if a commit-head is removed on one
// side while a child or successor is created on another side? Maybe a
// warning?
// Merge git refs
let base_git_ref_names: HashSet<_> = base.git_refs.keys().clone().collect();
let right_git_ref_names: HashSet<_> = right.git_refs.keys().clone().collect();
for maybe_modified_git_ref_name in right_git_ref_names.intersection(&base_git_ref_names) {
let base_commit_id = base.git_refs.get(*maybe_modified_git_ref_name).unwrap();
let right_commit_id = right.git_refs.get(*maybe_modified_git_ref_name).unwrap();
if base_commit_id == right_commit_id {
continue;
}
// TODO: Handle modify/modify conflict (i.e. if left and base are different
// here)
result.git_refs.insert(
(*maybe_modified_git_ref_name).clone(),
right_commit_id.clone(),
);
}
for added_git_ref_name in right_git_ref_names.difference(&base_git_ref_names) {
// TODO: Handle add/add conflict (i.e. if left also has the ref here)
result.git_refs.insert(
(*added_git_ref_name).clone(),
right.git_refs.get(*added_git_ref_name).unwrap().clone(),
);
}
for removed_git_ref_name in base_git_ref_names.difference(&right_git_ref_names) {
// TODO: Handle modify/remove conflict (i.e. if left and base are different
// here)
result.git_refs.remove(*removed_git_ref_name);
}
result
}
impl View {
pub fn new(op_store_view: op_store::View) -> Self {
View {
@ -155,4 +90,61 @@ impl View {
pub fn store_view_mut(&mut self) -> &mut op_store::View {
&mut self.data
}
pub fn merge(&mut self, base: &View, other: &View) {
if other.checkout() == base.checkout() || other.checkout() == self.checkout() {
// Keep the self side
} else if self.checkout() == base.checkout() {
self.set_checkout(other.checkout().clone());
} else {
// TODO: Return an error here. Or should we just pick one of the
// sides and emit a warning?
}
for removed_head in base.public_heads().difference(&other.public_heads()) {
self.remove_public_head(removed_head);
}
for added_head in other.public_heads().difference(&base.public_heads()) {
self.add_public_head(added_head);
}
for removed_head in base.heads().difference(&other.heads()) {
self.remove_head(removed_head);
}
for added_head in other.heads().difference(&base.heads()) {
self.add_head(added_head);
}
// TODO: Should it be considered a conflict if a commit-head is removed on one
// side while a child or successor is created on another side? Maybe a
// warning?
// Merge git refs
let base_git_ref_names: HashSet<_> = base.git_refs().keys().clone().collect();
let other_git_ref_names: HashSet<_> = other.git_refs().keys().clone().collect();
for maybe_modified_git_ref_name in other_git_ref_names.intersection(&base_git_ref_names) {
let base_commit_id = base.git_refs().get(*maybe_modified_git_ref_name).unwrap();
let other_commit_id = other.git_refs().get(*maybe_modified_git_ref_name).unwrap();
if base_commit_id == other_commit_id {
continue;
}
// TODO: Handle modify/modify conflict (i.e. if self and base are different
// here)
self.insert_git_ref(
(*maybe_modified_git_ref_name).clone(),
other_commit_id.clone(),
);
}
for added_git_ref_name in other_git_ref_names.difference(&base_git_ref_names) {
// TODO: Handle add/add conflict (i.e. if self also has the ref here)
self.insert_git_ref(
(*added_git_ref_name).clone(),
other.git_refs().get(*added_git_ref_name).unwrap().clone(),
);
}
for removed_git_ref_name in base_git_ref_names.difference(&other_git_ref_names) {
// TODO: Handle modify/remove conflict (i.e. if self and base are different
// here)
self.remove_git_ref(*removed_git_ref_name);
}
}
}