jj/cli/tests/test_identical_commits.rs
Scott Taylor 33ad38bfed templates: add "divergent" label to log for divergent changes
It would be good to include the word "divergent" in the log when a
change is divergent, since users are often unsure what's happening when
they see a divergent change, and giving them a term to search for would
be helpful. However, I don't think it looks good to put this label next
to the change ID itself if both are the same color, since it ends up
being hard to distinguish from the change offset at a glance. Also,
putting the label next to the change ID also messes up the alignment of
fields in the log. Therefore, I think it looks better to put the
"divergent" label at the end of the line.

Since divergence and hidden commits are similar, it makes sense for both
labels to be in the same place, so I also moved the hidden label to the
end for consistency.

One downside is that the labels are less obviously connected with the
change ID itself due to them being farther apart. I think this could be
fine, since they are still visually connected by being the same color.
2025-12-20 16:55:51 +00:00

223 lines
8.1 KiB
Rust

// Copyright 2025 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 crate::common::CommandOutput;
use crate::common::TestEnvironment;
use crate::common::TestWorkDir;
fn create_test_environment() -> TestEnvironment {
let mut test_env = TestEnvironment::default();
test_env.add_env_var("JJ_RANDOMNESS_SEED", "0");
test_env.add_env_var("JJ_TIMESTAMP", "2001-01-01T00:00:00+00:00");
test_env.add_config("experimental.record-predecessors-in-commit = false");
test_env
}
#[test]
fn test_identical_commits() {
let test_env = create_test_environment();
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
let work_dir = test_env.work_dir("repo");
work_dir.run_jj(["new", "root()", "-m=test"]).success();
// TODO: Should not fail
insta::assert_snapshot!(work_dir.run_jj(["new", "root()", "-m=test"]), @r"
------- stderr -------
Internal error: Unexpected error from backend
Caused by: Newly-created commit e94ed463cbb0776612e308eba2ecaae74a7f8a73 already exists
[EOF]
[exit status: 255]
");
// There should be a single "test" commit
insta::assert_snapshot!(get_log_output(&work_dir), @r"
@ e94ed463cbb0 test
◆ 000000000000
[EOF]
");
}
/// Create "test1" commit, then rewrite it in the same way "concurrently" (by
/// starting at the same operation)
#[test]
fn test_identical_commits_concurrently() {
let test_env = create_test_environment();
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
let work_dir = test_env.work_dir("repo");
work_dir.run_jj(["new", "root()", "-m=test1"]).success();
work_dir.run_jj(["describe", "-m=test2"]).success();
work_dir
.run_jj(["describe", "-m=test2", "--at-op=@-"])
.success();
// There should be a single "test2" commit
insta::assert_snapshot!(get_log_output(&work_dir), @r"
@ c5abd2256ac0 test2
◆ 000000000000
[EOF]
------- stderr -------
Concurrent modification detected, resolving automatically.
[EOF]
");
}
/// Create commit "test1", then rewrite it to "test2", then rewrite it back to
/// "test1"
#[test]
fn test_identical_commits_by_cycling_rewrite() {
let test_env = create_test_environment();
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
let work_dir = test_env.work_dir("repo");
work_dir.run_jj(["new", "root()", "-m=test1"]).success();
work_dir.run_jj(["describe", "-m=test2"]).success();
// TODO: Should not fail
insta::assert_snapshot!(work_dir.run_jj(["describe", "-m=test1"]), @r"
------- stderr -------
Internal error: Unexpected error from backend
Caused by: Newly-created commit 053222c21fa06b9492e22346f8f70e732231ad4f already exists
[EOF]
[exit status: 255]
");
insta::assert_snapshot!(work_dir.run_jj(["evolog"]), @r"
@ oxmtprsl test.user@example.com 2001-01-01 11:00:00 c5abd225
│ (empty) test2
│ -- operation f184243937e9 describe commit 053222c21fa06b9492e22346f8f70e732231ad4f
○ oxmtprsl/1 test.user@example.com 2001-01-01 11:00:00 053222c2 (hidden)
(empty) test1
-- operation 509c18587028 new empty commit
[EOF]
");
// TODO: Test `jj op diff --from @--`
}
/// Create commits "test1" and "test2" and rewrite "test1". Then rewrite "test2"
/// to become identical to the rewritten "test1".
#[test]
fn test_identical_commits_by_convergent_rewrite() {
let test_env = create_test_environment();
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
let work_dir = test_env.work_dir("repo");
work_dir.run_jj(["new", "root()", "-m=test1"]).success();
work_dir.run_jj(["new", "root()", "-m=test2"]).success();
work_dir
.run_jj(["describe", "-m=test3", "subject(test1)"])
.success();
// TODO: Should not fail
insta::assert_snapshot!(work_dir.run_jj(["describe", "-m=test3", "subject(test2)"]), @r"
------- stderr -------
Internal error: Unexpected error from backend
Caused by: Newly-created commit 460733f1f6f9283d5a810b231dd3f846fd3a6f04 already exists
[EOF]
[exit status: 255]
");
// TODO: The "test3" commit should have either "test1" or "test2" as predecessor
// (or both?)
insta::assert_snapshot!(work_dir.run_jj(["evolog"]), @r"
@ oxmtprsl/1 test.user@example.com 2001-01-01 11:00:00 c5abd225 (divergent)
(empty) test2
-- operation a1561db9359b new empty commit
[EOF]
");
}
/// Create commits "test1" and "test2" and then rewrite both of them to be
/// identical in a single operation
#[test]
fn test_identical_commits_by_convergent_rewrite_one_operation() {
let test_env = create_test_environment();
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
let work_dir = test_env.work_dir("repo");
work_dir.run_jj(["new", "root()", "-m=test1"]).success();
work_dir.run_jj(["new", "root()", "-m=test2"]).success();
// TODO: Should not fail
insta::assert_snapshot!(work_dir.run_jj(["describe", "-m=test3", "root()+"]), @r"
------- stderr -------
Internal error: Unexpected error from backend
Caused by: Newly-created commit 460733f1f6f9283d5a810b231dd3f846fd3a6f04 already exists
[EOF]
[exit status: 255]
");
// TODO: There should be a single "test3" commit
insta::assert_snapshot!(get_log_output(&work_dir), @r"
@ c5abd2256ac0 test2
│ ○ 053222c21fa0 test1
├─╯
◆ 000000000000
[EOF]
");
// TODO: The "test3" commit should have either "test1" or "test2" as predecessor
// (or both?)
insta::assert_snapshot!(work_dir.run_jj(["evolog"]), @r"
@ oxmtprsl/0 test.user@example.com 2001-01-01 11:00:00 c5abd225 (divergent)
(empty) test2
-- operation a1561db9359b new empty commit
[EOF]
");
}
/// Create two stacked commits. Then reorder them so they become rewrites of
/// each other.
#[test]
fn test_identical_commits_swap_by_reordering() {
let test_env = create_test_environment();
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
let work_dir = test_env.work_dir("repo");
work_dir.run_jj(["new", "root()", "-m=test"]).success();
work_dir.run_jj(["new", "-m=test"]).success();
// Test the setup
insta::assert_snapshot!(get_log_output(&work_dir), @r"
@ 5bae90c9b34d test
○ e94ed463cbb0 test
◆ 000000000000
[EOF]
");
// TODO: Should not fail
insta::assert_snapshot!(work_dir.run_jj(["rebase", "-r=@", "-B=@-"]), @r"
------- stderr -------
Internal error: Unexpected error from backend
Caused by: Newly-created commit e94ed463cbb0776612e308eba2ecaae74a7f8a73 already exists
[EOF]
[exit status: 255]
");
// There same two commits should still be visible
insta::assert_snapshot!(get_log_output(&work_dir), @r"
@ 5bae90c9b34d test
○ e94ed463cbb0 test
◆ 000000000000
[EOF]
");
// TODO: Each commit should be a predecessor of the other
insta::assert_snapshot!(work_dir.run_jj(["evolog", "-r=@"]), @r"
@ oxmtprsl/0 test.user@example.com 2001-01-01 11:00:00 5bae90c9 (divergent)
(empty) test
-- operation 380fbe20623e new empty commit
[EOF]
");
insta::assert_snapshot!(work_dir.run_jj(["evolog", "-r=@-"]), @r"
○ oxmtprsl/1 test.user@example.com 2001-01-01 11:00:00 e94ed463 (divergent)
(empty) test
-- operation 40e37b931010 new empty commit
[EOF]
");
// TODO: Test that `jj op show` displays something reasonable
}
#[must_use]
fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput {
let template = r#"commit_id.short() ++ " " ++ description"#;
work_dir.run_jj(["log", "-T", template])
}