diff --git a/CHANGELOG.md b/CHANGELOG.md index 19408d8ca..5d3fa66c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `jj git clone` now supports the `--colocate` flag to create the git repo in the same directory as the jj repo. +* `jj restore` gained a new option `--changes-in` to restore files + from a merge revision's parents. This undoes the changes that `jj diff -r` + would show. + + ### Fixed bugs ## [0.8.0] - 2023-07-09 diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 6d5cfbc02..6a145963e 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -480,8 +480,8 @@ struct DuplicateArgs { /// Abandon a revision /// /// Abandon a revision, rebasing descendants onto its parent(s). The behavior is -/// similar to `jj restore`; the difference is that `jj abandon` gives you a new -/// change, while `jj restore` updates the existing change. +/// similar to `jj restore --changes-in`; the difference is that `jj abandon` +/// gives you a new change, while `jj restore` updates the existing change. #[derive(clap::Args, Clone, Debug)] struct AbandonArgs { /// The revision(s) to abandon @@ -684,23 +684,43 @@ struct ResolveArgs { /// as they had in the source (`--from`). This is typically used for undoing /// changes to some paths in the working copy (`jj restore `). /// +/// If only one of `--from` or `--to` is specified, the other one defaults to +/// the working copy. +/// /// 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. +/// working copy from its parent(s). `jj restore` without arguments is similar +/// to `jj abandon`, except that it leaves an empty revision with its +/// description and other metadata preserved. /// /// See `jj diffedit` if you'd like to restore portions of files rather than /// entire files. #[derive(clap::Args, Clone, Debug)] struct RestoreArgs { + /// Restore only these paths (instead of all paths) + #[arg(value_hint = clap::ValueHint::AnyPath)] + paths: Vec, /// Revision to restore from (source) #[arg(long)] from: Option, /// Revision to restore into (destination) #[arg(long)] to: Option, - /// Restore only these paths (instead of all paths) - #[arg(value_hint = clap::ValueHint::AnyPath)] - paths: Vec, + /// Undo the changes in a revision as compared to the merge of its parents. + /// + /// This undoes the changes that can be seen with `jj diff -r REVISION`. If + /// `REVISION` only has a single parent, this option is equivalent to `jj + /// restore --to REVISION --from REVISION-`. + /// + /// The default behavior of `jj restore` is equivalent to `jj restore + /// --changes-in @`. + // + // If we followed the pattern of `jj diff` and `jj diffedit`, this option + // could simply be called `--revision`/`-r`. However, that would make it + // likely that someone unfamiliar with this pattern would use `-r` when they + // wanted `--from`. This would make a different revision empty, and the user + // might not even realize something went wrong. + #[arg(long, short, value_name="REVISION", conflicts_with_all=["to", "from"])] + changes_in: Option, } /// Touch up the content changes in a revision with a diff editor @@ -721,7 +741,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, @@ -2853,7 +2873,8 @@ fn cmd_restore( .resolve_single_rev(args.from.as_deref().unwrap_or("@"), ui)? .tree(); } else { - to_commit = workspace_command.resolve_single_rev("@", ui)?; + to_commit = + workspace_command.resolve_single_rev(args.changes_in.as_deref().unwrap_or("@"), ui)?; from_tree = merge_commit_trees(workspace_command.repo().as_ref(), &to_commit.parents())?; } workspace_command.check_rewritable(&to_commit)?; diff --git a/tests/test_global_opts.rs b/tests/test_global_opts.rs index d37f6dd1b..6d6decfea 100644 --- a/tests/test_global_opts.rs +++ b/tests/test_global_opts.rs @@ -417,7 +417,7 @@ fn test_help() { Usage: jj diffedit [OPTIONS] Options: - -r, --revision The revision to touch up. Defaults to @ if --to/--from are not specified + -r, --revision The revision to touch up. Defaults to @ if neither --to nor --from are specified --from Show changes from this revision. Defaults to @ if --to is specified --to Edit changes in this revision. Defaults to @ if --from is specified -h, --help Print help (see more with '--help') diff --git a/tests/test_restore_command.rs b/tests/test_restore_command.rs index 662d8bc28..bf310e664 100644 --- a/tests/test_restore_command.rs +++ b/tests/test_restore_command.rs @@ -43,12 +43,35 @@ 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 from its parents + 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", "-c=@-"]); + insta::assert_snapshot!(stdout, @r###" + Created e989e4b86680 (no description set) + Rebased 1 descendant commits + Working copy now at: b47256590e11 (no description set) + Parent commit : e989e4b86680 (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", "-c=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) Parent commit : 1a986a275de6 (no description set) Added 1 files, modified 0 files, removed 2 files "###); @@ -61,10 +84,10 @@ 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) - Parent commit : 5ed06151e039 (no description set) + Working copy now at: d6f3c6815772 (no description set) + Parent commit : ec9d5b59c3cf (no description set) "###); let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]); insta::assert_snapshot!(stdout, @""); @@ -79,10 +102,10 @@ 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) - Parent commit : c83e17dc46fd (no description set) + Working copy now at: 525afd5d4a26 (no description set) + Parent commit : 5f6eb3d5c5bf (no description set) "###); let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]); insta::assert_snapshot!(stdout, @""); @@ -97,8 +120,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) Parent commit : 1a986a275de6 (no description set) Added 0 files, modified 1 files, removed 1 files "###);