Skip to content

Commit

Permalink
rebase -s: add support for --insert-after and --insert-before opt…
Browse files Browse the repository at this point in the history
…ions
  • Loading branch information
bnjmnt4n committed Oct 16, 2024
1 parent e3ebb11 commit aa46c02
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 59 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ Thanks to the people who made this release happen!

* When reconfiguring the author, warn that the working copy won't be updated

* `jj rebase -s` can now be used with the `--insert-after` and `--insert-before`
options, like `jj rebase -r`.

### Fixed bugs

* Release binaries for Intel Macs have been restored. They were previously
Expand Down
97 changes: 63 additions & 34 deletions cli/src/commands/rebase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,26 +169,24 @@ pub(crate) struct RebaseArgs {
/// The revision(s) to insert after (can be repeated to create a merge
/// commit)
///
/// Only works with `-r`.
/// Only works with `-r` and `-s`.
#[arg(
long,
short = 'A',
visible_alias = "after",
conflicts_with = "destination",
conflicts_with = "source",
conflicts_with = "branch"
)]
insert_after: Vec<RevisionArg>,
/// The revision(s) to insert before (can be repeated to create a merge
/// commit)
///
/// Only works with `-r`.
/// Only works with `-r` and `-s`.
#[arg(
long,
short = 'B',
visible_alias = "before",
conflicts_with = "destination",
conflicts_with = "source",
conflicts_with = "branch"
)]
insert_before: Vec<RevisionArg>,
Expand Down Expand Up @@ -252,18 +250,14 @@ pub(crate) fn cmd_rebase(
&rebase_options,
)?;
} else if !args.source.is_empty() {
let new_parents = workspace_command
.resolve_some_revsets_default_single(ui, &args.destination)?
.into_iter()
.collect_vec();
let source_commits =
workspace_command.resolve_some_revsets_default_single(ui, &args.source)?;
rebase_descendants_transaction(
rebase_source(
ui,
command.settings(),
&mut workspace_command,
new_parents,
&source_commits,
&args.source,
&args.destination,
&args.insert_after,
&args.insert_before,
&rebase_options,
)?;
} else {
Expand Down Expand Up @@ -333,6 +327,47 @@ fn rebase_revisions(
)
}

#[allow(clippy::too_many_arguments)]
fn rebase_source(
ui: &mut Ui,
settings: &UserSettings,
workspace_command: &mut WorkspaceCommandHelper,
source: &[RevisionArg],
destination: &[RevisionArg],
insert_after: &[RevisionArg],
insert_before: &[RevisionArg],
rebase_options: &RebaseOptions,
) -> Result<(), CommandError> {
let source_commits = workspace_command
.resolve_some_revsets_default_single(ui, source)?
.into_iter()
.collect_vec();
workspace_command.check_rewritable(source_commits.iter().ids())?;

let (new_parents, new_children) = compute_rebase_destination(
ui,
workspace_command,
destination,
insert_after,
insert_before,
)?;
if !destination.is_empty() && new_children.is_empty() {
for commit in &source_commits {
check_rebase_destinations(workspace_command.repo(), &new_parents, commit)?;
}
}

rebase_descendants_transaction(
ui,
settings,
workspace_command,
&new_parents.iter().ids().cloned().collect_vec(),
&new_children,
&source_commits,
rebase_options,
)
}

fn rebase_branch(
ui: &mut Ui,
settings: &UserSettings,
Expand All @@ -341,28 +376,31 @@ fn rebase_branch(
branch_commits: &IndexSet<Commit>,
rebase_options: RebaseOptions,
) -> Result<(), CommandError> {
let parent_ids = new_parents
.iter()
.map(|commit| commit.id().clone())
.collect_vec();
let parent_ids = new_parents.iter().ids().cloned().collect_vec();
let branch_commit_ids = branch_commits
.iter()
.map(|commit| commit.id().clone())
.collect_vec();
let roots_expression = RevsetExpression::commits(parent_ids)
let roots_expression = RevsetExpression::commits(parent_ids.clone())
.range(&RevsetExpression::commits(branch_commit_ids))
.roots();
let root_commits: IndexSet<_> = roots_expression
let root_commits: Vec<_> = roots_expression
.evaluate_programmatic(workspace_command.repo().as_ref())
.unwrap()
.iter()
.commits(workspace_command.repo().store())
.try_collect()?;
workspace_command.check_rewritable(root_commits.iter().ids())?;
for commit in &root_commits {
check_rebase_destinations(workspace_command.repo(), &new_parents, commit)?;
}

rebase_descendants_transaction(
ui,
settings,
workspace_command,
new_parents,
&parent_ids,
&[],
&root_commits,
&rebase_options,
)
Expand All @@ -372,19 +410,15 @@ fn rebase_descendants_transaction(
ui: &mut Ui,
settings: &UserSettings,
workspace_command: &mut WorkspaceCommandHelper,
new_parents: Vec<Commit>,
target_roots: &IndexSet<Commit>,
new_parent_ids: &[CommitId],
new_children: &[Commit],
target_roots: &[Commit],
rebase_options: &RebaseOptions,
) -> Result<(), CommandError> {
if target_roots.is_empty() {
return Ok(());
}

workspace_command.check_rewritable(target_roots.iter().ids())?;
for commit in target_roots.iter() {
check_rebase_destinations(workspace_command.repo(), &new_parents, commit)?;
}

let mut tx = workspace_command.start_transaction();
let tx_description = if target_roots.len() == 1 {
format!(
Expand All @@ -405,8 +439,6 @@ fn rebase_descendants_transaction(
.iter()
.commits(tx.repo().store())
.try_collect()?;
let new_parent_ids = new_parents.iter().ids().cloned().collect_vec();
let new_children: [Commit; 0] = [];
let target_roots = target_roots.iter().ids().cloned().collect_vec();

let MoveCommitsStats {
Expand All @@ -417,15 +449,12 @@ fn rebase_descendants_transaction(
} = move_commits(
settings,
tx.repo_mut(),
&new_parent_ids,
&new_children,
new_parent_ids,
new_children,
&target_commits,
Some(&target_roots),
rebase_options,
)?;
// All the descendants of the roots should be part of `target_commits`, so
// `num_rebased_descendants` should be 0.
assert_eq!(num_rebased_descendants, 0);

if num_skipped_rebases > 0 {
writeln!(
Expand Down
4 changes: 2 additions & 2 deletions cli/tests/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -1776,10 +1776,10 @@ commit. This is true in general; it is not specific to this command.
* `-d`, `--destination <DESTINATION>` — The revision(s) to rebase onto (can be repeated to create a merge commit)
* `-A`, `--insert-after <INSERT_AFTER>` — The revision(s) to insert after (can be repeated to create a merge commit)
Only works with `-r`.
Only works with `-r` and `-s`.
* `-B`, `--insert-before <INSERT_BEFORE>` — The revision(s) to insert before (can be repeated to create a merge commit)
Only works with `-r`.
Only works with `-r` and `-s`.
* `--skip-emptied` — If true, when rebasing would produce an empty commit, the commit is abandoned. It will not be abandoned if it was already empty before the rebase. Will never skip merge commits with multiple non-empty parents
Expand Down
Loading

0 comments on commit aa46c02

Please sign in to comment.