mirror of
https://github.com/martinvonz/jj.git
synced 2025-05-16 20:54:27 +00:00
We haven't had any reports of problems from people who opted in. Since it's early in the release cycle now, let's now test it on everyone who builds from head, so we get almost a month of testing from those people before it's enabled by default in a released version. This impacts lots of test cases because the change-id header is added to the Git commit. Most are uninteresting. `test_git_fetch` now sees some divergent changes where it used to see only divergent bookmarks, which makes sense.
1372 lines
46 KiB
Rust
1372 lines
46 KiB
Rust
// 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 test_case::test_case;
|
||
|
||
use crate::common::CommandOutput;
|
||
use crate::common::TestEnvironment;
|
||
use crate::common::TestWorkDir;
|
||
|
||
/// Test adding a second workspace
|
||
#[test]
|
||
fn test_workspaces_add_second_workspace() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
main_dir.write_file("file", "contents");
|
||
main_dir.run_jj(["commit", "-m", "initial"]).success();
|
||
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: rlvkpnrz 504e3d8c (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
let output = main_dir.run_jj(["workspace", "add", "--name", "second", "../secondary"]);
|
||
insta::assert_snapshot!(output.normalize_backslash(), @r#"
|
||
------- stderr -------
|
||
Created workspace in "../secondary"
|
||
Working copy (@) now at: rzvqmyuk bcc858e1 (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm 7b22a8cb initial
|
||
Added 1 files, modified 0 files, removed 0 files
|
||
[EOF]
|
||
"#);
|
||
|
||
// Can see the working-copy commit in each workspace in the log output. The "@"
|
||
// node in the graph indicates the current workspace's working-copy commit.
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 504e3d8c1bcd default@
|
||
│ ○ bcc858e1d93f second@
|
||
├─╯
|
||
○ 7b22a8cbe888
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
insta::assert_snapshot!(get_log_output(&secondary_dir), @r"
|
||
@ bcc858e1d93f second@
|
||
│ ○ 504e3d8c1bcd default@
|
||
├─╯
|
||
○ 7b22a8cbe888
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
|
||
// Both workspaces show up when we list them
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: rlvkpnrz 504e3d8c (empty) (no description set)
|
||
second: rzvqmyuk bcc858e1 (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
/// Test how sparse patterns are inherited
|
||
#[test]
|
||
fn test_workspaces_sparse_patterns() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "ws1"]).success();
|
||
let ws1_dir = test_env.work_dir("ws1");
|
||
let ws2_dir = test_env.work_dir("ws2");
|
||
let ws3_dir = test_env.work_dir("ws3");
|
||
let ws4_dir = test_env.work_dir("ws4");
|
||
let ws5_dir = test_env.work_dir("ws5");
|
||
let ws6_dir = test_env.work_dir("ws6");
|
||
|
||
ws1_dir
|
||
.run_jj(["sparse", "set", "--clear", "--add=foo"])
|
||
.success();
|
||
ws1_dir.run_jj(["workspace", "add", "../ws2"]).success();
|
||
let output = ws2_dir.run_jj(["sparse", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
foo
|
||
[EOF]
|
||
");
|
||
ws2_dir.run_jj(["sparse", "set", "--add=bar"]).success();
|
||
ws2_dir.run_jj(["workspace", "add", "../ws3"]).success();
|
||
let output = ws3_dir.run_jj(["sparse", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
bar
|
||
foo
|
||
[EOF]
|
||
");
|
||
// --sparse-patterns behavior
|
||
ws3_dir
|
||
.run_jj(["workspace", "add", "--sparse-patterns=copy", "../ws4"])
|
||
.success();
|
||
let output = ws4_dir.run_jj(["sparse", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
bar
|
||
foo
|
||
[EOF]
|
||
");
|
||
ws3_dir
|
||
.run_jj(["workspace", "add", "--sparse-patterns=full", "../ws5"])
|
||
.success();
|
||
let output = ws5_dir.run_jj(["sparse", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
.
|
||
[EOF]
|
||
");
|
||
ws3_dir
|
||
.run_jj(["workspace", "add", "--sparse-patterns=empty", "../ws6"])
|
||
.success();
|
||
let output = ws6_dir.run_jj(["sparse", "list"]);
|
||
insta::assert_snapshot!(output, @"");
|
||
}
|
||
|
||
/// Test adding a second workspace while the current workspace is editing a
|
||
/// merge
|
||
#[test]
|
||
fn test_workspaces_add_second_workspace_on_merge() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
|
||
main_dir.run_jj(["describe", "-m=left"]).success();
|
||
main_dir.run_jj(["new", "@-", "-m=right"]).success();
|
||
main_dir.run_jj(["new", "all:@-+", "-m=merge"]).success();
|
||
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: zsuskuln 46ed31b6 (empty) merge
|
||
[EOF]
|
||
");
|
||
|
||
main_dir
|
||
.run_jj(["workspace", "add", "--name", "second", "../secondary"])
|
||
.success();
|
||
|
||
// The new workspace's working-copy commit shares all parents with the old one.
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 46ed31b61ce9 default@
|
||
├─╮
|
||
│ │ ○ d23b2d4ff55c second@
|
||
╭─┬─╯
|
||
│ ○ 3c52528f5893
|
||
○ │ a3155ab1bf5a
|
||
├─╯
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
/// Test that --ignore-working-copy is respected
|
||
#[test]
|
||
fn test_workspaces_add_ignore_working_copy() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
|
||
// TODO: maybe better to error out early?
|
||
let output = main_dir.run_jj(["workspace", "add", "--ignore-working-copy", "../secondary"]);
|
||
insta::assert_snapshot!(output.normalize_backslash(), @r#"
|
||
------- stderr -------
|
||
Created workspace in "../secondary"
|
||
Error: This command must be able to update the working copy.
|
||
Hint: Don't use --ignore-working-copy.
|
||
[EOF]
|
||
[exit status: 1]
|
||
"#);
|
||
}
|
||
|
||
/// Test that --at-op is respected
|
||
#[test]
|
||
fn test_workspaces_add_at_operation() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
|
||
main_dir.write_file("file1", "");
|
||
let output = main_dir.run_jj(["commit", "-m1"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Working copy (@) now at: rlvkpnrz 59e07459 (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm 9e4b0b91 1
|
||
[EOF]
|
||
");
|
||
|
||
main_dir.write_file("file2", "");
|
||
let output = main_dir.run_jj(["commit", "-m2"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Working copy (@) now at: kkmpptxz 6e9610ac (empty) (no description set)
|
||
Parent commit (@-) : rlvkpnrz 8b7259b9 2
|
||
[EOF]
|
||
");
|
||
|
||
// --at-op should disable snapshot in the main workspace, but the newly
|
||
// created workspace should still be writable.
|
||
main_dir.write_file("file3", "");
|
||
let output = main_dir.run_jj(["workspace", "add", "--at-op=@-", "../secondary"]);
|
||
insta::assert_snapshot!(output.normalize_backslash(), @r#"
|
||
------- stderr -------
|
||
Created workspace in "../secondary"
|
||
Working copy (@) now at: rzvqmyuk b8772476 (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm 9e4b0b91 1
|
||
Added 1 files, modified 0 files, removed 0 files
|
||
[EOF]
|
||
"#);
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
// New snapshot can be taken in the secondary workspace.
|
||
secondary_dir.write_file("file4", "");
|
||
let output = secondary_dir.run_jj(["status"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
Working copy changes:
|
||
A file4
|
||
Working copy (@) : rzvqmyuk f2ff8257 (no description set)
|
||
Parent commit (@-): qpvuntsm 9e4b0b91 1
|
||
[EOF]
|
||
------- stderr -------
|
||
Concurrent modification detected, resolving automatically.
|
||
[EOF]
|
||
");
|
||
|
||
let output = secondary_dir.run_jj(["op", "log", "-Tdescription"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
@ snapshot working copy
|
||
○ reconcile divergent operations
|
||
├─╮
|
||
○ │ commit 9152e822279787a168ddf4cede6440a21faa00d7
|
||
│ ○ create initial working-copy commit in workspace secondary
|
||
│ ○ add workspace 'secondary'
|
||
├─╯
|
||
○ snapshot working copy
|
||
○ commit 093c3c9624b6cfe22b310586f5638792aa80e6d7
|
||
○ snapshot working copy
|
||
○ add workspace 'default'
|
||
○
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
/// Test adding a workspace, but at a specific revision using '-r'
|
||
#[test]
|
||
fn test_workspaces_add_workspace_at_revision() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
main_dir.write_file("file-1", "contents");
|
||
main_dir.run_jj(["commit", "-m", "first"]).success();
|
||
|
||
main_dir.write_file("file-2", "contents");
|
||
main_dir.run_jj(["commit", "-m", "second"]).success();
|
||
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: kkmpptxz 5ac9178d (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
let output = main_dir.run_jj([
|
||
"workspace",
|
||
"add",
|
||
"--name",
|
||
"second",
|
||
"../secondary",
|
||
"-r",
|
||
"@--",
|
||
]);
|
||
insta::assert_snapshot!(output.normalize_backslash(), @r#"
|
||
------- stderr -------
|
||
Created workspace in "../secondary"
|
||
Working copy (@) now at: zxsnswpr ea5860fb (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm 27473635 first
|
||
Added 1 files, modified 0 files, removed 0 files
|
||
[EOF]
|
||
"#);
|
||
|
||
// Can see the working-copy commit in each workspace in the log output. The "@"
|
||
// node in the graph indicates the current workspace's working-copy commit.
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 5ac9178da8b2 default@
|
||
○ a47d8a593529
|
||
│ ○ ea5860fbd622 second@
|
||
├─╯
|
||
○ 27473635a942
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
insta::assert_snapshot!(get_log_output(&secondary_dir), @r"
|
||
@ ea5860fbd622 second@
|
||
│ ○ 5ac9178da8b2 default@
|
||
│ ○ a47d8a593529
|
||
├─╯
|
||
○ 27473635a942
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
/// Test multiple `-r` flags to `workspace add` to create a workspace
|
||
/// working-copy commit with multiple parents.
|
||
#[test]
|
||
fn test_workspaces_add_workspace_multiple_revisions() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
|
||
main_dir.write_file("file-1", "contents");
|
||
main_dir.run_jj(["commit", "-m", "first"]).success();
|
||
main_dir.run_jj(["new", "-r", "root()"]).success();
|
||
|
||
main_dir.write_file("file-2", "contents");
|
||
main_dir.run_jj(["commit", "-m", "second"]).success();
|
||
main_dir.run_jj(["new", "-r", "root()"]).success();
|
||
|
||
main_dir.write_file("file-3", "contents");
|
||
main_dir.run_jj(["commit", "-m", "third"]).success();
|
||
main_dir.run_jj(["new", "-r", "root()"]).success();
|
||
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 8d23abddc924
|
||
│ ○ eba7f49e2358
|
||
├─╯
|
||
│ ○ 62444a45efcf
|
||
├─╯
|
||
│ ○ 27473635a942
|
||
├─╯
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
|
||
let output = main_dir.run_jj([
|
||
"workspace",
|
||
"add",
|
||
"--name=merge",
|
||
"../merged",
|
||
"-r=description(third)",
|
||
"-r=description(second)",
|
||
"-r=description(first)",
|
||
]);
|
||
insta::assert_snapshot!(output.normalize_backslash(), @r#"
|
||
------- stderr -------
|
||
Created workspace in "../merged"
|
||
Working copy (@) now at: wmwvqwsz 2d7c9a2d (empty) (no description set)
|
||
Parent commit (@-) : mzvwutvl eba7f49e third
|
||
Parent commit (@-) : kkmpptxz 62444a45 second
|
||
Parent commit (@-) : qpvuntsm 27473635 first
|
||
Added 3 files, modified 0 files, removed 0 files
|
||
[EOF]
|
||
"#);
|
||
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 8d23abddc924 default@
|
||
│ ○ 2d7c9a2d41dc merge@
|
||
│ ├─┬─╮
|
||
│ │ │ ○ 27473635a942
|
||
├─────╯
|
||
│ │ ○ 62444a45efcf
|
||
├───╯
|
||
│ ○ eba7f49e2358
|
||
├─╯
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
#[test]
|
||
fn test_workspaces_add_workspace_from_subdir() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
let subdir_dir = main_dir.create_dir("subdir");
|
||
subdir_dir.write_file("file", "contents");
|
||
main_dir.run_jj(["commit", "-m", "initial"]).success();
|
||
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: rlvkpnrz 0ba0ff35 (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
// Create workspace while in sub-directory of current workspace
|
||
let output = subdir_dir.run_jj(["workspace", "add", "../../secondary"]);
|
||
insta::assert_snapshot!(output.normalize_backslash(), @r#"
|
||
------- stderr -------
|
||
Created workspace in "../../secondary"
|
||
Working copy (@) now at: rzvqmyuk dea1be10 (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm 80b67806 initial
|
||
Added 1 files, modified 0 files, removed 0 files
|
||
[EOF]
|
||
"#);
|
||
|
||
// Both workspaces show up when we list them
|
||
let output = secondary_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: rlvkpnrz 0ba0ff35 (empty) (no description set)
|
||
secondary: rzvqmyuk dea1be10 (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
#[test]
|
||
fn test_workspaces_add_workspace_in_current_workspace() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
|
||
main_dir.write_file("file", "contents");
|
||
main_dir.run_jj(["commit", "-m", "initial"]).success();
|
||
|
||
// Try to create workspace using name instead of path
|
||
let output = main_dir.run_jj(["workspace", "add", "secondary"]);
|
||
insta::assert_snapshot!(output.normalize_backslash(), @r#"
|
||
------- stderr -------
|
||
Created workspace in "secondary"
|
||
Warning: Workspace created inside current directory. If this was unintentional, delete the "secondary" directory and run `jj workspace forget secondary` to remove it.
|
||
Working copy (@) now at: pmmvwywv 058f604d (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm 7b22a8cb initial
|
||
Added 1 files, modified 0 files, removed 0 files
|
||
[EOF]
|
||
"#);
|
||
|
||
// Workspace created despite warning
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: rlvkpnrz af2d0cd5 (no description set)
|
||
secondary: pmmvwywv 058f604d (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
// Use explicit path instead (no warning)
|
||
let output = main_dir.run_jj(["workspace", "add", "./third"]);
|
||
insta::assert_snapshot!(output.normalize_backslash(), @r#"
|
||
------- stderr -------
|
||
Created workspace in "third"
|
||
Working copy (@) now at: zxsnswpr 1c1effec (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm 7b22a8cb initial
|
||
Added 1 files, modified 0 files, removed 0 files
|
||
[EOF]
|
||
"#);
|
||
|
||
// Both workspaces created
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: rlvkpnrz b2288847 (no description set)
|
||
secondary: pmmvwywv 058f604d (empty) (no description set)
|
||
third: zxsnswpr 1c1effec (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
// Can see files from the other workspaces in main workspace, since they are
|
||
// child directories and will therefore be snapshotted
|
||
let output = main_dir.run_jj(["file", "list"]);
|
||
insta::assert_snapshot!(output.normalize_backslash(), @r"
|
||
file
|
||
secondary/file
|
||
third/file
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
/// Test making changes to the working copy in a workspace as it gets rewritten
|
||
/// from another workspace
|
||
#[test]
|
||
fn test_workspaces_conflicting_edits() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
main_dir.write_file("file", "contents\n");
|
||
main_dir.run_jj(["new"]).success();
|
||
|
||
main_dir
|
||
.run_jj(["workspace", "add", "../secondary"])
|
||
.success();
|
||
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 393250c59e39 default@
|
||
│ ○ 547036666102 secondary@
|
||
├─╯
|
||
○ 9a462e35578a
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
|
||
// Make changes in both working copies
|
||
main_dir.write_file("file", "changed in main\n");
|
||
secondary_dir.write_file("file", "changed in second\n");
|
||
// Squash the changes from the main workspace into the initial commit (before
|
||
// running any command in the secondary workspace
|
||
let output = main_dir.run_jj(["squash"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Rebased 1 descendant commits
|
||
Working copy (@) now at: mzvwutvl 3a9b690d (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm b853f7c8 (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
// The secondary workspace's working-copy commit was updated
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 3a9b690d6e67 default@
|
||
│ ○ 90f3d42e0bff secondary@
|
||
├─╯
|
||
○ b853f7c8b006
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
let output = secondary_dir.run_jj(["st"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Error: The working copy is stale (not updated since operation 09c578c227de).
|
||
Hint: Run `jj workspace update-stale` to update it.
|
||
See https://jj-vcs.github.io/jj/latest/working-copy/#stale-working-copy for more information.
|
||
[EOF]
|
||
[exit status: 1]
|
||
");
|
||
// Same error on second run, and from another command
|
||
let output = secondary_dir.run_jj(["log"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Error: The working copy is stale (not updated since operation 09c578c227de).
|
||
Hint: Run `jj workspace update-stale` to update it.
|
||
See https://jj-vcs.github.io/jj/latest/working-copy/#stale-working-copy for more information.
|
||
[EOF]
|
||
[exit status: 1]
|
||
");
|
||
// It was detected that the working copy is now stale.
|
||
// Since there was an uncommitted change in the working copy, it should
|
||
// have been committed first (causing divergence)
|
||
let output = secondary_dir.run_jj(["workspace", "update-stale"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Concurrent modification detected, resolving automatically.
|
||
Rebased 1 descendant commits onto commits rewritten by other operation
|
||
Working copy (@) now at: pmmvwywv?? 90f3d42e (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm b853f7c8 (no description set)
|
||
Added 0 files, modified 1 files, removed 0 files
|
||
Updated working copy to fresh commit 90f3d42e0bff
|
||
[EOF]
|
||
");
|
||
insta::assert_snapshot!(get_log_output(&secondary_dir),
|
||
@r"
|
||
@ 90f3d42e0bff secondary@ (divergent)
|
||
│ × de7155dbea42 (divergent)
|
||
├─╯
|
||
│ ○ 3a9b690d6e67 default@
|
||
├─╯
|
||
○ b853f7c8b006
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
// The stale working copy should have been resolved by the previous command
|
||
insta::assert_snapshot!(get_log_output(&secondary_dir), @r"
|
||
@ 90f3d42e0bff secondary@ (divergent)
|
||
│ × de7155dbea42 (divergent)
|
||
├─╯
|
||
│ ○ 3a9b690d6e67 default@
|
||
├─╯
|
||
○ b853f7c8b006
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
/// Test a clean working copy that gets rewritten from another workspace
|
||
#[test]
|
||
fn test_workspaces_updated_by_other() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
main_dir.write_file("file", "contents\n");
|
||
main_dir.run_jj(["new"]).success();
|
||
|
||
main_dir
|
||
.run_jj(["workspace", "add", "../secondary"])
|
||
.success();
|
||
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 393250c59e39 default@
|
||
│ ○ 547036666102 secondary@
|
||
├─╯
|
||
○ 9a462e35578a
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
|
||
// Rewrite the check-out commit in one workspace.
|
||
main_dir.write_file("file", "changed in main\n");
|
||
let output = main_dir.run_jj(["squash"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Rebased 1 descendant commits
|
||
Working copy (@) now at: mzvwutvl 3a9b690d (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm b853f7c8 (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
// The secondary workspace's working-copy commit was updated.
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 3a9b690d6e67 default@
|
||
│ ○ 90f3d42e0bff secondary@
|
||
├─╯
|
||
○ b853f7c8b006
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
let output = secondary_dir.run_jj(["st"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Error: The working copy is stale (not updated since operation 09c578c227de).
|
||
Hint: Run `jj workspace update-stale` to update it.
|
||
See https://jj-vcs.github.io/jj/latest/working-copy/#stale-working-copy for more information.
|
||
[EOF]
|
||
[exit status: 1]
|
||
");
|
||
// It was detected that the working copy is now stale, but clean. So no
|
||
// divergent commit should be created.
|
||
let output = secondary_dir.run_jj(["workspace", "update-stale"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Working copy (@) now at: pmmvwywv 90f3d42e (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm b853f7c8 (no description set)
|
||
Added 0 files, modified 1 files, removed 0 files
|
||
Updated working copy to fresh commit 90f3d42e0bff
|
||
[EOF]
|
||
");
|
||
insta::assert_snapshot!(get_log_output(&secondary_dir),
|
||
@r"
|
||
@ 90f3d42e0bff secondary@
|
||
│ ○ 3a9b690d6e67 default@
|
||
├─╯
|
||
○ b853f7c8b006
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
/// Test a clean working copy that gets rewritten from another workspace
|
||
#[test]
|
||
fn test_workspaces_updated_by_other_automatic() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.add_config("[snapshot]\nauto-update-stale = true\n");
|
||
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
main_dir.write_file("file", "contents\n");
|
||
main_dir.run_jj(["new"]).success();
|
||
|
||
main_dir
|
||
.run_jj(["workspace", "add", "../secondary"])
|
||
.success();
|
||
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 393250c59e39 default@
|
||
│ ○ 547036666102 secondary@
|
||
├─╯
|
||
○ 9a462e35578a
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
|
||
// Rewrite the check-out commit in one workspace.
|
||
main_dir.write_file("file", "changed in main\n");
|
||
let output = main_dir.run_jj(["squash"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Rebased 1 descendant commits
|
||
Working copy (@) now at: mzvwutvl 3a9b690d (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm b853f7c8 (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
// The secondary workspace's working-copy commit was updated.
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 3a9b690d6e67 default@
|
||
│ ○ 90f3d42e0bff secondary@
|
||
├─╯
|
||
○ b853f7c8b006
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
|
||
// The first working copy gets automatically updated.
|
||
let output = secondary_dir.run_jj(["st"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
The working copy has no changes.
|
||
Working copy (@) : pmmvwywv 90f3d42e (empty) (no description set)
|
||
Parent commit (@-): qpvuntsm b853f7c8 (no description set)
|
||
[EOF]
|
||
------- stderr -------
|
||
Working copy (@) now at: pmmvwywv 90f3d42e (empty) (no description set)
|
||
Parent commit (@-) : qpvuntsm b853f7c8 (no description set)
|
||
Added 0 files, modified 1 files, removed 0 files
|
||
Updated working copy to fresh commit 90f3d42e0bff
|
||
[EOF]
|
||
");
|
||
|
||
insta::assert_snapshot!(get_log_output(&secondary_dir),
|
||
@r"
|
||
@ 90f3d42e0bff secondary@
|
||
│ ○ 3a9b690d6e67 default@
|
||
├─╯
|
||
○ b853f7c8b006
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
#[test_case(false; "manual")]
|
||
#[test_case(true; "automatic")]
|
||
fn test_workspaces_current_op_discarded_by_other(automatic: bool) {
|
||
let test_env = TestEnvironment::default();
|
||
if automatic {
|
||
test_env.add_config("[snapshot]\nauto-update-stale = true\n");
|
||
}
|
||
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
main_dir.write_file("modified", "base\n");
|
||
main_dir.write_file("deleted", "base\n");
|
||
main_dir.write_file("sparse", "base\n");
|
||
main_dir.run_jj(["new"]).success();
|
||
main_dir.write_file("modified", "main\n");
|
||
main_dir.run_jj(["new"]).success();
|
||
|
||
main_dir
|
||
.run_jj(["workspace", "add", "../secondary"])
|
||
.success();
|
||
// Make unsnapshotted writes in the secondary working copy
|
||
secondary_dir
|
||
.run_jj([
|
||
"sparse",
|
||
"set",
|
||
"--clear",
|
||
"--add=modified",
|
||
"--add=deleted",
|
||
"--add=added",
|
||
])
|
||
.success();
|
||
secondary_dir.write_file("modified", "secondary\n");
|
||
secondary_dir.remove_file("deleted");
|
||
secondary_dir.write_file("added", "secondary\n");
|
||
|
||
// Create an op by abandoning the parent commit. Importantly, that commit also
|
||
// changes the target tree in the secondary workspace.
|
||
main_dir.run_jj(["abandon", "@-"]).success();
|
||
|
||
let output = main_dir.run_jj([
|
||
"operation",
|
||
"log",
|
||
"--template",
|
||
r#"id.short(10) ++ " " ++ description"#,
|
||
]);
|
||
insta::allow_duplicates! {
|
||
insta::assert_snapshot!(output, @r"
|
||
@ e426bb88ce abandon commit de90575a14d8b9198dc0930f9de4a69f846ded36
|
||
○ c1d0d40e1f create initial working-copy commit in workspace secondary
|
||
○ 5869a42f65 add workspace 'secondary'
|
||
○ 72b8205d96 new empty commit
|
||
○ 6e671162a7 snapshot working copy
|
||
○ 5213f1e3a9 new empty commit
|
||
○ b1bf0cc848 snapshot working copy
|
||
○ 2affa70252 add workspace 'default'
|
||
○ 0000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
// Abandon ops, including the one the secondary workspace is currently on.
|
||
main_dir.run_jj(["operation", "abandon", "..@-"]).success();
|
||
main_dir.run_jj(["util", "gc", "--expire=now"]).success();
|
||
|
||
insta::allow_duplicates! {
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 320bc89effc9 default@
|
||
│ ○ 891f00062e10 secondary@
|
||
├─╯
|
||
○ 367415be5b44
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
if automatic {
|
||
// Run a no-op command to set the randomness seed for commit hashes.
|
||
secondary_dir.run_jj(["help"]).success();
|
||
|
||
let output = secondary_dir.run_jj(["st"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
Working copy changes:
|
||
C {modified => added}
|
||
D deleted
|
||
M modified
|
||
Working copy (@) : kmkuslsw 18851b39 RECOVERY COMMIT FROM `jj workspace update-stale`
|
||
Parent commit (@-): rzvqmyuk 891f0006 (empty) (no description set)
|
||
[EOF]
|
||
------- stderr -------
|
||
Failed to read working copy's current operation; attempting recovery. Error message from read attempt: Object c1d0d40e1f9ef1e820a494113c16a66dd3550fe2d1a3231027f4305ad1f85956697de9ffdd2ec1e714a1e6ec419c6369c8a2abf91223b4732358e6929acf5ae8 of type operation not found
|
||
Created and checked out recovery commit 866928d1e0fd
|
||
[EOF]
|
||
");
|
||
} else {
|
||
let output = secondary_dir.run_jj(["st"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Error: Could not read working copy's operation.
|
||
Hint: Run `jj workspace update-stale` to recover.
|
||
See https://jj-vcs.github.io/jj/latest/working-copy/#stale-working-copy for more information.
|
||
[EOF]
|
||
[exit status: 1]
|
||
");
|
||
|
||
let output = secondary_dir.run_jj(["workspace", "update-stale"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Failed to read working copy's current operation; attempting recovery. Error message from read attempt: Object c1d0d40e1f9ef1e820a494113c16a66dd3550fe2d1a3231027f4305ad1f85956697de9ffdd2ec1e714a1e6ec419c6369c8a2abf91223b4732358e6929acf5ae8 of type operation not found
|
||
Created and checked out recovery commit 866928d1e0fd
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
insta::allow_duplicates! {
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 320bc89effc9 default@
|
||
│ ○ 18851b397d09 secondary@
|
||
│ ○ 891f00062e10
|
||
├─╯
|
||
○ 367415be5b44
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
// The sparse patterns should remain
|
||
let output = secondary_dir.run_jj(["sparse", "list"]);
|
||
insta::allow_duplicates! {
|
||
insta::assert_snapshot!(output, @r"
|
||
added
|
||
deleted
|
||
modified
|
||
[EOF]
|
||
");
|
||
}
|
||
let output = secondary_dir.run_jj(["st"]);
|
||
insta::allow_duplicates! {
|
||
insta::assert_snapshot!(output, @r"
|
||
Working copy changes:
|
||
C {modified => added}
|
||
D deleted
|
||
M modified
|
||
Working copy (@) : kmkuslsw 18851b39 RECOVERY COMMIT FROM `jj workspace update-stale`
|
||
Parent commit (@-): rzvqmyuk 891f0006 (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
}
|
||
insta::allow_duplicates! {
|
||
// The modified file should have the same contents it had before (not reset to
|
||
// the base contents)
|
||
insta::assert_snapshot!(secondary_dir.read_file("modified"), @"secondary");
|
||
}
|
||
|
||
let output = secondary_dir.run_jj(["evolog"]);
|
||
insta::allow_duplicates! {
|
||
insta::assert_snapshot!(output, @r"
|
||
@ kmkuslsw test.user@example.com 2001-02-03 08:05:18 secondary@ 18851b39
|
||
│ RECOVERY COMMIT FROM `jj workspace update-stale`
|
||
○ kmkuslsw hidden test.user@example.com 2001-02-03 08:05:18 866928d1
|
||
(empty) RECOVERY COMMIT FROM `jj workspace update-stale`
|
||
[EOF]
|
||
");
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn test_workspaces_update_stale_noop() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
|
||
let output = main_dir.run_jj(["workspace", "update-stale"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Attempted recovery, but the working copy is not stale
|
||
[EOF]
|
||
");
|
||
|
||
let output = main_dir.run_jj(["workspace", "update-stale", "--ignore-working-copy"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Error: This command must be able to update the working copy.
|
||
Hint: Don't use --ignore-working-copy.
|
||
[EOF]
|
||
[exit status: 1]
|
||
");
|
||
|
||
let output = main_dir.run_jj(["op", "log", "-Tdescription"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
@ add workspace 'default'
|
||
○
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
/// Test "update-stale" in a dirty, but not stale working copy.
|
||
#[test]
|
||
fn test_workspaces_update_stale_snapshot() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
main_dir.write_file("file", "changed in main\n");
|
||
main_dir.run_jj(["new"]).success();
|
||
main_dir
|
||
.run_jj(["workspace", "add", "../secondary"])
|
||
.success();
|
||
|
||
// Record new operation in one workspace.
|
||
main_dir.run_jj(["new"]).success();
|
||
|
||
// Snapshot the other working copy, which unfortunately results in concurrent
|
||
// operations, but should be resolved cleanly.
|
||
secondary_dir.write_file("file", "changed in second\n");
|
||
let output = secondary_dir.run_jj(["workspace", "update-stale"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Concurrent modification detected, resolving automatically.
|
||
Attempted recovery, but the working copy is not stale
|
||
[EOF]
|
||
");
|
||
|
||
insta::assert_snapshot!(get_log_output(&secondary_dir), @r"
|
||
@ 35d779b3baea secondary@
|
||
│ ○ c9516583d53b default@
|
||
│ ○ f6ae7810ef56
|
||
├─╯
|
||
○ 7d5738ba9943
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
/// Test forgetting workspaces
|
||
#[test]
|
||
fn test_workspaces_forget() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
|
||
main_dir.write_file("file", "contents");
|
||
main_dir.run_jj(["new"]).success();
|
||
|
||
main_dir
|
||
.run_jj(["workspace", "add", "../secondary"])
|
||
.success();
|
||
let output = main_dir.run_jj(["workspace", "forget"]);
|
||
insta::assert_snapshot!(output, @"");
|
||
|
||
// When listing workspaces, only the secondary workspace shows up
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
secondary: pmmvwywv 31da1455 (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
// `jj status` tells us that there's no working copy here
|
||
let output = main_dir.run_jj(["st"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
No working copy
|
||
[EOF]
|
||
");
|
||
|
||
// The old working copy doesn't get an "@" in the log output
|
||
// TODO: It seems useful to still have the "secondary@" marker here even though
|
||
// there's only one workspace. We should show it when the command is not run
|
||
// from that workspace.
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
○ 31da14559558
|
||
○ 006bd1130b84
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
|
||
// Revision "@" cannot be used
|
||
let output = main_dir.run_jj(["log", "-r", "@"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Error: Workspace `default` doesn't have a working-copy commit
|
||
[EOF]
|
||
[exit status: 1]
|
||
");
|
||
|
||
// Try to add back the workspace
|
||
// TODO: We should make this just add it back instead of failing
|
||
let output = main_dir.run_jj(["workspace", "add", "."]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Error: Workspace already exists
|
||
[EOF]
|
||
[exit status: 1]
|
||
");
|
||
|
||
// Add a third workspace...
|
||
main_dir.run_jj(["workspace", "add", "../third"]).success();
|
||
// ... and then forget it, and the secondary workspace too
|
||
let output = main_dir.run_jj(["workspace", "forget", "secondary", "third"]);
|
||
insta::assert_snapshot!(output, @"");
|
||
// No workspaces left
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @"");
|
||
}
|
||
|
||
#[test]
|
||
fn test_workspaces_forget_multi_transaction() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
|
||
main_dir.write_file("file", "contents");
|
||
main_dir.run_jj(["new"]).success();
|
||
|
||
main_dir.run_jj(["workspace", "add", "../second"]).success();
|
||
main_dir.run_jj(["workspace", "add", "../third"]).success();
|
||
|
||
// there should be three workspaces
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: rlvkpnrz f6bf8819 (empty) (no description set)
|
||
second: pmmvwywv 31da1455 (empty) (no description set)
|
||
third: rzvqmyuk bf5b5b4d (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
// delete two at once, in a single tx
|
||
main_dir
|
||
.run_jj(["workspace", "forget", "second", "third"])
|
||
.success();
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: rlvkpnrz f6bf8819 (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
// the op log should have multiple workspaces forgotten in a single tx
|
||
let output = main_dir.run_jj(["op", "log", "--limit", "1"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
@ ccedd4f34298 test-username@host.example.com 2001-02-03 04:05:12.000 +07:00 - 2001-02-03 04:05:12.000 +07:00
|
||
│ forget workspaces second, third
|
||
│ args: jj workspace forget second third
|
||
[EOF]
|
||
");
|
||
|
||
// now, undo, and that should restore both workspaces
|
||
main_dir.run_jj(["op", "undo"]).success();
|
||
|
||
// finally, there should be three workspaces at the end
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: rlvkpnrz f6bf8819 (empty) (no description set)
|
||
second: pmmvwywv 31da1455 (empty) (no description set)
|
||
third: rzvqmyuk bf5b5b4d (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
#[test]
|
||
fn test_workspaces_forget_abandon_commits() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
|
||
main_dir.write_file("file", "contents");
|
||
|
||
main_dir.run_jj(["workspace", "add", "../second"]).success();
|
||
main_dir.run_jj(["workspace", "add", "../third"]).success();
|
||
main_dir.run_jj(["workspace", "add", "../fourth"]).success();
|
||
let third_dir = test_env.work_dir("third");
|
||
third_dir.run_jj(["edit", "second@"]).success();
|
||
let fourth_dir = test_env.work_dir("fourth");
|
||
fourth_dir.run_jj(["edit", "second@"]).success();
|
||
|
||
// there should be four workspaces, three of which are at the same empty commit
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: qpvuntsm 006bd113 (no description set)
|
||
fourth: uuqppmxq 94f41578 (empty) (no description set)
|
||
second: uuqppmxq 94f41578 (empty) (no description set)
|
||
third: uuqppmxq 94f41578 (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ 006bd1130b84 default@
|
||
│ ○ 94f41578a9e1 fourth@ second@ third@
|
||
├─╯
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
|
||
// delete the default workspace (should not abandon commit since not empty)
|
||
main_dir
|
||
.run_jj(["workspace", "forget", "default"])
|
||
.success();
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
○ 94f41578a9e1 fourth@ second@ third@
|
||
│ ○ 006bd1130b84
|
||
├─╯
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
|
||
// delete the second workspace (should not abandon commit since other workspaces
|
||
// still have commit checked out)
|
||
main_dir.run_jj(["workspace", "forget", "second"]).success();
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
○ 94f41578a9e1 fourth@ third@
|
||
│ ○ 006bd1130b84
|
||
├─╯
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
|
||
// delete the last 2 workspaces (commit should be abandoned now even though
|
||
// forgotten in same tx)
|
||
main_dir
|
||
.run_jj(["workspace", "forget", "third", "fourth"])
|
||
.success();
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
○ 006bd1130b84
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
/// Test context of commit summary template
|
||
#[test]
|
||
fn test_list_workspaces_template() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
test_env.add_config(
|
||
r#"
|
||
templates.commit_summary = """commit_id.short() ++ " " ++ description.first_line() ++
|
||
if(current_working_copy, " (current)")"""
|
||
"#,
|
||
);
|
||
let main_dir = test_env.work_dir("main");
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
main_dir.write_file("file", "contents");
|
||
main_dir.run_jj(["commit", "-m", "initial"]).success();
|
||
main_dir
|
||
.run_jj(["workspace", "add", "--name", "second", "../secondary"])
|
||
.success();
|
||
|
||
// "current_working_copy" should point to the workspace we operate on
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: 504e3d8c1bcd (current)
|
||
second: 058f604dffcd
|
||
[EOF]
|
||
");
|
||
|
||
let output = secondary_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: 504e3d8c1bcd
|
||
second: 058f604dffcd (current)
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
/// Test getting the workspace root from primary and secondary workspaces
|
||
#[test]
|
||
fn test_workspaces_root() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
let output = main_dir.run_jj(["workspace", "root"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
$TEST_ENV/main
|
||
[EOF]
|
||
");
|
||
let main_subdir_dir = main_dir.create_dir("subdir");
|
||
let output = main_subdir_dir.run_jj(["workspace", "root"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
$TEST_ENV/main
|
||
[EOF]
|
||
");
|
||
|
||
main_dir
|
||
.run_jj(["workspace", "add", "--name", "secondary", "../secondary"])
|
||
.success();
|
||
let output = secondary_dir.run_jj(["workspace", "root"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
$TEST_ENV/secondary
|
||
[EOF]
|
||
");
|
||
let secondary_subdir_dir = secondary_dir.create_dir("subdir");
|
||
let output = secondary_subdir_dir.run_jj(["workspace", "root"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
$TEST_ENV/secondary
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
#[test]
|
||
fn test_debug_snapshot() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
||
let work_dir = test_env.work_dir("repo");
|
||
|
||
work_dir.write_file("file", "contents");
|
||
work_dir.run_jj(["debug", "snapshot"]).success();
|
||
let output = work_dir.run_jj(["op", "log"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
@ 05a77f06d585 test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00
|
||
│ snapshot working copy
|
||
│ args: jj debug snapshot
|
||
○ 2affa7025254 test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00
|
||
│ add workspace 'default'
|
||
○ 000000000000 root()
|
||
[EOF]
|
||
");
|
||
work_dir.run_jj(["describe", "-m", "initial"]).success();
|
||
let output = work_dir.run_jj(["op", "log"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
@ 2c73e89e3beb test-username@host.example.com 2001-02-03 04:05:10.000 +07:00 - 2001-02-03 04:05:10.000 +07:00
|
||
│ describe commit 006bd1130b84e90ab082adeabd7409270d5a86da
|
||
│ args: jj describe -m initial
|
||
○ 05a77f06d585 test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00
|
||
│ snapshot working copy
|
||
│ args: jj debug snapshot
|
||
○ 2affa7025254 test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00
|
||
│ add workspace 'default'
|
||
○ 000000000000 root()
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
#[test]
|
||
fn test_workspaces_rename_nothing_changed() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
let output = main_dir.run_jj(["workspace", "rename", "default"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Nothing changed.
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
#[test]
|
||
fn test_workspaces_rename_new_workspace_name_already_used() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
main_dir
|
||
.run_jj(["workspace", "add", "--name", "second", "../secondary"])
|
||
.success();
|
||
let output = main_dir.run_jj(["workspace", "rename", "second"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Error: Failed to rename a workspace
|
||
Caused by: Workspace second already exists
|
||
[EOF]
|
||
[exit status: 1]
|
||
");
|
||
}
|
||
|
||
#[test]
|
||
fn test_workspaces_rename_forgotten_workspace() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
main_dir
|
||
.run_jj(["workspace", "add", "--name", "second", "../secondary"])
|
||
.success();
|
||
main_dir.run_jj(["workspace", "forget", "second"]).success();
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
let output = secondary_dir.run_jj(["workspace", "rename", "third"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
------- stderr -------
|
||
Error: The current workspace 'second' is not tracked in the repo.
|
||
[EOF]
|
||
[exit status: 1]
|
||
");
|
||
}
|
||
|
||
#[test]
|
||
fn test_workspaces_rename_workspace() {
|
||
let test_env = TestEnvironment::default();
|
||
test_env.run_jj_in(".", ["git", "init", "main"]).success();
|
||
let main_dir = test_env.work_dir("main");
|
||
main_dir
|
||
.run_jj(["workspace", "add", "--name", "second", "../secondary"])
|
||
.success();
|
||
let secondary_dir = test_env.work_dir("secondary");
|
||
|
||
// Both workspaces show up when we list them
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: qpvuntsm e8849ae1 (empty) (no description set)
|
||
second: uuqppmxq 94f41578 (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
let output = secondary_dir.run_jj(["workspace", "rename", "third"]);
|
||
insta::assert_snapshot!(output, @"");
|
||
|
||
let output = main_dir.run_jj(["workspace", "list"]);
|
||
insta::assert_snapshot!(output, @r"
|
||
default: qpvuntsm e8849ae1 (empty) (no description set)
|
||
third: uuqppmxq 94f41578 (empty) (no description set)
|
||
[EOF]
|
||
");
|
||
|
||
// Can see the working-copy commit in each workspace in the log output.
|
||
insta::assert_snapshot!(get_log_output(&main_dir), @r"
|
||
@ e8849ae12c70 default@
|
||
│ ○ 94f41578a9e1 third@
|
||
├─╯
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
insta::assert_snapshot!(get_log_output(&secondary_dir), @r"
|
||
@ 94f41578a9e1 third@
|
||
│ ○ e8849ae12c70 default@
|
||
├─╯
|
||
◆ 000000000000
|
||
[EOF]
|
||
");
|
||
}
|
||
|
||
#[must_use]
|
||
fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput {
|
||
let template = r#"
|
||
separate(" ",
|
||
commit_id.short(),
|
||
working_copies,
|
||
if(divergent, "(divergent)"),
|
||
)
|
||
"#;
|
||
work_dir.run_jj(["log", "-T", template, "-r", "all()"])
|
||
}
|