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
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
commit is open, a new working-copy commit will be created on top (the open
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 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
one argument to it, the new commit will have all of them as parents.

View file

@ -1114,7 +1114,16 @@ enum Commands {
Restore(RestoreArgs),
Touchup(TouchupArgs),
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),
Backout(BackoutArgs),
#[clap(subcommand)]
@ -1541,20 +1550,6 @@ struct SplitArgs {
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
///
/// There are three different ways of specifying which revisions to rebase:
@ -3956,50 +3951,13 @@ any changes, then the operation will be aborted.
Ok(())
}
fn cmd_merge(ui: &mut Ui, command: &CommandHelper, args: &MergeArgs) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?;
let revision_args = &args.revisions;
if revision_args.len() < 2 {
return Err(CommandError::UserError(String::from(
fn cmd_merge(ui: &mut Ui, command: &CommandHelper, args: &NewArgs) -> Result<(), CommandError> {
if args.revisions.len() < 2 {
return Err(CommandError::CliError(String::from(
"Merge requires at least two revisions",
)));
}
let mut commits = vec![];
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(())
cmd_new(ui, command, args)
}
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");
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]);
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 {