Skip to content

Commit

Permalink
jj rebase: Allow revsets with multiple commits with new --multi
Browse files Browse the repository at this point in the history
Eventually, we should be able to rely on `jj op restore` and the `--multi`
argument should likely be removed. This is a temporary measure until we figure
out #922 and the like.

Fixes #571
  • Loading branch information
ilyagr committed Feb 4, 2023
1 parent 1ddbb6d commit ba30263
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
and `jj split any-non-existent-path` inserts an empty commit between the
target commit and its parents.

* `jj rebase` now accepts a new `--multi` argument that allows the revset in the
`-d` argument to expand to several revisions. For example, `jj rebase -s B -d
B- -d C` now works even if `B` is a merge commit.

### Fixed bugs

* When sharing the working copy with a Git repo, we used to forget to export
Expand Down
25 changes: 18 additions & 7 deletions src/cli_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1386,15 +1386,26 @@ fn load_revset_aliases(
pub fn resolve_base_revs(
workspace_command: &WorkspaceCommandHelper,
revisions: &[RevisionArg],
multi: bool,
) -> Result<IndexSet<Commit>, CommandError> {
let mut commits = IndexSet::new();
for revision_str in revisions {
let commit = workspace_command.resolve_single_rev(revision_str)?;
let commit_hash = short_commit_hash(commit.id());
if !commits.insert(commit) {
return Err(user_error(format!(
r#"More than one revset resolved to revision {commit_hash}"#,
)));
if multi {
for revset in revisions {
let revisions = workspace_command.resolve_revset(revset)?;
workspace_command.check_non_empty(&revisions)?;
// It's OK if one of the base revs includes a non-rewritable commit
commits.extend(revisions);
}
} else {
// TODO: Change the error resolve_single_rev returns!
for revision_str in revisions {
let commit = workspace_command.resolve_single_rev(revision_str)?;
let commit_hash = short_commit_hash(commit.id());
if !commits.insert(commit) {
return Err(user_error(format!(
r#"More than one revset resolved to revision {commit_hash}"#,
)));
}
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,9 @@ struct NewArgs {
/// Parent(s) of the new change
#[arg(default_value = "@")]
revisions: Vec<RevisionArg>,
/// Allow revsets expanding to multiple commits in a single argument
#[arg(long)]
multi: bool,
/// Ignored (but lets you pass `-r` for consistency with other commands)
#[arg(short = 'r', hide = true)]
unused_revision: bool,
Expand Down Expand Up @@ -725,6 +728,9 @@ struct RebaseArgs {
/// The revision(s) to rebase onto
#[arg(long, short, required = true)]
destination: Vec<RevisionArg>,
/// Allow revsets expanding to multiple commits in a single argument
#[arg(long)]
multi: bool,
}

/// Apply the reverse of a revision on top of another revision
Expand Down Expand Up @@ -1994,7 +2000,7 @@ fn cmd_new(ui: &mut Ui, command: &CommandHelper, args: &NewArgs) -> Result<(), C
!args.revisions.is_empty(),
"expected a non-empty list from clap"
);
let commits = resolve_base_revs(&workspace_command, &args.revisions)?
let commits = resolve_base_revs(&workspace_command, &args.revisions, args.multi)?
.into_iter()
.collect_vec();
let parent_ids = commits.iter().map(|c| c.id().clone()).collect();
Expand Down Expand Up @@ -2685,7 +2691,7 @@ fn cmd_merge(ui: &mut Ui, command: &CommandHelper, args: &NewArgs) -> Result<(),

fn cmd_rebase(ui: &mut Ui, command: &CommandHelper, args: &RebaseArgs) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?;
let new_parents = resolve_base_revs(&workspace_command, &args.destination)?
let new_parents = resolve_base_revs(&workspace_command, &args.destination, args.multi)?
.into_iter()
.collect_vec();
if let Some(rev_str) = &args.revision {
Expand Down
11 changes: 11 additions & 0 deletions tests/test_rebase_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,17 @@ fn test_rebase_multiple_destinations() {
fe2e8e8b50b3 c
d370aee184ba b
"###);
let stdout =
test_env.jj_cmd_success(&repo_path, &["rebase", "--multi", "-r", "a", "-d", "b|c"]);
insta::assert_snapshot!(stdout, @r###""###);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
o a
|\
@ | c
| o b
|/
o
"###);

let stderr =
test_env.jj_cmd_failure(&repo_path, &["rebase", "-r", "a", "-d", "b", "-d", "root"]);
Expand Down

0 comments on commit ba30263

Please sign in to comment.