ok/jj
1
0
Fork 0
forked from mirrors/jj

cli: make jj merge delegate to jj new

This commit is contained in:
Martin von Zweigbergk 2022-08-30 22:31:18 -07:00 committed by Martin von Zweigbergk
parent d3286c2847
commit 3a46623446
3 changed files with 34 additions and 58 deletions

View file

@ -30,6 +30,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* `jj new` now always checks out the new commit (used to be only if the parent * `jj new` now always checks out the new commit (used to be only if the parent
was `@`). was `@`).
* `jj merge` now checks out the new commit. The command now behaves exactly
like `jj new`, except that it requires at least two arguments.
* When the working-copy commit is abandoned by `jj abandon` and the parent * When the working-copy commit is abandoned by `jj abandon` and the parent
commit is open, a new working-copy commit will be created on top (the open commit is open, a new working-copy commit will be created on top (the open
parent commit used to get checked out). parent commit used to get checked out).
@ -141,8 +145,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* `jj checkout` now lets you specify a description with `--message/-m`. * `jj checkout` now lets you specify a description with `--message/-m`.
* `jj merge` now outputs the id of the newly created commit.
* `jj new` can now be used for creating merge commits. If you pass more than * `jj new` can now be used for creating merge commits. If you pass more than
one argument to it, the new commit will have all of them as parents. one argument to it, the new commit will have all of them as parents.

View file

@ -1114,7 +1114,16 @@ enum Commands {
Restore(RestoreArgs), Restore(RestoreArgs),
Touchup(TouchupArgs), Touchup(TouchupArgs),
Split(SplitArgs), Split(SplitArgs),
Merge(MergeArgs), /// Merge work from multiple branches
///
/// Unlike most other VCSs, `jj merge` does not implicitly include the
/// working copy revision's parent as one of the parents of the merge;
/// you need to explicitly list all revisions that should become parents
/// of the merge.
///
/// This is the same as `jj new`, except that it requires at least two
/// arguments.
Merge(NewArgs),
Rebase(RebaseArgs), Rebase(RebaseArgs),
Backout(BackoutArgs), Backout(BackoutArgs),
#[clap(subcommand)] #[clap(subcommand)]
@ -1541,20 +1550,6 @@ struct SplitArgs {
paths: Vec<String>, paths: Vec<String>,
} }
/// Merge work from multiple branches
///
/// Unlike most other VCSs, `jj merge` does not implicitly include the working
/// copy revision's parent as one of the parents of the merge; you need to
/// explicitly list all revisions that should become parents of the merge. Also,
/// you need to explicitly check out the resulting revision if you want to.
#[derive(clap::Args, Clone, Debug)]
struct MergeArgs {
revisions: Vec<String>,
/// The change description to use (don't open editor)
#[clap(long, short)]
message: Option<String>,
}
/// Move revisions to a different parent /// Move revisions to a different parent
/// ///
/// There are three different ways of specifying which revisions to rebase: /// There are three different ways of specifying which revisions to rebase:
@ -3956,50 +3951,13 @@ any changes, then the operation will be aborted.
Ok(()) Ok(())
} }
fn cmd_merge(ui: &mut Ui, command: &CommandHelper, args: &MergeArgs) -> Result<(), CommandError> { fn cmd_merge(ui: &mut Ui, command: &CommandHelper, args: &NewArgs) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?; if args.revisions.len() < 2 {
let revision_args = &args.revisions; return Err(CommandError::CliError(String::from(
if revision_args.len() < 2 {
return Err(CommandError::UserError(String::from(
"Merge requires at least two revisions", "Merge requires at least two revisions",
))); )));
} }
let mut commits = vec![]; cmd_new(ui, command, args)
let mut parent_ids = vec![];
for revision_arg in revision_args {
// TODO: Should we allow each argument to resolve to multiple revisions?
// It would be neat to be able to do `jj merge main` when `main` is conflicted,
// but I'm not sure it would actually be useful.
let commit = workspace_command.resolve_single_rev(revision_arg)?;
parent_ids.push(commit.id().clone());
commits.push(commit);
}
let description = if let Some(message) = &args.message {
message.to_string()
} else {
edit_description(
ui,
workspace_command.repo(),
"\n\nJJ: Enter commit description for the merge commit.\n",
)?
};
let merged_tree = merge_commit_trees(workspace_command.repo().as_repo_ref(), &commits);
let mut tx = workspace_command.start_transaction("merge commits");
let new_commit = CommitBuilder::for_new_commit(ui.settings(), merged_tree.id().clone())
.set_parents(parent_ids)
.set_description(description)
.set_open(false)
.write_to_repo(tx.mut_repo());
ui.write("Created merge commit: ")?;
ui.write_commit_summary(
workspace_command.repo().as_repo_ref(),
&workspace_command.workspace_id(),
&new_commit,
)?;
ui.write("\n")?;
workspace_command.finish_transaction(ui, tx)?;
Ok(())
} }
fn cmd_rebase(ui: &mut Ui, command: &CommandHelper, args: &RebaseArgs) -> Result<(), CommandError> { fn cmd_rebase(ui: &mut Ui, command: &CommandHelper, args: &RebaseArgs) -> Result<(), CommandError> {

View file

@ -70,6 +70,22 @@ fn test_new_merge() {
insta::assert_snapshot!(stdout, @"a"); insta::assert_snapshot!(stdout, @"a");
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]); let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]);
insta::assert_snapshot!(stdout, @"b"); insta::assert_snapshot!(stdout, @"b");
// Same test with `jj merge`
test_env.jj_cmd_success(&repo_path, &["undo"]);
test_env.jj_cmd_success(&repo_path, &["merge", "main", "@"]);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ c34d60aa33225c2080da52faa39980efe944bddd (no description set)
|\
o | 99814c62bec5c13d2053435b3d6bbeb1900cb57e add file2
| o fe37af248a068697c6dcd7ebd17f5aac2205e7cb add file1
|/
o 0000000000000000000000000000000000000000 (no description set)
"###);
// `jj merge` with less than two arguments is an error
test_env.jj_cmd_cli_error(&repo_path, &["merge"]);
test_env.jj_cmd_cli_error(&repo_path, &["merge", "main"]);
} }
fn get_log_output(test_env: &TestEnvironment, repo_path: &Path) -> String { fn get_log_output(test_env: &TestEnvironment, repo_path: &Path) -> String {