mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-15 00:44:33 +00:00
view: move merge_views() onto View
This commit is contained in:
parent
ac2530637a
commit
61ffa66fb5
2 changed files with 59 additions and 72 deletions
|
@ -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();
|
||||
|
|
122
lib/src/view.rs
122
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue