forked from mirrors/jj
merged_tree: add config option to write trees using new format
We're finally ready to start writing trees using the new format where we represent conflicts by having multiple trees in the commit instead of having a single tree with multiple entries at a path. This patch adds a config option for that. It's not ready to be used yet, so I haven't updated the release notes or other documentation. I added only a simple CLI test for testing what happens when the config is enabled in an existing repo. 108 tests currently fail if we flip the default.
This commit is contained in:
parent
bb755ae754
commit
8e47d2d66f
5 changed files with 119 additions and 7 deletions
85
cli/tests/test_tree_level_conflicts.rs
Normal file
85
cli/tests/test_tree_level_conflicts.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright 2022 The Jujutsu Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use common::TestEnvironment;
|
||||
|
||||
pub mod common;
|
||||
|
||||
#[test]
|
||||
fn test_enable_tree_level_conflicts() {
|
||||
let test_env = TestEnvironment::default();
|
||||
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
|
||||
let repo_path = test_env.env_root().join("repo");
|
||||
|
||||
// Create a few commits before we enable tree-level conflicts
|
||||
let file_path = repo_path.join("file");
|
||||
test_env.jj_cmd_success(&repo_path, &["new", "root", "-m=left"]);
|
||||
std::fs::write(&file_path, "left").unwrap();
|
||||
test_env.jj_cmd_success(&repo_path, &["new", "root", "-m=right"]);
|
||||
std::fs::write(&file_path, "right").unwrap();
|
||||
test_env.jj_cmd_success(
|
||||
&repo_path,
|
||||
&[
|
||||
"new",
|
||||
r#"description("left")"#,
|
||||
r#"description("right")"#,
|
||||
"-m=merge",
|
||||
],
|
||||
);
|
||||
test_env.jj_cmd_success(&repo_path, &["new"]);
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["log"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
@ mzvwutvl test.user@example.com 2001-02-03 04:05:11.000 +07:00 f2101bed conflict
|
||||
│ (empty) (no description set)
|
||||
◉ zsuskuln test.user@example.com 2001-02-03 04:05:10.000 +07:00 5100e4e1 conflict
|
||||
├─╮ (empty) merge
|
||||
│ ◉ kkmpptxz test.user@example.com 2001-02-03 04:05:10.000 +07:00 0b65c8fb
|
||||
│ │ right
|
||||
◉ │ rlvkpnrz test.user@example.com 2001-02-03 04:05:09.000 +07:00 32003b88
|
||||
├─╯ left
|
||||
◉ zzzzzzzz root 00000000
|
||||
"###);
|
||||
|
||||
// Enable tree-level conflicts
|
||||
test_env.add_config(r#"format.tree-level-conflicts = true"#);
|
||||
// We get a new working-copy commit. The working copy unfortunately appears
|
||||
// non-empty
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["log"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
@ mzvwutvl test.user@example.com 2001-02-03 04:05:13.000 +07:00 54c562fa conflict
|
||||
│ (no description set)
|
||||
◉ zsuskuln test.user@example.com 2001-02-03 04:05:10.000 +07:00 5100e4e1 conflict
|
||||
├─╮ (empty) merge
|
||||
│ ◉ kkmpptxz test.user@example.com 2001-02-03 04:05:10.000 +07:00 0b65c8fb
|
||||
│ │ right
|
||||
◉ │ rlvkpnrz test.user@example.com 2001-02-03 04:05:09.000 +07:00 32003b88
|
||||
├─╯ left
|
||||
◉ zzzzzzzz root 00000000
|
||||
"###);
|
||||
// ...but at least it has no diff
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
|
||||
// If we create new commit off of an unconflicted commit, it also appears
|
||||
// non-empty
|
||||
test_env.jj_cmd_success(&repo_path, &["new", "k"]);
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-r=@"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
@ yostqsxw test.user@example.com 2001-02-03 04:05:16.000 +07:00 f5e911f1
|
||||
│ (no description set)
|
||||
~
|
||||
"###);
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
}
|
|
@ -940,9 +940,13 @@ impl MergedTreeBuilder {
|
|||
|
||||
/// Create new tree(s) from the base tree(s) and overrides.
|
||||
///
|
||||
/// When the base tree was a legacy tree, then the result will be another
|
||||
/// legacy tree. Overrides with conflicts will result in conflict objects
|
||||
/// being written to the store.
|
||||
/// When the base tree was a legacy tree and the
|
||||
/// `format.tree-level-conflicts` config is disabled, then the result will
|
||||
/// be another legacy tree. Overrides with conflicts will result in
|
||||
/// conflict objects being written to the store. If
|
||||
/// `format.tree-tree-level-conflicts` is enabled, then a legacy tree will
|
||||
/// still be written and immediately converted and returned as a merged
|
||||
/// tree.
|
||||
pub fn write_tree(self, store: &Arc<Store>) -> BackendResult<MergedTreeId> {
|
||||
match self.base_tree_id.clone() {
|
||||
MergedTreeId::Legacy(base_tree_id) => {
|
||||
|
@ -959,7 +963,14 @@ impl MergedTreeBuilder {
|
|||
}
|
||||
}
|
||||
}
|
||||
Ok(MergedTreeId::Legacy(tree_builder.write_tree()))
|
||||
let legacy_id = tree_builder.write_tree();
|
||||
if store.use_tree_conflict_format() {
|
||||
let legacy_tree = store.get_tree(&RepoPath::root(), &legacy_id)?;
|
||||
let merged_tree = MergedTree::from_legacy_tree(legacy_tree)?;
|
||||
Ok(merged_tree.id())
|
||||
} else {
|
||||
Ok(MergedTreeId::Legacy(legacy_id))
|
||||
}
|
||||
}
|
||||
MergedTreeId::Merge(base_tree_ids) => {
|
||||
let new_tree_ids = self.write_merged_trees(base_tree_ids, store)?;
|
||||
|
|
|
@ -152,7 +152,7 @@ impl ReadonlyRepo {
|
|||
let backend = backend_factory(&store_path)?;
|
||||
let backend_path = store_path.join("type");
|
||||
fs::write(&backend_path, backend.name()).context(&backend_path)?;
|
||||
let store = Store::new(backend);
|
||||
let store = Store::new(backend, user_settings.use_tree_conflict_format());
|
||||
let repo_settings = user_settings.with_repo(&repo_path).unwrap();
|
||||
|
||||
let op_store_path = repo_path.join("op_store");
|
||||
|
@ -585,7 +585,10 @@ impl RepoLoader {
|
|||
repo_path: &Path,
|
||||
store_factories: &StoreFactories,
|
||||
) -> Result<Self, StoreLoadError> {
|
||||
let store = Store::new(store_factories.load_backend(&repo_path.join("store"))?);
|
||||
let store = Store::new(
|
||||
store_factories.load_backend(&repo_path.join("store"))?,
|
||||
user_settings.use_tree_conflict_format(),
|
||||
);
|
||||
let repo_settings = user_settings.with_repo(repo_path).unwrap();
|
||||
let op_store = Arc::from(store_factories.load_op_store(&repo_path.join("op_store"))?);
|
||||
let op_heads_store =
|
||||
|
|
|
@ -97,6 +97,12 @@ impl UserSettings {
|
|||
self.rng.clone()
|
||||
}
|
||||
|
||||
pub fn use_tree_conflict_format(&self) -> bool {
|
||||
self.config
|
||||
.get_bool("format.tree-level-conflicts")
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn user_name(&self) -> String {
|
||||
self.config.get_string("user.name").unwrap_or_default()
|
||||
}
|
||||
|
|
|
@ -38,14 +38,16 @@ pub struct Store {
|
|||
backend: Box<dyn Backend>,
|
||||
commit_cache: RwLock<HashMap<CommitId, Arc<backend::Commit>>>,
|
||||
tree_cache: RwLock<HashMap<(RepoPath, TreeId), Arc<backend::Tree>>>,
|
||||
use_tree_conflict_format: bool,
|
||||
}
|
||||
|
||||
impl Store {
|
||||
pub fn new(backend: Box<dyn Backend>) -> Arc<Self> {
|
||||
pub fn new(backend: Box<dyn Backend>, use_tree_conflict_format: bool) -> Arc<Self> {
|
||||
Arc::new(Store {
|
||||
backend,
|
||||
commit_cache: Default::default(),
|
||||
tree_cache: Default::default(),
|
||||
use_tree_conflict_format,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -53,6 +55,11 @@ impl Store {
|
|||
self.backend.as_any()
|
||||
}
|
||||
|
||||
/// Whether new tree should be written using the tree-level format.
|
||||
pub fn use_tree_conflict_format(&self) -> bool {
|
||||
self.use_tree_conflict_format
|
||||
}
|
||||
|
||||
pub fn commit_id_length(&self) -> usize {
|
||||
self.backend.commit_id_length()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue