2022-11-26 23:57:50 +00:00
|
|
|
// Copyright 2022 The Jujutsu Authors
|
2022-03-21 04:05:21 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
2023-02-28 10:43:14 +00:00
|
|
|
use std::path::Path;
|
|
|
|
|
2023-05-21 08:49:35 +00:00
|
|
|
use itertools::Itertools as _;
|
|
|
|
|
2022-03-30 17:47:11 +00:00
|
|
|
use crate::common::TestEnvironment;
|
|
|
|
|
2022-03-21 04:05:21 +00:00
|
|
|
#[test]
|
2022-03-26 17:44:28 +00:00
|
|
|
fn test_concurrent_operation_divergence() {
|
2022-03-21 04:05:21 +00:00
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2022-03-21 04:05:21 +00:00
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "message 1"]);
|
|
|
|
test_env.jj_cmd_ok(
|
2022-03-21 04:05:21 +00:00
|
|
|
&repo_path,
|
2022-04-20 05:51:52 +00:00
|
|
|
&["describe", "-m", "message 2", "--at-op", "@-"],
|
2022-03-21 04:05:21 +00:00
|
|
|
);
|
|
|
|
|
2024-07-21 09:43:01 +00:00
|
|
|
// "--at-op=@" disables op heads merging, and prints head operation ids.
|
|
|
|
let stderr = test_env.jj_cmd_failure(&repo_path, &["op", "log", "--at-op=@"]);
|
2024-07-21 10:27:36 +00:00
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
|
|
|
Error: The "@" expression resolved to more than one operation
|
|
|
|
Hint: Try specifying one of the operations by ID: e31015019d90, 48f4a48f3f70
|
|
|
|
"###);
|
|
|
|
|
2024-07-21 09:43:01 +00:00
|
|
|
// "op log --at-op" should work without merging the head operations
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["op", "log", "--at-op=48f4a48f3f70"]);
|
2024-01-11 03:31:54 +00:00
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-07-21 09:43:01 +00:00
|
|
|
@ 48f4a48f3f70 test-username@host.example.com 2001-02-03 04:05:09.000 +07:00 - 2001-02-03 04:05:09.000 +07:00
|
2024-01-11 03:31:54 +00:00
|
|
|
│ describe commit 230dd059e1b059aefc0da06a2e5a7dbf22362f22
|
|
|
|
│ args: jj describe -m 'message 2' --at-op @-
|
2024-07-15 22:20:10 +00:00
|
|
|
○ b51416386f26 test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00
|
2024-01-11 03:31:54 +00:00
|
|
|
│ add workspace 'default'
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 9a7d829846af test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00
|
2024-01-07 18:32:31 +00:00
|
|
|
│ initialize repo
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 000000000000 root()
|
2024-01-11 03:31:54 +00:00
|
|
|
"###);
|
|
|
|
|
2022-03-21 04:05:21 +00:00
|
|
|
// We should be informed about the concurrent modification
|
2023-10-10 11:59:18 +00:00
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["log", "-T", "description"]);
|
2022-03-21 04:05:21 +00:00
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
○ message 2
|
2023-02-09 02:53:47 +00:00
|
|
|
│ @ message 1
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
◆
|
2022-03-21 04:05:21 +00:00
|
|
|
"###);
|
2023-10-10 11:07:06 +00:00
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
|
|
|
Concurrent modification detected, resolving automatically.
|
|
|
|
"###);
|
2022-03-21 04:05:21 +00:00
|
|
|
}
|
2022-03-26 17:44:28 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_concurrent_operations_auto_rebase() {
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2022-03-26 17:44:28 +00:00
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file"), "contents").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "initial"]);
|
2022-03-26 17:44:28 +00:00
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["op", "log"]);
|
2022-11-22 17:11:40 +00:00
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
@ 66d1dd775c54 test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00
|
|
|
|
│ describe commit 4e8f9d2be039994f589b4e57ac5e9488703e604d
|
2023-02-09 02:53:47 +00:00
|
|
|
│ args: jj describe -m initial
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 130d67859810 test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00
|
2023-02-09 02:53:47 +00:00
|
|
|
│ snapshot working copy
|
2023-02-27 07:55:15 +00:00
|
|
|
│ args: jj describe -m initial
|
2024-07-15 22:20:10 +00:00
|
|
|
○ b51416386f26 test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00
|
2023-02-09 02:53:47 +00:00
|
|
|
│ add workspace 'default'
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 9a7d829846af test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00
|
2024-01-07 18:32:31 +00:00
|
|
|
│ initialize repo
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 000000000000 root()
|
2022-11-22 17:11:40 +00:00
|
|
|
"###);
|
2023-02-09 02:53:47 +00:00
|
|
|
let op_id_hex = stdout[3..15].to_string();
|
2022-03-26 17:44:28 +00:00
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "rewritten"]);
|
|
|
|
test_env.jj_cmd_ok(
|
2022-03-26 17:44:28 +00:00
|
|
|
&repo_path,
|
|
|
|
&["new", "--at-op", &op_id_hex, "-m", "new child"],
|
|
|
|
);
|
|
|
|
|
|
|
|
// We should be informed about the concurrent modification
|
2023-10-10 11:59:18 +00:00
|
|
|
let (stdout, stderr) = get_log_output_with_stderr(&test_env, &repo_path);
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
○ db141860e12c2d5591c56fde4fc99caf71cec418 new child
|
2024-06-23 22:20:33 +00:00
|
|
|
@ 07c3641e495cce57ea4ca789123b52f421c57aa2 rewritten
|
2024-07-15 22:20:10 +00:00
|
|
|
◆ 0000000000000000000000000000000000000000
|
2022-03-26 17:44:28 +00:00
|
|
|
"###);
|
2023-10-10 11:07:06 +00:00
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
|
|
|
Concurrent modification detected, resolving automatically.
|
|
|
|
Rebased 1 descendant commits onto commits rewritten by other operation
|
|
|
|
"###);
|
2022-03-26 17:44:28 +00:00
|
|
|
}
|
2022-10-08 06:37:10 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_concurrent_operations_wc_modified() {
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2022-10-08 06:37:10 +00:00
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file"), "contents\n").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "initial"]);
|
2022-10-08 06:37:10 +00:00
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["op", "log"]);
|
2023-02-09 02:53:47 +00:00
|
|
|
let op_id_hex = stdout[3..15].to_string();
|
2022-10-08 06:37:10 +00:00
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
test_env.jj_cmd_ok(
|
2022-10-08 06:37:10 +00:00
|
|
|
&repo_path,
|
|
|
|
&["new", "--at-op", &op_id_hex, "-m", "new child1"],
|
|
|
|
);
|
2023-10-10 11:59:18 +00:00
|
|
|
test_env.jj_cmd_ok(
|
2022-10-08 06:37:10 +00:00
|
|
|
&repo_path,
|
|
|
|
&["new", "--at-op", &op_id_hex, "-m", "new child2"],
|
|
|
|
);
|
|
|
|
std::fs::write(repo_path.join("file"), "modified\n").unwrap();
|
|
|
|
|
|
|
|
// We should be informed about the concurrent modification
|
2023-10-10 11:59:18 +00:00
|
|
|
let (stdout, stderr) = get_log_output_with_stderr(&test_env, &repo_path);
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
@ 4eadcf3df11f46ef3d825c776496221cc8303053 new child1
|
2024-07-15 22:20:10 +00:00
|
|
|
│ ○ 68119f1643b7e3c301c5f7c2b6c9bf4ccba87379 new child2
|
2023-02-09 02:53:47 +00:00
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 2ff7ae858a3a11837fdf9d1a76be295ef53f1bb3 initial
|
|
|
|
◆ 0000000000000000000000000000000000000000
|
2022-10-08 06:37:10 +00:00
|
|
|
"###);
|
2023-10-10 11:07:06 +00:00
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
|
|
|
Concurrent modification detected, resolving automatically.
|
|
|
|
"###);
|
2022-10-08 06:37:10 +00:00
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git"]);
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
diff --git a/file b/file
|
2024-07-14 10:26:07 +00:00
|
|
|
index 12f00e90b6..2e0996000b 100644
|
2022-10-08 06:37:10 +00:00
|
|
|
--- a/file
|
|
|
|
+++ b/file
|
|
|
|
@@ -1,1 +1,1 @@
|
|
|
|
-contents
|
|
|
|
+modified
|
|
|
|
"###);
|
|
|
|
|
|
|
|
// The working copy should be committed after merging the operations
|
2023-02-27 07:59:53 +00:00
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["op", "log", "-Tdescription"]);
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
@ snapshot working copy
|
2024-07-15 22:20:10 +00:00
|
|
|
○ resolve concurrent operations
|
2023-02-27 07:59:53 +00:00
|
|
|
├─╮
|
2024-07-15 22:20:10 +00:00
|
|
|
○ │ new empty commit
|
|
|
|
│ ○ new empty commit
|
2023-02-27 07:59:53 +00:00
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
○ describe commit 506f4ec3c2c62befa15fabc34ca9d4e6d7bef254
|
|
|
|
○ snapshot working copy
|
|
|
|
○ add workspace 'default'
|
|
|
|
○ initialize repo
|
|
|
|
○
|
2022-10-08 06:37:10 +00:00
|
|
|
"###);
|
|
|
|
}
|
2023-02-28 10:43:14 +00:00
|
|
|
|
2023-05-21 08:49:35 +00:00
|
|
|
#[test]
|
|
|
|
fn test_concurrent_snapshot_wc_reloadable() {
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2023-05-21 08:49:35 +00:00
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
let op_heads_dir = repo_path
|
|
|
|
.join(".jj")
|
|
|
|
.join("repo")
|
|
|
|
.join("op_heads")
|
|
|
|
.join("heads");
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("base"), "").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "initial"]);
|
2023-05-21 08:49:35 +00:00
|
|
|
|
|
|
|
// Create new commit and checkout it.
|
|
|
|
std::fs::write(repo_path.join("child1"), "").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "new child1"]);
|
2023-05-21 08:49:35 +00:00
|
|
|
|
|
|
|
let template = r#"id ++ "\n" ++ description ++ "\n" ++ tags"#;
|
|
|
|
let op_log_stdout = test_env.jj_cmd_success(&repo_path, &["op", "log", "-T", template]);
|
|
|
|
insta::assert_snapshot!(op_log_stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
@ 9f11958bcf79340028eeabf9b0381cd8d2ae2258d0097b8ce8bd24fe7138eca08d9eb113bb4722ebacd9b7a6fa017e3888f72907be7487f275823c8d21359eed
|
|
|
|
│ commit 554d22b2c43c1c47e279430197363e8daabe2fd6
|
2023-05-21 08:49:35 +00:00
|
|
|
│ args: jj commit -m 'new child1'
|
2024-07-15 22:20:10 +00:00
|
|
|
○ f5460e8f43a04fbc61553d12fa5ba8d3b12e4fdcfda1999db6b67cc8e1e473b7e62cc0536196a53b84f34e18c1c6d608f427bb64bd5f834f845a9859e39cb320
|
2023-05-21 08:49:35 +00:00
|
|
|
│ snapshot working copy
|
|
|
|
│ args: jj commit -m 'new child1'
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 49359b6597ead3fbb66802a6bbd8761c0ad4646a2b089090d6fd72fb6e2568aa99c4a92f9f1f252a83cce56ec84961c36e85f731f19fc5a4c24d6a3f7282b774
|
2024-06-23 22:20:33 +00:00
|
|
|
│ commit de71e09289762a65f80bb1c3dae2a949df6bcde7
|
2023-05-21 08:49:35 +00:00
|
|
|
│ args: jj commit -m initial
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 86dbba2b96a4a801abef7f77f8fdf338b6e36f81ea4a531aacf06acbd06f4037731fffef42503c2225fdb206488971c1601ca8b2b4a83a3fe2dce64ee4db085e
|
2023-05-21 08:49:35 +00:00
|
|
|
│ snapshot working copy
|
|
|
|
│ args: jj commit -m initial
|
2024-07-15 22:20:10 +00:00
|
|
|
○ b51416386f2685fd5493f2b20e8eec3c24a1776d9e1a7cb5ed7e30d2d9c88c0c1e1fe71b0b7358cba60de42533d1228ed9878f2f89817d892c803395ccf9fe92
|
2023-05-21 08:49:35 +00:00
|
|
|
│ add workspace 'default'
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 9a7d829846af88a2f7a1e348fb46ff58729e49632bc9c6a052aec8501563cb0d10f4a4e6010ffde529f84a2b9b5b3a4c211a889106a41f6c076dfdacc79f6af7
|
2024-01-07 18:32:31 +00:00
|
|
|
│ initialize repo
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
2024-01-07 18:32:31 +00:00
|
|
|
|
2023-05-21 08:49:35 +00:00
|
|
|
"###);
|
|
|
|
let op_log_lines = op_log_stdout.lines().collect_vec();
|
|
|
|
let current_op_id = op_log_lines[0].split_once(" ").unwrap().1;
|
|
|
|
let previous_op_id = op_log_lines[6].split_once(" ").unwrap().1;
|
|
|
|
|
|
|
|
// Another process started from the "initial" operation, but snapshots after
|
|
|
|
// the "child1" checkout has been completed.
|
|
|
|
std::fs::rename(
|
|
|
|
op_heads_dir.join(current_op_id),
|
|
|
|
op_heads_dir.join(previous_op_id),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
std::fs::write(repo_path.join("child2"), "").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "new child2"]);
|
2023-10-10 11:07:06 +00:00
|
|
|
insta::assert_snapshot!(stdout, @"");
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
Working copy now at: kkmpptxz 1795621b new child2
|
|
|
|
Parent commit : rlvkpnrz 86f54245 new child1
|
2023-05-21 08:49:35 +00:00
|
|
|
"###);
|
|
|
|
|
|
|
|
// Since the repo can be reloaded before snapshotting, "child2" should be
|
|
|
|
// a child of "child1", not of "initial".
|
|
|
|
let template = r#"commit_id ++ " " ++ description"#;
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", template, "-s"]);
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
@ 1795621b54f4ebb435978b65d66bc0f90d8f20b6 new child2
|
2023-05-21 08:49:35 +00:00
|
|
|
│ A child2
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 86f54245e13f850f8275b5541e56da996b6a47b7 new child1
|
2023-05-21 08:49:35 +00:00
|
|
|
│ A child1
|
2024-07-15 22:20:10 +00:00
|
|
|
○ 84f07f6bca2ffeddac84a8b09f60c6b81112375c initial
|
2023-05-21 08:49:35 +00:00
|
|
|
│ A base
|
2024-07-15 22:20:10 +00:00
|
|
|
◆ 0000000000000000000000000000000000000000
|
2023-05-21 08:49:35 +00:00
|
|
|
"###);
|
|
|
|
}
|
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
fn get_log_output_with_stderr(test_env: &TestEnvironment, cwd: &Path) -> (String, String) {
|
2023-02-28 11:30:57 +00:00
|
|
|
let template = r#"commit_id ++ " " ++ description"#;
|
2023-10-10 11:59:18 +00:00
|
|
|
test_env.jj_cmd_ok(cwd, &["log", "-T", template])
|
2023-02-28 10:43:14 +00:00
|
|
|
}
|