2022-11-26 23:57:50 +00:00
|
|
|
|
// Copyright 2022 The Jujutsu Authors
|
2022-04-22 04:49:57 +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.
|
|
|
|
|
|
|
|
|
|
use std::path::Path;
|
|
|
|
|
|
|
|
|
|
use crate::common::TestEnvironment;
|
|
|
|
|
|
|
|
|
|
/// Test adding a second workspace
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_add_second_workspace() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
let secondary_path = test_env.env_root().join("secondary");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file"), "contents").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["commit", "-m", "initial"]);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
2022-04-28 23:32:18 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
default: rlvkpnrz 8183d0fc (empty) (no description set)
|
2022-04-28 23:32:18 +00:00
|
|
|
|
"###);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(
|
2022-04-22 04:49:57 +00:00
|
|
|
|
&main_path,
|
|
|
|
|
&["workspace", "add", "--name", "second", "../secondary"],
|
|
|
|
|
);
|
2023-10-10 11:07:06 +00:00
|
|
|
|
insta::assert_snapshot!(stdout.replace('\\', "/"), @"");
|
|
|
|
|
insta::assert_snapshot!(stderr.replace('\\', "/"), @r###"
|
2022-04-22 04:49:57 +00:00
|
|
|
|
Created workspace in "../secondary"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
Working copy now at: rzvqmyuk 5ed2222c (empty) (no description set)
|
|
|
|
|
Parent commit : qpvuntsm 751b12b7 initial
|
2022-04-22 04:49:57 +00:00
|
|
|
|
Added 1 files, modified 0 files, removed 0 files
|
|
|
|
|
"###);
|
|
|
|
|
|
2023-01-25 16:29:15 +00:00
|
|
|
|
// 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.
|
2022-04-22 04:49:57 +00:00
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 5ed2222c28e2 second@
|
2024-06-23 22:20:33 +00:00
|
|
|
|
│ @ 8183d0fcaa4c default@
|
2023-02-09 02:53:47 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 751b12b7b981
|
|
|
|
|
◆ 000000000000
|
2022-04-22 04:49:57 +00:00
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
@ 5ed2222c28e2 second@
|
2024-07-15 22:20:10 +00:00
|
|
|
|
│ ○ 8183d0fcaa4c default@
|
2023-02-09 02:53:47 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 751b12b7b981
|
|
|
|
|
◆ 000000000000
|
2022-04-22 04:49:57 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Both workspaces show up when we list them
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
default: rlvkpnrz 8183d0fc (empty) (no description set)
|
|
|
|
|
second: rzvqmyuk 5ed2222c (empty) (no description set)
|
2022-04-22 04:49:57 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-17 16:48:29 +00:00
|
|
|
|
/// Test how sparse patterns are inherited
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_sparse_patterns() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "ws1"]);
|
2024-02-17 16:48:29 +00:00
|
|
|
|
let ws1_path = test_env.env_root().join("ws1");
|
|
|
|
|
let ws2_path = test_env.env_root().join("ws2");
|
|
|
|
|
let ws3_path = test_env.env_root().join("ws3");
|
2024-09-06 16:48:57 +00:00
|
|
|
|
let ws4_path = test_env.env_root().join("ws4");
|
|
|
|
|
let ws5_path = test_env.env_root().join("ws5");
|
|
|
|
|
let ws6_path = test_env.env_root().join("ws6");
|
2024-02-17 16:48:29 +00:00
|
|
|
|
|
|
|
|
|
test_env.jj_cmd_ok(&ws1_path, &["sparse", "set", "--clear", "--add=foo"]);
|
|
|
|
|
test_env.jj_cmd_ok(&ws1_path, &["workspace", "add", "../ws2"]);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&ws2_path, &["sparse", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-02-17 17:04:21 +00:00
|
|
|
|
foo
|
2024-02-17 16:48:29 +00:00
|
|
|
|
"###);
|
|
|
|
|
test_env.jj_cmd_ok(&ws2_path, &["sparse", "set", "--add=bar"]);
|
|
|
|
|
test_env.jj_cmd_ok(&ws2_path, &["workspace", "add", "../ws3"]);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&ws3_path, &["sparse", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-02-17 17:04:21 +00:00
|
|
|
|
bar
|
|
|
|
|
foo
|
2024-02-17 16:48:29 +00:00
|
|
|
|
"###);
|
2024-09-06 16:48:57 +00:00
|
|
|
|
// --sparse-patterns behavior
|
|
|
|
|
test_env.jj_cmd_ok(
|
|
|
|
|
&ws3_path,
|
|
|
|
|
&["workspace", "add", "--sparse-patterns=copy", "../ws4"],
|
|
|
|
|
);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&ws4_path, &["sparse", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
bar
|
|
|
|
|
foo
|
|
|
|
|
"###);
|
|
|
|
|
test_env.jj_cmd_ok(
|
|
|
|
|
&ws3_path,
|
|
|
|
|
&["workspace", "add", "--sparse-patterns=full", "../ws5"],
|
|
|
|
|
);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&ws5_path, &["sparse", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
.
|
|
|
|
|
"###);
|
|
|
|
|
test_env.jj_cmd_ok(
|
|
|
|
|
&ws3_path,
|
|
|
|
|
&["workspace", "add", "--sparse-patterns=empty", "../ws6"],
|
|
|
|
|
);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&ws6_path, &["sparse", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @"");
|
2024-02-17 16:48:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-10-29 19:43:17 +00:00
|
|
|
|
/// 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();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2023-10-29 19:43:17 +00:00
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["describe", "-m=left"]);
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new", "@-", "-m=right"]);
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new", "all:@-+", "-m=merge"]);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
default: zsuskuln 35e47bff (empty) merge
|
2023-10-29 19:43:17 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
test_env.jj_cmd_ok(
|
|
|
|
|
&main_path,
|
|
|
|
|
&["workspace", "add", "--name", "second", "../secondary"],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// The new workspace's working-copy commit shares all parents with the old one.
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 7013a493bd09 second@
|
2023-10-29 19:43:17 +00:00
|
|
|
|
├─╮
|
2024-06-23 22:20:33 +00:00
|
|
|
|
│ │ @ 35e47bff781e default@
|
2023-10-29 19:43:17 +00:00
|
|
|
|
╭─┬─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
│ ○ 444b77e99d43
|
|
|
|
|
○ │ 1694f2ddf8ec
|
2023-10-29 19:43:17 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
◆ 000000000000
|
2023-10-29 19:43:17 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-22 14:06:49 +00:00
|
|
|
|
/// Test that --ignore-working-copy is respected
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_add_ignore_working_copy() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
|
|
|
|
|
// TODO: maybe better to error out early?
|
|
|
|
|
let stderr = test_env.jj_cmd_failure(
|
|
|
|
|
&main_path,
|
|
|
|
|
&["workspace", "add", "--ignore-working-copy", "../secondary"],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stderr.replace('\\', "/"), @r###"
|
|
|
|
|
Created workspace in "../secondary"
|
|
|
|
|
Error: This command must be able to update the working copy.
|
|
|
|
|
Hint: Don't use --ignore-working-copy.
|
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Test that --at-op is respected
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_add_at_operation() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file1"), "").unwrap();
|
|
|
|
|
let (_stdout, stderr) = test_env.jj_cmd_ok(&main_path, &["commit", "-m1"]);
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
|
|
|
|
Working copy now at: rlvkpnrz 18d8b994 (empty) (no description set)
|
|
|
|
|
Parent commit : qpvuntsm 3364a7ed 1
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file2"), "").unwrap();
|
|
|
|
|
let (_stdout, stderr) = test_env.jj_cmd_ok(&main_path, &["commit", "-m2"]);
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
|
|
|
|
Working copy now at: kkmpptxz 2e7dc5ab (empty) (no description set)
|
|
|
|
|
Parent commit : rlvkpnrz 0dbaa19a 2
|
|
|
|
|
"###);
|
|
|
|
|
|
2024-07-22 14:06:49 +00:00
|
|
|
|
// --at-op should disable snapshot in the main workspace, but the newly
|
|
|
|
|
// created workspace should still be writable.
|
2024-07-22 14:06:49 +00:00
|
|
|
|
std::fs::write(main_path.join("file3"), "").unwrap();
|
2024-07-22 14:06:49 +00:00
|
|
|
|
let (_stdout, stderr) = test_env.jj_cmd_ok(
|
2024-07-22 14:06:49 +00:00
|
|
|
|
&main_path,
|
|
|
|
|
&["workspace", "add", "--at-op=@-", "../secondary"],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stderr.replace('\\', "/"), @r###"
|
|
|
|
|
Created workspace in "../secondary"
|
2024-07-22 14:06:49 +00:00
|
|
|
|
Working copy now at: rzvqmyuk a4d1cbc9 (empty) (no description set)
|
|
|
|
|
Parent commit : qpvuntsm 3364a7ed 1
|
|
|
|
|
Added 1 files, modified 0 files, removed 0 files
|
2024-07-22 14:06:49 +00:00
|
|
|
|
"###);
|
|
|
|
|
let secondary_path = test_env.env_root().join("secondary");
|
|
|
|
|
|
|
|
|
|
// New snapshot can be taken in the secondary workspace.
|
|
|
|
|
std::fs::write(secondary_path.join("file4"), "").unwrap();
|
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&secondary_path, &["status"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Working copy changes:
|
|
|
|
|
A file4
|
2024-07-22 14:06:49 +00:00
|
|
|
|
Working copy : rzvqmyuk 2ba74f85 (no description set)
|
|
|
|
|
Parent commit: qpvuntsm 3364a7ed 1
|
2024-07-22 14:06:49 +00:00
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
|
|
|
|
Concurrent modification detected, resolving automatically.
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&secondary_path, &["op", "log", "-Tdescription"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
@ snapshot working copy
|
2024-08-30 04:59:09 +00:00
|
|
|
|
○ reconcile divergent operations
|
2024-07-22 14:06:49 +00:00
|
|
|
|
├─╮
|
|
|
|
|
○ │ commit cd06097124e3e5860867e35c2bb105902c28ea38
|
2024-07-22 14:06:49 +00:00
|
|
|
|
│ ○ create initial working-copy commit in workspace secondary
|
2024-07-22 14:06:49 +00:00
|
|
|
|
│ ○ add workspace 'secondary'
|
|
|
|
|
├─╯
|
|
|
|
|
○ snapshot working copy
|
|
|
|
|
○ commit 1c867a0762e30de4591890ea208849f793742c1b
|
|
|
|
|
○ snapshot working copy
|
|
|
|
|
○ add workspace 'default'
|
|
|
|
|
○ initialize repo
|
|
|
|
|
○
|
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-11 19:01:57 +00:00
|
|
|
|
/// Test adding a workspace, but at a specific revision using '-r'
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_add_workspace_at_revision() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2023-10-11 19:01:57 +00:00
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
let secondary_path = test_env.env_root().join("secondary");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file-1"), "contents").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["commit", "-m", "first"]);
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file-2"), "contents").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["commit", "-m", "second"]);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
default: kkmpptxz dadeedb4 (empty) (no description set)
|
2023-10-11 19:01:57 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let (_, stderr) = test_env.jj_cmd_ok(
|
|
|
|
|
&main_path,
|
|
|
|
|
&[
|
|
|
|
|
"workspace",
|
|
|
|
|
"add",
|
|
|
|
|
"--name",
|
|
|
|
|
"second",
|
|
|
|
|
"../secondary",
|
|
|
|
|
"-r",
|
|
|
|
|
"@--",
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stderr.replace('\\', "/"), @r###"
|
|
|
|
|
Created workspace in "../secondary"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
Working copy now at: zxsnswpr e374e74a (empty) (no description set)
|
|
|
|
|
Parent commit : qpvuntsm f6097c2f first
|
2023-10-11 19:01:57 +00:00
|
|
|
|
Added 1 files, modified 0 files, removed 0 files
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// 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(&test_env, &main_path), @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ e374e74aa0c8 second@
|
2024-06-23 22:20:33 +00:00
|
|
|
|
│ @ dadeedb493e8 default@
|
2024-07-15 22:20:10 +00:00
|
|
|
|
│ ○ c420244c6398
|
2023-10-11 19:01:57 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ f6097c2f7cac
|
|
|
|
|
◆ 000000000000
|
2023-10-11 19:01:57 +00:00
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
@ e374e74aa0c8 second@
|
2024-07-15 22:20:10 +00:00
|
|
|
|
│ ○ dadeedb493e8 default@
|
|
|
|
|
│ ○ c420244c6398
|
2023-10-11 19:01:57 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ f6097c2f7cac
|
|
|
|
|
◆ 000000000000
|
2023-10-11 19:01:57 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-03 01:36:18 +00:00
|
|
|
|
/// 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();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2023-11-03 01:36:18 +00:00
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file-1"), "contents").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["commit", "-m", "first"]);
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new", "-r", "root()"]);
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file-2"), "contents").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["commit", "-m", "second"]);
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new", "-r", "root()"]);
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file-3"), "contents").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["commit", "-m", "third"]);
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new", "-r", "root()"]);
|
|
|
|
|
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-03-16 05:37:11 +00:00
|
|
|
|
@ 5b36783cd11c
|
2024-07-15 22:20:10 +00:00
|
|
|
|
│ ○ 6c843d62ca29
|
2023-11-03 01:36:18 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
│ ○ 544cd61f2d26
|
2023-11-03 01:36:18 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
│ ○ f6097c2f7cac
|
2023-11-03 01:36:18 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
◆ 000000000000
|
2023-11-03 01:36:18 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let (_, stderr) = test_env.jj_cmd_ok(
|
|
|
|
|
&main_path,
|
|
|
|
|
&[
|
|
|
|
|
"workspace",
|
|
|
|
|
"add",
|
|
|
|
|
"--name=merge",
|
|
|
|
|
"../merged",
|
2024-06-23 22:20:33 +00:00
|
|
|
|
"-r=description(third)",
|
|
|
|
|
"-r=description(second)",
|
|
|
|
|
"-r=description(first)",
|
2023-11-03 01:36:18 +00:00
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stderr.replace('\\', "/"), @r###"
|
|
|
|
|
Created workspace in "../merged"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
Working copy now at: wmwvqwsz f4fa64f4 (empty) (no description set)
|
|
|
|
|
Parent commit : mzvwutvl 6c843d62 third
|
|
|
|
|
Parent commit : kkmpptxz 544cd61f second
|
|
|
|
|
Parent commit : qpvuntsm f6097c2f first
|
2023-11-03 01:36:18 +00:00
|
|
|
|
Added 3 files, modified 0 files, removed 0 files
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ f4fa64f40944 merge@
|
2023-11-03 01:36:18 +00:00
|
|
|
|
├─┬─╮
|
2024-07-15 22:20:10 +00:00
|
|
|
|
│ │ ○ f6097c2f7cac
|
|
|
|
|
│ ○ │ 544cd61f2d26
|
2023-11-03 01:36:18 +00:00
|
|
|
|
│ ├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ │ 6c843d62ca29
|
2023-11-03 01:36:18 +00:00
|
|
|
|
├─╯
|
2024-03-16 05:37:11 +00:00
|
|
|
|
│ @ 5b36783cd11c default@
|
2023-11-03 01:36:18 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
◆ 000000000000
|
2023-11-03 01:36:18 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-17 23:29:50 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_add_workspace_from_subdir() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
let subdir_path = main_path.join("subdir");
|
|
|
|
|
let secondary_path = test_env.env_root().join("secondary");
|
|
|
|
|
|
|
|
|
|
std::fs::create_dir(&subdir_path).unwrap();
|
|
|
|
|
std::fs::write(subdir_path.join("file"), "contents").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["commit", "-m", "initial"]);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
default: rlvkpnrz e1038e77 (empty) (no description set)
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Create workspace while in sub-directory of current workspace
|
|
|
|
|
let (stdout, stderr) =
|
|
|
|
|
test_env.jj_cmd_ok(&subdir_path, &["workspace", "add", "../../secondary"]);
|
|
|
|
|
insta::assert_snapshot!(stdout.replace('\\', "/"), @"");
|
|
|
|
|
insta::assert_snapshot!(stderr.replace('\\', "/"), @r###"
|
|
|
|
|
Created workspace in "../../secondary"
|
|
|
|
|
Working copy now at: rzvqmyuk 7ad84461 (empty) (no description set)
|
|
|
|
|
Parent commit : qpvuntsm a3a43d9e initial
|
|
|
|
|
Added 1 files, modified 0 files, removed 0 files
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Both workspaces show up when we list them
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&secondary_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
default: rlvkpnrz e1038e77 (empty) (no description set)
|
|
|
|
|
secondary: rzvqmyuk 7ad84461 (empty) (no description set)
|
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-20 21:36:30 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_add_workspace_in_current_workspace() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file"), "contents").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["commit", "-m", "initial"]);
|
|
|
|
|
|
|
|
|
|
// Try to create workspace using name instead of path
|
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&main_path, &["workspace", "add", "secondary"]);
|
|
|
|
|
insta::assert_snapshot!(stdout.replace('\\', "/"), @"");
|
|
|
|
|
insta::assert_snapshot!(stderr.replace('\\', "/"), @r###"
|
|
|
|
|
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 0a77a39d (empty) (no description set)
|
|
|
|
|
Parent commit : qpvuntsm 751b12b7 initial
|
|
|
|
|
Added 1 files, modified 0 files, removed 0 files
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Workspace created despite warning
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
default: rlvkpnrz 46d9ba8b (no description set)
|
|
|
|
|
secondary: pmmvwywv 0a77a39d (empty) (no description set)
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Use explicit path instead (no warning)
|
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&main_path, &["workspace", "add", "./third"]);
|
|
|
|
|
insta::assert_snapshot!(stdout.replace('\\', "/"), @"");
|
|
|
|
|
insta::assert_snapshot!(stderr.replace('\\', "/"), @r###"
|
|
|
|
|
Created workspace in "third"
|
|
|
|
|
Working copy now at: zxsnswpr 64746d4b (empty) (no description set)
|
|
|
|
|
Parent commit : qpvuntsm 751b12b7 initial
|
|
|
|
|
Added 1 files, modified 0 files, removed 0 files
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Both workspaces created
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
default: rlvkpnrz 477c647f (no description set)
|
|
|
|
|
secondary: pmmvwywv 0a77a39d (empty) (no description set)
|
|
|
|
|
third: zxsnswpr 64746d4b (empty) (no description set)
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Can see files from the other workspaces in main workspace, since they are
|
|
|
|
|
// child directories and will therefore be snapshotted
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["file", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout.replace('\\', "/"), @r###"
|
|
|
|
|
file
|
|
|
|
|
secondary/file
|
|
|
|
|
third/file
|
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-22 04:49:57 +00:00
|
|
|
|
/// 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();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
let secondary_path = test_env.env_root().join("secondary");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file"), "contents\n").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new"]);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "add", "../secondary"]);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 3224de8ae048 secondary@
|
2024-06-23 22:20:33 +00:00
|
|
|
|
│ @ 06b57f44a3ca default@
|
2023-02-09 02:53:47 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 506f4ec3c2c6
|
|
|
|
|
◆ 000000000000
|
2022-04-22 04:49:57 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Make changes in both working copies
|
|
|
|
|
std::fs::write(main_path.join("file"), "changed in main\n").unwrap();
|
|
|
|
|
std::fs::write(secondary_path.join("file"), "changed in second\n").unwrap();
|
2022-10-02 17:09:46 +00:00
|
|
|
|
// Squash the changes from the main workspace into the initial commit (before
|
2022-04-22 04:49:57 +00:00
|
|
|
|
// running any command in the secondary workspace
|
2023-10-10 11:59:18 +00:00
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&main_path, &["squash"]);
|
2023-10-10 11:07:06 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @"");
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2022-04-22 04:49:57 +00:00
|
|
|
|
Rebased 1 descendant commits
|
2024-06-23 22:20:33 +00:00
|
|
|
|
Working copy now at: mzvwutvl a58c9a9b (empty) (no description set)
|
|
|
|
|
Parent commit : qpvuntsm d4124476 (no description set)
|
2022-04-22 04:49:57 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
2022-10-02 17:09:46 +00:00
|
|
|
|
// The secondary workspace's working-copy commit was updated
|
2022-04-22 04:49:57 +00:00
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
@ a58c9a9b19ce default@
|
2024-07-15 22:20:10 +00:00
|
|
|
|
│ ○ e82cd4ee8faa secondary@
|
2023-02-09 02:53:47 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ d41244767d45
|
|
|
|
|
◆ 000000000000
|
2022-04-22 04:49:57 +00:00
|
|
|
|
"###);
|
2022-10-02 17:09:46 +00:00
|
|
|
|
let stderr = test_env.jj_cmd_failure(&secondary_path, &["st"]);
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2024-07-23 02:01:20 +00:00
|
|
|
|
Error: The working copy is stale (not updated since operation 0da24da631e3).
|
2022-10-02 17:09:46 +00:00
|
|
|
|
Hint: Run `jj workspace update-stale` to update it.
|
2024-09-05 05:38:56 +00:00
|
|
|
|
See https://martinvonz.github.io/jj/latest/working-copy/#stale-working-copy for more information.
|
2022-10-02 17:09:46 +00:00
|
|
|
|
"###);
|
|
|
|
|
// Same error on second run, and from another command
|
|
|
|
|
let stderr = test_env.jj_cmd_failure(&secondary_path, &["log"]);
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2024-07-23 02:01:20 +00:00
|
|
|
|
Error: The working copy is stale (not updated since operation 0da24da631e3).
|
2022-10-02 17:09:46 +00:00
|
|
|
|
Hint: Run `jj workspace update-stale` to update it.
|
2024-09-05 05:38:56 +00:00
|
|
|
|
See https://martinvonz.github.io/jj/latest/working-copy/#stale-working-copy for more information.
|
2022-10-02 17:09:46 +00:00
|
|
|
|
"###);
|
2023-10-10 11:59:18 +00:00
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&secondary_path, &["workspace", "update-stale"]);
|
2023-02-26 11:52:06 +00:00
|
|
|
|
// It was detected that the working copy is now stale.
|
|
|
|
|
// Since there was an uncommitted change in the working copy, it should
|
2022-04-22 04:49:57 +00:00
|
|
|
|
// have been committed first (causing divergence)
|
2023-10-10 11:07:06 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @"");
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2023-02-26 11:52:06 +00:00
|
|
|
|
Concurrent modification detected, resolving automatically.
|
|
|
|
|
Rebased 1 descendant commits onto commits rewritten by other operation
|
2024-06-23 22:20:33 +00:00
|
|
|
|
Working copy now at: pmmvwywv?? e82cd4ee (empty) (no description set)
|
2022-10-02 17:09:46 +00:00
|
|
|
|
Added 0 files, modified 1 files, removed 0 files
|
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &secondary_path),
|
|
|
|
|
@r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
× a28c85ce128b (divergent)
|
|
|
|
|
│ ○ a58c9a9b19ce default@
|
2023-02-26 11:52:06 +00:00
|
|
|
|
├─╯
|
2024-06-23 22:20:33 +00:00
|
|
|
|
│ @ e82cd4ee8faa secondary@ (divergent)
|
2023-02-09 02:53:47 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ d41244767d45
|
|
|
|
|
◆ 000000000000
|
2022-04-22 04:49:57 +00:00
|
|
|
|
"###);
|
2022-08-18 07:49:32 +00:00
|
|
|
|
// The stale working copy should have been resolved by the previous command
|
|
|
|
|
let stdout = get_log_output(&test_env, &secondary_path);
|
|
|
|
|
assert!(!stdout.starts_with("The working copy is stale"));
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
× a28c85ce128b (divergent)
|
|
|
|
|
│ ○ a58c9a9b19ce default@
|
2023-02-26 11:52:06 +00:00
|
|
|
|
├─╯
|
2024-06-23 22:20:33 +00:00
|
|
|
|
│ @ e82cd4ee8faa secondary@ (divergent)
|
2023-02-09 02:53:47 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ d41244767d45
|
|
|
|
|
◆ 000000000000
|
2022-08-18 07:49:32 +00:00
|
|
|
|
"###);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 02:07:46 +00:00
|
|
|
|
/// Test a clean working copy that gets rewritten from another workspace
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_updated_by_other() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2023-02-27 02:07:46 +00:00
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
let secondary_path = test_env.env_root().join("secondary");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file"), "contents\n").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new"]);
|
2023-02-27 02:07:46 +00:00
|
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "add", "../secondary"]);
|
2023-02-27 02:07:46 +00:00
|
|
|
|
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 3224de8ae048 secondary@
|
2024-06-23 22:20:33 +00:00
|
|
|
|
│ @ 06b57f44a3ca default@
|
2023-02-27 02:07:46 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 506f4ec3c2c6
|
|
|
|
|
◆ 000000000000
|
2023-02-27 02:07:46 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Rewrite the check-out commit in one workspace.
|
|
|
|
|
std::fs::write(main_path.join("file"), "changed in main\n").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&main_path, &["squash"]);
|
2023-10-10 11:07:06 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @"");
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2023-02-27 02:07:46 +00:00
|
|
|
|
Rebased 1 descendant commits
|
2024-06-23 22:20:33 +00:00
|
|
|
|
Working copy now at: mzvwutvl a58c9a9b (empty) (no description set)
|
|
|
|
|
Parent commit : qpvuntsm d4124476 (no description set)
|
2023-02-27 02:07:46 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// The secondary workspace's working-copy commit was updated.
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
@ a58c9a9b19ce default@
|
2024-07-15 22:20:10 +00:00
|
|
|
|
│ ○ e82cd4ee8faa secondary@
|
2023-02-27 02:07:46 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ d41244767d45
|
|
|
|
|
◆ 000000000000
|
2023-02-27 02:07:46 +00:00
|
|
|
|
"###);
|
|
|
|
|
let stderr = test_env.jj_cmd_failure(&secondary_path, &["st"]);
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2024-07-23 02:01:20 +00:00
|
|
|
|
Error: The working copy is stale (not updated since operation 0da24da631e3).
|
2023-02-27 02:07:46 +00:00
|
|
|
|
Hint: Run `jj workspace update-stale` to update it.
|
2024-09-05 05:38:56 +00:00
|
|
|
|
See https://martinvonz.github.io/jj/latest/working-copy/#stale-working-copy for more information.
|
2023-02-27 02:07:46 +00:00
|
|
|
|
"###);
|
2023-10-10 11:59:18 +00:00
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&secondary_path, &["workspace", "update-stale"]);
|
2023-02-27 02:07:46 +00:00
|
|
|
|
// It was detected that the working copy is now stale, but clean. So no
|
|
|
|
|
// divergent commit should be created.
|
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: pmmvwywv e82cd4ee (empty) (no description set)
|
2023-02-27 02:07:46 +00:00
|
|
|
|
Added 0 files, modified 1 files, removed 0 files
|
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &secondary_path),
|
|
|
|
|
@r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ a58c9a9b19ce default@
|
2024-06-23 22:20:33 +00:00
|
|
|
|
│ @ e82cd4ee8faa secondary@
|
2023-02-27 02:07:46 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ d41244767d45
|
|
|
|
|
◆ 000000000000
|
2023-02-27 02:07:46 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_current_op_discarded_by_other() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
// Use the local backend because GitBackend::gc() depends on the git CLI.
|
|
|
|
|
test_env.jj_cmd_ok(
|
|
|
|
|
test_env.env_root(),
|
|
|
|
|
&["init", "main", "--config-toml=ui.allow-init-native=true"],
|
|
|
|
|
);
|
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
let secondary_path = test_env.env_root().join("secondary");
|
|
|
|
|
|
2024-03-16 13:16:37 +00:00
|
|
|
|
std::fs::write(main_path.join("modified"), "base\n").unwrap();
|
|
|
|
|
std::fs::write(main_path.join("deleted"), "base\n").unwrap();
|
2024-03-16 03:51:59 +00:00
|
|
|
|
std::fs::write(main_path.join("sparse"), "base\n").unwrap();
|
2024-03-16 13:16:37 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new"]);
|
|
|
|
|
std::fs::write(main_path.join("modified"), "main\n").unwrap();
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new"]);
|
|
|
|
|
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "add", "../secondary"]);
|
2024-03-16 13:16:37 +00:00
|
|
|
|
// Make unsnapshotted writes in the secondary working copy
|
2024-03-16 03:51:59 +00:00
|
|
|
|
test_env.jj_cmd_ok(
|
|
|
|
|
&secondary_path,
|
|
|
|
|
&[
|
|
|
|
|
"sparse",
|
|
|
|
|
"set",
|
|
|
|
|
"--clear",
|
|
|
|
|
"--add=modified",
|
|
|
|
|
"--add=deleted",
|
|
|
|
|
"--add=added",
|
|
|
|
|
],
|
|
|
|
|
);
|
2024-03-16 13:16:37 +00:00
|
|
|
|
std::fs::write(secondary_path.join("modified"), "secondary\n").unwrap();
|
|
|
|
|
std::fs::remove_file(secondary_path.join("deleted")).unwrap();
|
|
|
|
|
std::fs::write(secondary_path.join("added"), "secondary\n").unwrap();
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
|
|
|
|
|
// Create an op by abandoning the parent commit. Importantly, that commit also
|
|
|
|
|
// changes the target tree in the secondary workspace.
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["abandon", "@-"]);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(
|
|
|
|
|
&main_path,
|
|
|
|
|
&[
|
|
|
|
|
"operation",
|
|
|
|
|
"log",
|
|
|
|
|
"--template",
|
|
|
|
|
r#"id.short(10) ++ " " ++ description"#,
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-07-23 08:04:11 +00:00
|
|
|
|
@ 7337338f0b abandon commit 20dd439c4bd12c6ad56c187ac490bd0141804618f638dc5c4dc92ff9aecba20f152b23160db9dcf61beb31a5cb14091d9def5a36d11c9599cc4d2e5689236af1
|
|
|
|
|
○ f4bd4d046b create initial working-copy commit in workspace secondary
|
|
|
|
|
○ 0f99641958 add workspace 'secondary'
|
|
|
|
|
○ 5641361f60 new empty commit
|
|
|
|
|
○ 3a6c319c59 snapshot working copy
|
|
|
|
|
○ 42c6005842 new empty commit
|
|
|
|
|
○ 6a45045541 snapshot working copy
|
|
|
|
|
○ a9e6630bf0 add workspace 'default'
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ cecfee9647 initialize repo
|
|
|
|
|
○ 0000000000
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Abandon ops, including the one the secondary workspace is currently on.
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["operation", "abandon", "..@-"]);
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["util", "gc", "--expire=now"]);
|
|
|
|
|
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-07-23 08:04:11 +00:00
|
|
|
|
○ 96b31dafdc41 secondary@
|
|
|
|
|
│ @ 6c051bd1ccd5 default@
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
├─╯
|
2024-07-23 08:04:11 +00:00
|
|
|
|
○ 7c5b25a4fc8f
|
2024-07-15 22:20:10 +00:00
|
|
|
|
◆ 000000000000
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stderr = test_env.jj_cmd_failure(&secondary_path, &["st"]);
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
|
|
|
|
Error: Could not read working copy's operation.
|
|
|
|
|
Hint: Run `jj workspace update-stale` to recover.
|
2024-09-05 05:38:56 +00:00
|
|
|
|
See https://martinvonz.github.io/jj/latest/working-copy/#stale-working-copy for more information.
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&secondary_path, &["workspace", "update-stale"]);
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2024-07-23 08:04:11 +00:00
|
|
|
|
Failed to read working copy's current operation; attempting recovery. Error message from read attempt: Object f4bd4d046b3cdf61b0fda7738a0b1414c0aedc6c8229d39a35ee26facc358cad8b588b04d7eba1302a82409c529f69dbb1ff9ea28789d935b74f123f377aa30b of type operation not found
|
|
|
|
|
Created and checked out recovery commit 62f70695e3b0
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(stdout, @"");
|
|
|
|
|
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-07-23 08:04:11 +00:00
|
|
|
|
○ b0b400439a82 secondary@
|
|
|
|
|
○ 96b31dafdc41
|
|
|
|
|
│ @ 6c051bd1ccd5 default@
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
├─╯
|
2024-07-23 08:04:11 +00:00
|
|
|
|
○ 7c5b25a4fc8f
|
2024-07-15 22:20:10 +00:00
|
|
|
|
◆ 000000000000
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
2024-03-16 03:51:59 +00:00
|
|
|
|
// The sparse patterns should remain
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&secondary_path, &["sparse", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
added
|
|
|
|
|
deleted
|
|
|
|
|
modified
|
|
|
|
|
"###);
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&secondary_path, &["st"]);
|
|
|
|
|
insta::assert_snapshot!(stderr, @"");
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Working copy changes:
|
2024-03-16 13:16:37 +00:00
|
|
|
|
A added
|
|
|
|
|
D deleted
|
|
|
|
|
M modified
|
2024-07-23 08:04:11 +00:00
|
|
|
|
Working copy : kmkuslsw b0b40043 (no description set)
|
|
|
|
|
Parent commit: rzvqmyuk 96b31daf (empty) (no description set)
|
2024-03-16 13:16:37 +00:00
|
|
|
|
"###);
|
|
|
|
|
// The modified file should have the same contents it had before (not reset to
|
|
|
|
|
// the base contents)
|
|
|
|
|
insta::assert_snapshot!(std::fs::read_to_string(secondary_path.join("modified")).unwrap(), @r###"
|
|
|
|
|
secondary
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
2024-07-24 13:49:18 +00:00
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&secondary_path, &["evolog"]);
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
insta::assert_snapshot!(stderr, @"");
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-07-23 08:04:11 +00:00
|
|
|
|
@ kmkuslsw test.user@example.com 2001-02-03 08:05:18 secondary@ b0b40043
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
│ (no description set)
|
2024-07-23 08:04:11 +00:00
|
|
|
|
○ kmkuslsw hidden test.user@example.com 2001-02-03 08:05:18 62f70695
|
workspace: recover from missing operation
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
2024-02-03 05:26:23 +00:00
|
|
|
|
(empty) (no description set)
|
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 02:07:46 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_update_stale_noop() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2023-02-27 02:07:46 +00:00
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&main_path, &["workspace", "update-stale"]);
|
2023-10-10 11:07:06 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @"");
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2023-02-27 02:07:46 +00:00
|
|
|
|
Nothing to do (the working copy is not stale).
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stderr = test_env.jj_cmd_failure(
|
|
|
|
|
&main_path,
|
|
|
|
|
&["workspace", "update-stale", "--ignore-working-copy"],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
|
|
|
|
Error: This command must be able to update the working copy.
|
|
|
|
|
Hint: Don't use --ignore-working-copy.
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["op", "log", "-Tdescription"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
@ add workspace 'default'
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ initialize repo
|
|
|
|
|
○
|
2023-02-27 02:07:46 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-26 11:52:06 +00:00
|
|
|
|
/// Test "update-stale" in a dirty, but not stale working copy.
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_update_stale_snapshot() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2023-02-26 11:52:06 +00:00
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
let secondary_path = test_env.env_root().join("secondary");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file"), "changed in main\n").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new"]);
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "add", "../secondary"]);
|
2023-02-26 11:52:06 +00:00
|
|
|
|
|
|
|
|
|
// Record new operation in one workspace.
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new"]);
|
2023-02-26 11:52:06 +00:00
|
|
|
|
|
|
|
|
|
// Snapshot the other working copy, which unfortunately results in concurrent
|
|
|
|
|
// operations, but should be resolved cleanly.
|
|
|
|
|
std::fs::write(secondary_path.join("file"), "changed in second\n").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&secondary_path, &["workspace", "update-stale"]);
|
2023-10-10 11:07:06 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @"");
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2023-02-26 11:52:06 +00:00
|
|
|
|
Concurrent modification detected, resolving automatically.
|
|
|
|
|
Nothing to do (the working copy is not stale).
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
@ e672fd8fefac secondary@
|
2024-07-15 22:20:10 +00:00
|
|
|
|
│ ○ ea37b073f5ab default@
|
|
|
|
|
│ ○ b13c81dedc64
|
2023-02-26 11:52:06 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ e6e9989f1179
|
|
|
|
|
◆ 000000000000
|
2023-02-26 11:52:06 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-22 04:49:57 +00:00
|
|
|
|
/// Test forgetting workspaces
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_forget() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file"), "contents").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new"]);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "add", "../secondary"]);
|
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&main_path, &["workspace", "forget"]);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @"");
|
2023-10-10 11:59:18 +00:00
|
|
|
|
insta::assert_snapshot!(stderr, @"");
|
2022-04-22 04:49:57 +00:00
|
|
|
|
|
|
|
|
|
// When listing workspaces, only the secondary workspace shows up
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
2022-04-28 23:32:18 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
secondary: pmmvwywv 18463f43 (empty) (no description set)
|
2022-04-28 23:32:18 +00:00
|
|
|
|
"###);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
|
|
|
|
|
// `jj status` tells us that there's no working copy here
|
2023-10-10 11:59:18 +00:00
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&main_path, &["st"]);
|
2022-04-28 23:32:18 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
No working copy
|
|
|
|
|
"###);
|
2023-10-10 11:59:18 +00:00
|
|
|
|
insta::assert_snapshot!(stderr, @"");
|
2022-04-22 04:49:57 +00:00
|
|
|
|
|
2022-09-18 21:46:12 +00:00
|
|
|
|
// The old working copy doesn't get an "@" in the log output
|
2022-04-22 04:49:57 +00:00
|
|
|
|
// 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(&test_env, &main_path), @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 18463f438cc9
|
|
|
|
|
○ 4e8f9d2be039
|
|
|
|
|
◆ 000000000000
|
2022-04-22 04:49:57 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Revision "@" cannot be used
|
|
|
|
|
let stderr = test_env.jj_cmd_failure(&main_path, &["log", "-r", "@"]);
|
2022-04-28 23:32:18 +00:00
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2024-06-19 23:14:00 +00:00
|
|
|
|
Error: Workspace "default" doesn't have a working-copy commit
|
2022-04-28 23:32:18 +00:00
|
|
|
|
"###);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
|
|
|
|
|
// Try to add back the workspace
|
|
|
|
|
// TODO: We should make this just add it back instead of failing
|
|
|
|
|
let stderr = test_env.jj_cmd_failure(&main_path, &["workspace", "add", "."]);
|
2022-04-28 23:32:18 +00:00
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
|
|
|
|
Error: Workspace already exists
|
|
|
|
|
"###);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
|
2023-10-13 14:37:15 +00:00
|
|
|
|
// Add a third workspace...
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "add", "../third"]);
|
|
|
|
|
// ... and then forget it, and the secondary workspace too
|
|
|
|
|
let (stdout, stderr) =
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "forget", "secondary", "third"]);
|
2022-04-22 04:49:57 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @"");
|
2023-10-10 11:59:18 +00:00
|
|
|
|
insta::assert_snapshot!(stderr, @"");
|
2022-04-22 04:49:57 +00:00
|
|
|
|
// No workspaces left
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @"");
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-13 14:37:15 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_forget_multi_transaction() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2023-10-13 14:37:15 +00:00
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file"), "contents").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["new"]);
|
|
|
|
|
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "add", "../second"]);
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "add", "../third"]);
|
|
|
|
|
|
|
|
|
|
// there should be three workspaces
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
default: rlvkpnrz 909d51b1 (empty) (no description set)
|
|
|
|
|
second: pmmvwywv 18463f43 (empty) (no description set)
|
|
|
|
|
third: rzvqmyuk cc383fa2 (empty) (no description set)
|
2023-10-13 14:37:15 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// delete two at once, in a single tx
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "forget", "second", "third"]);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
default: rlvkpnrz 909d51b1 (empty) (no description set)
|
2023-10-13 14:37:15 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// the op log should have multiple workspaces forgotten in a single tx
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["op", "log", "--limit", "1"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-07-23 02:01:20 +00:00
|
|
|
|
@ b7ab9f1c16cc test-username@host.example.com 2001-02-03 04:05:12.000 +07:00 - 2001-02-03 04:05:12.000 +07:00
|
2023-10-13 14:37:15 +00:00
|
|
|
|
│ forget workspaces second, third
|
|
|
|
|
│ args: jj workspace forget second third
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// now, undo, and that should restore both workspaces
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["op", "undo"]);
|
|
|
|
|
|
|
|
|
|
// finally, there should be three workspaces at the end
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
default: rlvkpnrz 909d51b1 (empty) (no description set)
|
|
|
|
|
second: pmmvwywv 18463f43 (empty) (no description set)
|
|
|
|
|
third: rzvqmyuk cc383fa2 (empty) (no description set)
|
2023-10-13 14:37:15 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 23:26:47 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_forget_abandon_commits() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file"), "contents").unwrap();
|
|
|
|
|
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "add", "../second"]);
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "add", "../third"]);
|
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["workspace", "add", "../fourth"]);
|
|
|
|
|
let third_path = test_env.env_root().join("third");
|
|
|
|
|
test_env.jj_cmd_ok(&third_path, &["edit", "second@"]);
|
|
|
|
|
let fourth_path = test_env.env_root().join("fourth");
|
|
|
|
|
test_env.jj_cmd_ok(&fourth_path, &["edit", "second@"]);
|
|
|
|
|
|
|
|
|
|
// there should be four workspaces, three of which are at the same empty commit
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
default: qpvuntsm 4e8f9d2b (no description set)
|
|
|
|
|
fourth: uuqppmxq 57d63245 (empty) (no description set)
|
|
|
|
|
second: uuqppmxq 57d63245 (empty) (no description set)
|
|
|
|
|
third: uuqppmxq 57d63245 (empty) (no description set)
|
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 57d63245a308 fourth@ second@ third@
|
2024-06-27 23:26:47 +00:00
|
|
|
|
│ @ 4e8f9d2be039 default@
|
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
◆ 000000000000
|
2024-06-27 23:26:47 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// delete the default workspace (should not abandon commit since not empty)
|
|
|
|
|
test_env.jj_cmd_success(&main_path, &["workspace", "forget", "default"]);
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 57d63245a308 fourth@ second@ third@
|
|
|
|
|
│ ○ 4e8f9d2be039
|
2024-06-27 23:26:47 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
◆ 000000000000
|
2024-06-27 23:26:47 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// delete the second workspace (should not abandon commit since other workspaces
|
|
|
|
|
// still have commit checked out)
|
|
|
|
|
test_env.jj_cmd_success(&main_path, &["workspace", "forget", "second"]);
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 57d63245a308 fourth@ third@
|
|
|
|
|
│ ○ 4e8f9d2be039
|
2024-06-27 23:26:47 +00:00
|
|
|
|
├─╯
|
2024-07-15 22:20:10 +00:00
|
|
|
|
◆ 000000000000
|
2024-06-27 23:26:47 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// delete the last 2 workspaces (commit should be abandoned now even though
|
|
|
|
|
// forgotten in same tx)
|
|
|
|
|
test_env.jj_cmd_success(&main_path, &["workspace", "forget", "third", "fourth"]);
|
|
|
|
|
insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###"
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 4e8f9d2be039
|
|
|
|
|
◆ 000000000000
|
2024-06-27 23:26:47 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 02:01:37 +00:00
|
|
|
|
/// Test context of commit summary template
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_list_workspaces_template() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2023-01-16 02:01:37 +00:00
|
|
|
|
test_env.add_config(
|
2023-01-26 19:26:18 +00:00
|
|
|
|
r#"
|
2023-02-28 11:30:57 +00:00
|
|
|
|
templates.commit_summary = """commit_id.short() ++ " " ++ description.first_line() ++
|
2023-02-14 14:55:30 +00:00
|
|
|
|
if(current_working_copy, " (current)")"""
|
2023-01-26 19:26:18 +00:00
|
|
|
|
"#,
|
2023-01-16 02:01:37 +00:00
|
|
|
|
);
|
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
let secondary_path = test_env.env_root().join("secondary");
|
|
|
|
|
|
|
|
|
|
std::fs::write(main_path.join("file"), "contents").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&main_path, &["commit", "-m", "initial"]);
|
|
|
|
|
test_env.jj_cmd_ok(
|
2023-01-16 02:01:37 +00:00
|
|
|
|
&main_path,
|
|
|
|
|
&["workspace", "add", "--name", "second", "../secondary"],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// "current_working_copy" should point to the workspace we operate on
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
default: 8183d0fcaa4c (current)
|
|
|
|
|
second: 0a77a39d7d6f
|
2023-01-16 02:01:37 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&secondary_path, &["workspace", "list"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
default: 8183d0fcaa4c
|
|
|
|
|
second: 0a77a39d7d6f (current)
|
2023-01-16 02:01:37 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-24 11:46:59 +00:00
|
|
|
|
/// Test getting the workspace root from primary and secondary workspaces
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_workspaces_root() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "main"]);
|
2023-01-24 11:46:59 +00:00
|
|
|
|
let main_path = test_env.env_root().join("main");
|
|
|
|
|
let secondary_path = test_env.env_root().join("secondary");
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "root"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
$TEST_ENV/main
|
|
|
|
|
"###);
|
|
|
|
|
let main_subdir_path = main_path.join("subdir");
|
|
|
|
|
std::fs::create_dir(&main_subdir_path).unwrap();
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&main_subdir_path, &["workspace", "root"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
$TEST_ENV/main
|
|
|
|
|
"###);
|
|
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(
|
2023-01-24 11:46:59 +00:00
|
|
|
|
&main_path,
|
|
|
|
|
&["workspace", "add", "--name", "secondary", "../secondary"],
|
|
|
|
|
);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&secondary_path, &["workspace", "root"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
$TEST_ENV/secondary
|
|
|
|
|
"###);
|
|
|
|
|
let secondary_subdir_path = secondary_path.join("subdir");
|
|
|
|
|
std::fs::create_dir(&secondary_subdir_path).unwrap();
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&secondary_subdir_path, &["workspace", "root"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
$TEST_ENV/secondary
|
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-19 03:17:03 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_debug_snapshot() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file"), "contents").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["debug", "snapshot"]);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["op", "log"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
@ e1e762d39b39 test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00
|
2024-06-19 03:17:03 +00:00
|
|
|
|
│ snapshot working copy
|
|
|
|
|
│ args: jj debug snapshot
|
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-06-19 03:17:03 +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-06-19 03:17:03 +00:00
|
|
|
|
│ initialize repo
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 000000000000 root()
|
2024-06-19 03:17:03 +00:00
|
|
|
|
"###);
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "initial"]);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["op", "log"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
@ 9ac6e7144e8a 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 4e8f9d2be039994f589b4e57ac5e9488703e604d
|
2024-06-19 03:17:03 +00:00
|
|
|
|
│ args: jj describe -m initial
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ e1e762d39b39 test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00
|
2024-06-19 03:17:03 +00:00
|
|
|
|
│ snapshot working copy
|
|
|
|
|
│ args: jj debug snapshot
|
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-06-19 03:17:03 +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-06-19 03:17:03 +00:00
|
|
|
|
│ initialize repo
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ 000000000000 root()
|
2024-06-19 03:17:03 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-22 04:49:57 +00:00
|
|
|
|
fn get_log_output(test_env: &TestEnvironment, cwd: &Path) -> String {
|
2023-08-15 03:18:52 +00:00
|
|
|
|
let template = r#"
|
2023-02-28 10:43:14 +00:00
|
|
|
|
separate(" ",
|
2024-03-16 05:37:11 +00:00
|
|
|
|
commit_id.short(),
|
2023-02-28 10:43:14 +00:00
|
|
|
|
working_copies,
|
|
|
|
|
if(divergent, "(divergent)"),
|
2022-10-19 05:21:25 +00:00
|
|
|
|
)
|
2023-08-15 03:18:52 +00:00
|
|
|
|
"#;
|
2023-02-28 10:43:14 +00:00
|
|
|
|
test_env.jj_cmd_success(cwd, &["log", "-T", template, "-r", "all()"])
|
2022-04-22 04:49:57 +00:00
|
|
|
|
}
|