From 61ffa66fb586f4f319cd9ad6f6122daaa3d80311 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Wed, 2 Jun 2021 08:47:33 -0700 Subject: [PATCH] view: move merge_views() onto View --- lib/src/repo.rs | 9 +--- lib/src/view.rs | 122 ++++++++++++++++++++++-------------------------- 2 files changed, 59 insertions(+), 72 deletions(-) diff --git a/lib/src/repo.rs b/lib/src/repo.rs index 28adbf784..6d46bf540 100644 --- a/lib/src/repo.rs +++ b/lib/src/repo.rs @@ -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(); diff --git a/lib/src/view.rs b/lib/src/view.rs index b741b5347..201ebeebb 100644 --- a/lib/src/view.rs +++ b/lib/src/view.rs @@ -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); + } + } }