Skip to content

Commit

Permalink
split: add --empty-parent and --empty-child options
Browse files Browse the repository at this point in the history
  • Loading branch information
samueltardieu committed Jan 31, 2023
1 parent f1e6146 commit aa26480
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 20 deletions.
65 changes: 45 additions & 20 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use jujutsu_lib::backend::{CommitId, ObjectId, TreeValue};
use jujutsu_lib::commit::Commit;
use jujutsu_lib::dag_walk::topo_order_reverse;
use jujutsu_lib::index::IndexEntry;
use jujutsu_lib::matchers::EverythingMatcher;
use jujutsu_lib::matchers::{EverythingMatcher, NothingMatcher};
use jujutsu_lib::op_store::{RefTarget, WorkspaceId};
use jujutsu_lib::repo::ReadonlyRepo;
use jujutsu_lib::repo_path::RepoPath;
Expand Down Expand Up @@ -622,10 +622,21 @@ struct DiffeditArgs {
/// the previous revision. The remaining changes will be put in a new revision
/// on top. You will be asked to enter a change description for each.
#[derive(clap::Args, Clone, Debug)]
#[command(group(ArgGroup::new("arg").args(&["empty_parent", "empty_child", "paths"])))]
struct SplitArgs {
/// The revision to split
#[arg(long, short, default_value = "@")]
revision: RevisionArg,
/// Add a new empty commit between the commit and its parent
///
/// This option must be used alone
#[arg(long, short = 'P')]
empty_parent: bool,
/// Add a new empty commit between the commit and its children if any
///
/// This option must be used alone
#[arg(long, short = 'C')]
empty_child: bool,
/// Put these paths in the first commit and don't run the diff editor
#[arg(value_hint = clap::ValueHint::AnyPath)]
paths: Vec<String>,
Expand Down Expand Up @@ -2558,11 +2569,17 @@ fn cmd_split(ui: &mut Ui, command: &CommandHelper, args: &SplitArgs) -> Result<(
let mut workspace_command = command.workspace_helper(ui)?;
let commit = workspace_command.resolve_single_rev(&args.revision)?;
workspace_command.check_rewriteable(&commit)?;
let matcher = workspace_command.matcher_from_values(&args.paths)?;
let matcher = if args.empty_child {
Box::new(EverythingMatcher)
} else if args.empty_parent {
Box::new(NothingMatcher)
} else {
workspace_command.matcher_from_values(&args.paths)?
};
let mut tx =
workspace_command.start_transaction(&format!("split commit {}", commit.id().hex()));
let base_tree = merge_commit_trees(tx.base_repo().as_repo_ref(), &commit.parents());
let interactive = args.paths.is_empty();
let interactive = args.paths.is_empty() && !args.empty_child && !args.empty_parent;
let instructions = format!(
"\
You are splitting a commit in two: {}
Expand Down Expand Up @@ -2592,29 +2609,37 @@ don't make any changes, then the operation will be aborted.
.store()
.get_tree(&RepoPath::root(), &tree_id)?;

let first_template = description_template_for_cmd_split(
tx.base_workspace_helper(),
"Enter commit description for the first part (parent).",
commit.description(),
&base_tree,
&middle_tree,
)?;
let first_description = edit_description(tx.base_repo(), &first_template, command.settings())?;
let (first_description, second_description) = if args.empty_child {
(commit.description().to_owned(), String::new())
} else if args.empty_parent {
(String::new(), commit.description().to_owned())
} else {
let first_template = description_template_for_cmd_split(
tx.base_workspace_helper(),
"Enter commit description for the first part (parent).",
commit.description(),
&base_tree,
&middle_tree,
)?;
let first_description =
edit_description(tx.base_repo(), &first_template, command.settings())?;
let second_template = description_template_for_cmd_split(
tx.base_workspace_helper(),
"Enter commit description for the second part (child).",
commit.description(),
&middle_tree,
&commit.tree(),
)?;
let second_description =
edit_description(tx.base_repo(), &second_template, command.settings())?;
(first_description, second_description)
};
let first_commit = tx
.mut_repo()
.rewrite_commit(command.settings(), &commit)
.set_tree(tree_id)
.set_description(first_description)
.write()?;
let second_template = description_template_for_cmd_split(
tx.base_workspace_helper(),
"Enter commit description for the second part (child).",
commit.description(),
&middle_tree,
&commit.tree(),
)?;
let second_description =
edit_description(tx.base_repo(), &second_template, command.settings())?;
let second_commit = tx
.mut_repo()
.rewrite_commit(command.settings(), &commit)
Expand Down
128 changes: 128 additions & 0 deletions tests/test_split_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,131 @@ fn test_split_by_paths() {
A file2
"###);
}

#[test]
fn test_split_empty_child() {
let 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");

std::fs::write(repo_path.join("file1"), "foo").unwrap();
test_env.jj_cmd_success(&repo_path, &["commit", "-m", "original parent"]);

std::fs::write(repo_path.join("file2"), "foo").unwrap();
test_env.jj_cmd_success(&repo_path, &["commit", "-m", "target commit"]);

std::fs::write(repo_path.join("file3"), "foo").unwrap();
test_env.jj_cmd_success(&repo_path, &["describe", "-m", "first original child"]);

test_env.jj_cmd_success(
&repo_path,
&["new", "-r", "@-", "-m", "second original child"],
);
std::fs::write(repo_path.join("file3"), "foo").unwrap();

let stdout = test_env.jj_cmd_success(
&repo_path,
&[
"log",
"-T",
r#"change_id.short() if(empty, " (empty) ", " ") description"#,
],
);
insta::assert_snapshot!(stdout, @r###"
@ d043564ef936 second original child
| o ffdaa62087a2 first original child
|/
o 8e4fac809cbb target commit
o 9a45c67d3e96 original parent
o 000000000000 (empty) (no description set)
"###);

let stdout = test_env.jj_cmd_success(&repo_path, &["split", "-r", "@-", "--empty-child"]);
insta::assert_snapshot!(stdout, @r###"
Rebased 2 descendant commits
First part: 198584685467 target commit
Second part: 1c004c965469 (no description set)
Working copy now at: a3941c48999c second original child
"###);
let stdout = test_env.jj_cmd_success(
&repo_path,
&[
"log",
"-T",
r#"change_id.short() if(empty, " (empty) ", " ") description"#,
],
);
insta::assert_snapshot!(stdout, @r###"
@ d043564ef936 second original child
| o ffdaa62087a2 first original child
|/
o 19b790168e73 (empty) (no description set)
o 8e4fac809cbb target commit
o 9a45c67d3e96 original parent
o 000000000000 (empty) (no description set)
"###);
}

#[test]
fn test_split_empty_parent() {
let 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");

std::fs::write(repo_path.join("file1"), "foo").unwrap();
test_env.jj_cmd_success(&repo_path, &["commit", "-m", "original parent"]);

std::fs::write(repo_path.join("file2"), "foo").unwrap();
test_env.jj_cmd_success(&repo_path, &["commit", "-m", "target commit"]);

std::fs::write(repo_path.join("file3"), "foo").unwrap();
test_env.jj_cmd_success(&repo_path, &["describe", "-m", "first original child"]);

test_env.jj_cmd_success(
&repo_path,
&["new", "-r", "@-", "-m", "second original child"],
);
std::fs::write(repo_path.join("file3"), "foo").unwrap();

let stdout = test_env.jj_cmd_success(
&repo_path,
&[
"log",
"-T",
r#"change_id.short() if(empty, " (empty) ", " ") description"#,
],
);
insta::assert_snapshot!(stdout, @r###"
@ d043564ef936 second original child
| o ffdaa62087a2 first original child
|/
o 8e4fac809cbb target commit
o 9a45c67d3e96 original parent
o 000000000000 (empty) (no description set)
"###);

let stdout = test_env.jj_cmd_success(&repo_path, &["split", "-r", "@-", "--empty-parent"]);
insta::assert_snapshot!(stdout, @r###"
Rebased 2 descendant commits
First part: e50bed592047 (no description set)
Second part: 0c956b3f408e target commit
Working copy now at: c41f6d9f1cf7 second original child
"###);
let stdout = test_env.jj_cmd_success(
&repo_path,
&[
"log",
"-T",
r#"change_id.short() if(empty, " (empty) ", " ") description"#,
],
);
insta::assert_snapshot!(stdout, @r###"
@ d043564ef936 second original child
| o ffdaa62087a2 first original child
|/
o 19b790168e73 target commit
o 8e4fac809cbb (empty) (no description set)
o 9a45c67d3e96 original parent
o 000000000000 (empty) (no description set)
"###);
}

0 comments on commit aa26480

Please sign in to comment.