mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-26 22:10:52 +00:00
view: merge checkouts for all workspaces, not just the default one (#13)
This commit is contained in:
parent
766c01a6d9
commit
6d3e2017f8
3 changed files with 98 additions and 19 deletions
|
@ -551,6 +551,10 @@ impl MutableRepo {
|
|||
self.view_mut().set_checkout(workspace_id, commit_id);
|
||||
}
|
||||
|
||||
pub fn remove_checkout(&mut self, workspace_id: &WorkspaceId) {
|
||||
self.view_mut().remove_checkout(workspace_id);
|
||||
}
|
||||
|
||||
pub fn check_out(
|
||||
&mut self,
|
||||
workspace_id: WorkspaceId,
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
|
||||
use crate::backend::CommitId;
|
||||
use crate::index::IndexRef;
|
||||
|
@ -45,6 +45,10 @@ impl View {
|
|||
self.get_checkout(&WorkspaceId::default()).unwrap()
|
||||
}
|
||||
|
||||
pub fn checkouts(&self) -> &HashMap<WorkspaceId, CommitId> {
|
||||
&self.data.checkouts
|
||||
}
|
||||
|
||||
pub fn get_checkout(&self, workspace_id: &WorkspaceId) -> Option<&CommitId> {
|
||||
self.data.checkouts.get(workspace_id)
|
||||
}
|
||||
|
@ -77,6 +81,10 @@ impl View {
|
|||
self.data.checkouts.insert(workspace_id, commit_id);
|
||||
}
|
||||
|
||||
pub fn remove_checkout(&mut self, workspace_id: &WorkspaceId) {
|
||||
self.data.checkouts.remove(workspace_id);
|
||||
}
|
||||
|
||||
pub fn add_head(&mut self, head_id: &CommitId) {
|
||||
self.data.head_ids.insert(head_id.clone());
|
||||
}
|
||||
|
@ -234,15 +242,30 @@ impl View {
|
|||
}
|
||||
|
||||
pub fn merge(&mut self, index: IndexRef, base: &View, other: &View) {
|
||||
// TODO: Merge checkout for all workspaces or pass in a particular workspace ID
|
||||
// to this function
|
||||
if other.checkout() == base.checkout() || other.checkout() == self.checkout() {
|
||||
// Keep the self side
|
||||
} else if self.checkout() == base.checkout() {
|
||||
self.set_checkout(WorkspaceId::default(), other.checkout().clone());
|
||||
} else {
|
||||
// TODO: Return an error here. Or should we just pick one of the
|
||||
// sides and emit a warning?
|
||||
// Merge checkouts. If there's a conflict, we keep the self side.
|
||||
for (workspace_id, base_checkout) in base.checkouts() {
|
||||
let self_checkout = self.get_checkout(workspace_id);
|
||||
let other_checkout = other.get_checkout(workspace_id);
|
||||
if other_checkout == Some(base_checkout) || other_checkout == self_checkout {
|
||||
// The other side didn't change or both sides changed in the
|
||||
// same way.
|
||||
} else if let Some(other_checkout) = other_checkout {
|
||||
if self_checkout == Some(base_checkout) {
|
||||
self.set_checkout(workspace_id.clone(), other_checkout.clone());
|
||||
}
|
||||
} else {
|
||||
// The other side removed the workspace. We want to remove it even if the self
|
||||
// side changed the checkout.
|
||||
self.remove_checkout(workspace_id);
|
||||
}
|
||||
}
|
||||
for (workspace_id, other_checkout) in other.checkouts() {
|
||||
if self.get_checkout(workspace_id).is_none()
|
||||
&& base.get_checkout(workspace_id).is_none()
|
||||
{
|
||||
// The other side added the workspace.
|
||||
self.set_checkout(workspace_id.clone(), other_checkout.clone());
|
||||
}
|
||||
}
|
||||
|
||||
for removed_head in base.public_heads().difference(other.public_heads()) {
|
||||
|
|
|
@ -155,27 +155,79 @@ fn test_merge_views_checkout() {
|
|||
let test_workspace = testutils::init_repo(&settings, false);
|
||||
let repo = &test_workspace.repo;
|
||||
|
||||
// Workspace 1 gets updated in both transactions.
|
||||
// Workspace 2 gets updated only in tx1.
|
||||
// Workspace 3 gets updated only in tx2.
|
||||
// Workspace 4 gets deleted in tx1 and modified in tx2.
|
||||
// Workspace 5 gets deleted in tx2 and modified in tx1.
|
||||
// Workspace 6 gets added in tx1.
|
||||
// Workspace 7 gets added in tx2.
|
||||
let mut initial_tx = repo.start_transaction("test");
|
||||
let commit1 =
|
||||
testutils::create_random_commit(&settings, repo).write_to_repo(initial_tx.mut_repo());
|
||||
let commit2 =
|
||||
testutils::create_random_commit(&settings, repo).write_to_repo(initial_tx.mut_repo());
|
||||
let commit3 =
|
||||
testutils::create_random_commit(&settings, repo).write_to_repo(initial_tx.mut_repo());
|
||||
let ws1_id = WorkspaceId::new("ws1".to_string());
|
||||
let ws2_id = WorkspaceId::new("ws2".to_string());
|
||||
let ws3_id = WorkspaceId::new("ws3".to_string());
|
||||
let ws4_id = WorkspaceId::new("ws4".to_string());
|
||||
let ws5_id = WorkspaceId::new("ws5".to_string());
|
||||
let ws6_id = WorkspaceId::new("ws6".to_string());
|
||||
let ws7_id = WorkspaceId::new("ws7".to_string());
|
||||
initial_tx
|
||||
.mut_repo()
|
||||
.set_checkout(ws1_id.clone(), commit1.id().clone());
|
||||
initial_tx
|
||||
.mut_repo()
|
||||
.set_checkout(ws2_id.clone(), commit1.id().clone());
|
||||
initial_tx
|
||||
.mut_repo()
|
||||
.set_checkout(ws3_id.clone(), commit1.id().clone());
|
||||
initial_tx
|
||||
.mut_repo()
|
||||
.set_checkout(ws4_id.clone(), commit1.id().clone());
|
||||
initial_tx
|
||||
.mut_repo()
|
||||
.set_checkout(ws5_id.clone(), commit1.id().clone());
|
||||
let repo = initial_tx.commit();
|
||||
|
||||
let mut tx1 = repo.start_transaction("test");
|
||||
let checkout_tx1 = testutils::create_random_commit(&settings, repo)
|
||||
.set_open(false)
|
||||
.write_to_repo(tx1.mut_repo());
|
||||
tx1.mut_repo()
|
||||
.set_checkout(WorkspaceId::default(), checkout_tx1.id().clone());
|
||||
.set_checkout(ws1_id.clone(), commit2.id().clone());
|
||||
tx1.mut_repo()
|
||||
.set_checkout(ws2_id.clone(), commit2.id().clone());
|
||||
tx1.mut_repo().remove_checkout(&ws4_id);
|
||||
tx1.mut_repo()
|
||||
.set_checkout(ws5_id.clone(), commit2.id().clone());
|
||||
tx1.mut_repo()
|
||||
.set_checkout(ws6_id.clone(), commit2.id().clone());
|
||||
tx1.commit();
|
||||
|
||||
let mut tx2 = repo.start_transaction("test");
|
||||
let checkout_tx2 = testutils::create_random_commit(&settings, repo)
|
||||
.set_open(false)
|
||||
.write_to_repo(tx2.mut_repo());
|
||||
tx2.mut_repo()
|
||||
.set_checkout(WorkspaceId::default(), checkout_tx2.id().clone());
|
||||
.set_checkout(ws1_id.clone(), commit3.id().clone());
|
||||
tx2.mut_repo()
|
||||
.set_checkout(ws3_id.clone(), commit3.id().clone());
|
||||
tx2.mut_repo()
|
||||
.set_checkout(ws4_id.clone(), commit3.id().clone());
|
||||
tx2.mut_repo().remove_checkout(&ws5_id);
|
||||
tx2.mut_repo()
|
||||
.set_checkout(ws7_id.clone(), commit3.id().clone());
|
||||
tx2.commit();
|
||||
|
||||
let repo = repo.reload();
|
||||
|
||||
// We currently arbitrarily pick the first transaction's checkout (first by
|
||||
// transaction end time).
|
||||
assert_eq!(repo.view().checkout(), checkout_tx1.id());
|
||||
assert_eq!(repo.view().get_checkout(&ws1_id), Some(commit2.id()));
|
||||
assert_eq!(repo.view().get_checkout(&ws2_id), Some(commit2.id()));
|
||||
assert_eq!(repo.view().get_checkout(&ws3_id), Some(commit3.id()));
|
||||
assert_eq!(repo.view().get_checkout(&ws4_id), None);
|
||||
assert_eq!(repo.view().get_checkout(&ws5_id), None);
|
||||
assert_eq!(repo.view().get_checkout(&ws6_id), Some(commit2.id()));
|
||||
assert_eq!(repo.view().get_checkout(&ws7_id), Some(commit3.id()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Reference in a new issue