From d4211942a8cf5fd6ae9a929650c180a3e3bc7e1c Mon Sep 17 00:00:00 2001 From: Austin Seipp Date: Thu, 2 Nov 2023 20:36:18 -0500 Subject: [PATCH] cli: support multiple `--revision` arguments to `workspace add` Summary: A natural extension of the existing support, as suggested by Scott Olson. Closes #2496. Signed-off-by: Austin Seipp Change-Id: I91c9c8c377ad67ccde7945ed41af6c79 --- CHANGELOG.md | 4 ++ cli/src/commands/workspace.rs | 22 ++++++++--- cli/tests/test_workspaces.rs | 70 +++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5603e96f08d..ee0fa210bb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### New features +* `jj workspace add` can now take _multiple_ `--revision` arguments, which if + provided will create a new workspace on top of the merge commit of all the + given parents. + ### Fixed bugs diff --git a/cli/src/commands/workspace.rs b/cli/src/commands/workspace.rs index 2b5715cf00e..ce3ae48224b 100644 --- a/cli/src/commands/workspace.rs +++ b/cli/src/commands/workspace.rs @@ -60,10 +60,15 @@ pub struct WorkspaceAddArgs { /// directory. #[arg(long)] name: Option, - /// The revision that the workspace should be created at; a new working copy - /// commit will be created on top of it. + /// A list of parents that that the workspace should be created from; a new + /// working copy commit will be created on top of them. If a single commit + /// is provided, the working copy is put on top. If multiple commits are + /// provided, they will be merged together and a working copy commit will be + /// created on top of the merge commit. If no parents are provided, the new + /// working copy commit will be created on top of the current workspace's + /// working copy commit. #[arg(long, short)] - revision: Option, + revision: Vec, } /// Stop tracking a workspace's working-copy commit in the repo @@ -166,9 +171,9 @@ fn cmd_workspace_add( &name )); - let parents = if let Some(specific_rev) = &args.revision { - vec![old_workspace_command.resolve_single_rev(specific_rev, ui)?] - } else { + // check if args.revision is empty, and if so, create a working copy based + // on the existing one + let parents = if args.revision.is_empty() { // Check out parents of the current workspace's working-copy commit, or the // root if there is no working-copy commit in the current workspace. if let Some(old_wc_commit_id) = tx @@ -180,6 +185,11 @@ fn cmd_workspace_add( } else { vec![tx.repo().store().root_commit()] } + } else { + args.revision + .iter() + .map(|rev| old_workspace_command.resolve_single_rev(rev, ui)) + .collect::, _>>()? }; let tree = merge_commit_trees(tx.repo(), &parents)?; diff --git a/cli/tests/test_workspaces.rs b/cli/tests/test_workspaces.rs index cf12b8e0fa6..8775aced0b9 100644 --- a/cli/tests/test_workspaces.rs +++ b/cli/tests/test_workspaces.rs @@ -164,6 +164,76 @@ fn test_workspaces_add_workspace_at_revision() { "###); } +/// Test using multiple `workspace add -r` commands to create a workspace at +/// a merge commit. +#[test] +fn test_workspaces_add_workspace_multiple_revisions() { + let test_env = TestEnvironment::default(); + test_env.jj_cmd_ok(test_env.env_root(), &["init", "--git", "main"]); + 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###" + @ 5b36783cd11c4607a329c5e8c2fd9097c9ce2add + │ ◉ 23881f07b53ce1ea936ca8842e344dea9c3356e5 + ├─╯ + │ ◉ 1f6a15f0af2a985703864347f5fdf27a82fc3d73 + ├─╯ + │ ◉ e7d7dbb91c5a543ea680711093e689916d5f31df + ├─╯ + ◉ 0000000000000000000000000000000000000000 + "###); + + let (_, stderr) = test_env.jj_cmd_ok( + &main_path, + &[ + "workspace", + "add", + "--name", + "merge", + "../merged", + "-r", + "238", + "-r", + "1f6", + "-r", + "e7d", + ], + ); + insta::assert_snapshot!(stderr.replace('\\', "/"), @r###" + Created workspace in "../merged" + Working copy now at: wmwvqwsz fa8fdc28 (empty) (no description set) + Parent commit : mzvwutvl 23881f07 third + Parent commit : kkmpptxz 1f6a15f0 second + Parent commit : qpvuntsm e7d7dbb9 first + Added 3 files, modified 0 files, removed 0 files + "###); + + insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###" + ◉ fa8fdc28af12d3c96b1e0ed062f5a8f9a99818f0 merge@ + ├─┬─╮ + │ │ ◉ e7d7dbb91c5a543ea680711093e689916d5f31df + │ ◉ │ 1f6a15f0af2a985703864347f5fdf27a82fc3d73 + │ ├─╯ + ◉ │ 23881f07b53ce1ea936ca8842e344dea9c3356e5 + ├─╯ + │ @ 5b36783cd11c4607a329c5e8c2fd9097c9ce2add default@ + ├─╯ + ◉ 0000000000000000000000000000000000000000 + "###); +} + /// Test making changes to the working copy in a workspace as it gets rewritten /// from another workspace #[test]