cli: teach jj squash to move only changes to specified paths

This commit is contained in:
Martin von Zweigbergk 2022-04-09 10:27:17 -07:00 committed by Martin von Zweigbergk
parent 082ec5ae3b
commit 4be0da3607
3 changed files with 55 additions and 21 deletions

View File

@ -11,10 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* The new `jj print` command prints the contents of a file in a revision.
* `jj move` now lets you limit the set of changes to move by specifying paths
on the command line (in addition to the `--interactive` mode). For example,
use `jj move --to @-- foo` to move the changes to file (or directory) `foo` in
the working copy to the grandparent commit.
* `jj move` and `jj squash` now lets you limit the set of changes to move by
specifying paths on the command line (in addition to the `--interactive`
mode). For example, use `jj move --to @-- foo` to move the changes to file
(or directory) `foo` in the working copy to the grandparent commit.
### Fixed bugs

View File

@ -1292,6 +1292,9 @@ struct SquashArgs {
/// Interactively choose which parts to squash
#[clap(long, short)]
interactive: bool,
/// Move only changes to these paths (instead of all paths)
#[clap(conflicts_with = "interactive")]
paths: Vec<String>,
}
/// Move changes from a revision's parent into the revision
@ -3245,10 +3248,8 @@ fn cmd_squash(ui: &mut Ui, command: &CommandHelper, args: &SquashArgs) -> Result
let mut tx =
workspace_command.start_transaction(&format!("squash commit {}", commit.id().hex()));
let mut_repo = tx.mut_repo();
let new_parent_tree_id;
if args.interactive {
let instructions = format!(
"\
let instructions = format!(
"\
You are moving changes from: {}
into its parent: {}
@ -3260,16 +3261,19 @@ Adjust the right side until the diff shows the changes you want to move
to the destination. If you don't make any changes, then all the changes
from the source will be moved into the parent.
",
short_commit_description(&commit),
short_commit_description(parent)
);
new_parent_tree_id =
workspace_command.edit_diff(&parent.tree(), &commit.tree(), &instructions)?;
if &new_parent_tree_id == parent.tree().id() {
return Err(CommandError::UserError(String::from("No changes selected")));
}
} else {
new_parent_tree_id = commit.tree().id().clone();
short_commit_description(&commit),
short_commit_description(parent)
);
let new_parent_tree_id = workspace_command.select_diff(
ui,
&parent.tree(),
&commit.tree(),
&instructions,
args.interactive,
&args.paths,
)?;
if &new_parent_tree_id == parent.tree().id() {
return Err(CommandError::UserError(String::from("No changes selected")));
}
// Abandon the child if the parent now has all the content from the child
// (always the case in the non-interactive case).

View File

@ -122,7 +122,7 @@ fn test_squash() {
}
#[test]
fn test_squash_interactive() {
fn test_squash_partial() {
let mut test_env = TestEnvironment::default();
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
@ -148,7 +148,8 @@ fn test_squash_interactive() {
o 000000000000
"###);
// Everything is moved into the parent if no change is made
// If we don't make any changes in the diff-editor, the whole change is moved
// into the parent
let edit_script = test_env.set_up_fake_diff_editor();
std::fs::write(&edit_script, "").unwrap();
let stdout = test_env.jj_cmd_success(&repo_path, &["squash", "-r", "b", "-i"]);
@ -166,7 +167,7 @@ fn test_squash_interactive() {
insta::assert_snapshot!(stdout, @"b
");
// Can squash only some changes
// Can squash only some changes in interactive mode
test_env.jj_cmd_success(&repo_path, &["undo"]);
std::fs::write(&edit_script, "reset file1").unwrap();
let stdout = test_env.jj_cmd_success(&repo_path, &["squash", "-r", "b", "-i"]);
@ -193,4 +194,33 @@ fn test_squash_interactive() {
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2", "-r", "b"]);
insta::assert_snapshot!(stdout, @"b
");
// Can squash only some changes in non-interactive mode
test_env.jj_cmd_success(&repo_path, &["undo"]);
// Clear the script so we know it won't be used even without -i
std::fs::write(&edit_script, "").unwrap();
let stdout = test_env.jj_cmd_success(&repo_path, &["squash", "-r", "b", "file2"]);
insta::assert_snapshot!(stdout, @r###"
Rebased 1 descendant commits
Working copy now at: a911fa1d0627
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", template]);
insta::assert_snapshot!(stdout, @r###"
@ a911fa1d0627 c
o fb73ad17899f b
o 70621f4c7a42 a
o 000000000000
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1", "-r", "a"]);
insta::assert_snapshot!(stdout, @"a
");
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2", "-r", "a"]);
insta::assert_snapshot!(stdout, @"b
");
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1", "-r", "b"]);
insta::assert_snapshot!(stdout, @"b
");
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2", "-r", "b"]);
insta::assert_snapshot!(stdout, @"b
");
}