diff --git a/CHANGELOG.md b/CHANGELOG.md index 779c1c4ac2..372bcc250b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `jj git push --deleted` will remove all locally deleted branches from the remote. -* `jj restore` without `--from` works correctly even if `@` is a merge - commit. +* `jj restore` now works correctly without `--from` works correctly even if `@` + is a merge commit. It gained a `-r` argument and its interface is now in line + with `jj diff`, `jj diffedit`, etc. * `jj rebase` now accepts multiple `-s` and `-b` arguments. Revsets with multiple commits are allowed with `--allow-large-revsets`. diff --git a/src/commands/mod.rs b/src/commands/mod.rs index ca1f9485ef..834917ea0a 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -582,18 +582,28 @@ struct ResolveArgs { /// Restore paths from another revision /// +/// With the `-r` option, which is the default, restores a revision from its +/// parent (or the merge of its parents). +/// +/// If `--to` and/or `--from` are specified, restores one revision from the +/// content of another revision. +/// /// That means that the paths get the same content in the destination (`--to`) /// as they had in the source (`--from`). This is typically used for undoing /// changes to some paths in the working copy (`jj restore `). /// -/// When neither `--from` nor `--to` is specified, the command restores into the -/// working copy from its parent. If one of `--from` or `--to` is specified, the -/// other one defaults to the working copy. +/// If one of `--from` or `--to` is specified, the other one defaults to the +/// working copy. /// /// See `jj diffedit` if you'd like to restore portions of files rather than /// entire files. #[derive(clap::Args, Clone, Debug)] struct RestoreArgs { + /// The revision to restore. Defaults to @ if neither --to nor --from are + /// specified. + #[arg(long, short, conflicts_with_all=["to", "from"])] + revision: Option, + /// Revision to restore from (source) #[arg(long)] from: Option, @@ -623,7 +633,7 @@ struct RestoreArgs { /// changes into or out of the parent revision. #[derive(clap::Args, Clone, Debug)] struct DiffeditArgs { - /// The revision to touch up. Defaults to @ if --to/--from are not + /// The revision to touch up. Defaults to @ if neither --to nor --from are /// specified. #[arg(long, short)] revision: Option, @@ -2509,7 +2519,8 @@ fn cmd_restore( .resolve_single_rev(args.from.as_deref().unwrap_or("@"))? .tree(); } else { - to_commit = workspace_command.resolve_single_rev("@")?; + to_commit = + workspace_command.resolve_single_rev(args.revision.as_deref().unwrap_or("@"))?; from_tree = merge_commit_trees(workspace_command.repo(), &to_commit.parents()); } workspace_command.check_rewritable(&to_commit)?; diff --git a/tests/test_restore_command.rs b/tests/test_restore_command.rs index 95e55c58f0..93786eb82f 100644 --- a/tests/test_restore_command.rs +++ b/tests/test_restore_command.rs @@ -42,12 +42,34 @@ fn test_restore() { let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]); insta::assert_snapshot!(stdout, @""); - // Can restore from other revision + // Can restore another revision + test_env.jj_cmd_success(&repo_path, &["undo"]); + let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s", "-r=@-"]); + insta::assert_snapshot!(stdout, @r###" + A file2 + "###); + let stdout = test_env.jj_cmd_success(&repo_path, &["restore", "-r=@-"]); + insta::assert_snapshot!(stdout, @r###" + Created e989e4b86680 (no description set) + Rebased 1 descendant commits + Working copy now at: b47256590e11 (no description set) + Added 0 files, modified 1 files, removed 0 files + "###); + let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s", "-r=@-"]); + insta::assert_snapshot!(stdout, @""); + + // Cannot restore the root revision + let stderr = test_env.jj_cmd_failure(&repo_path, &["restore", "-r=root"]); + insta::assert_snapshot!(stderr, @r###" + Error: Cannot rewrite the root commit + "###); + + // Can restore this revision from another revision test_env.jj_cmd_success(&repo_path, &["undo"]); let stdout = test_env.jj_cmd_success(&repo_path, &["restore", "--from", "@--"]); insta::assert_snapshot!(stdout, @r###" - Created 9cb58509136b (no description set) - Working copy now at: 9cb58509136b (no description set) + Created 1dd6eb63d587 (no description set) + Working copy now at: 1dd6eb63d587 (no description set) Added 1 files, modified 0 files, removed 2 files "###); let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]); @@ -59,9 +81,9 @@ fn test_restore() { test_env.jj_cmd_success(&repo_path, &["undo"]); let stdout = test_env.jj_cmd_success(&repo_path, &["restore", "--to", "@-"]); insta::assert_snapshot!(stdout, @r###" - Created 5ed06151e039 (no description set) + Created ec9d5b59c3cf (no description set) Rebased 1 descendant commits - Working copy now at: ca6c95b68bd2 (no description set) + Working copy now at: d6f3c6815772 (no description set) "###); let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]); insta::assert_snapshot!(stdout, @""); @@ -76,9 +98,9 @@ fn test_restore() { test_env.jj_cmd_success(&repo_path, &["undo"]); let stdout = test_env.jj_cmd_success(&repo_path, &["restore", "--from", "@", "--to", "@-"]); insta::assert_snapshot!(stdout, @r###" - Created c83e17dc46fd (no description set) + Created 5f6eb3d5c5bf (no description set) Rebased 1 descendant commits - Working copy now at: df9fb6892f99 (no description set) + Working copy now at: 525afd5d4a26 (no description set) "###); let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]); insta::assert_snapshot!(stdout, @""); @@ -93,8 +115,8 @@ fn test_restore() { test_env.jj_cmd_success(&repo_path, &["undo"]); let stdout = test_env.jj_cmd_success(&repo_path, &["restore", "file2", "file3"]); insta::assert_snapshot!(stdout, @r###" - Created 28647642d4a5 (no description set) - Working copy now at: 28647642d4a5 (no description set) + Created 569ce73d04fb (no description set) + Working copy now at: 569ce73d04fb (no description set) Added 0 files, modified 1 files, removed 1 files "###); let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]);