diff --git a/cli/src/commands/rebase.rs b/cli/src/commands/rebase.rs index 8b6ffc68cdf..bd50dcd2434 100644 --- a/cli/src/commands/rebase.rs +++ b/cli/src/commands/rebase.rs @@ -286,7 +286,7 @@ fn rebase_branch( } /// Rebases `old_commits` onto `new_parents`. -pub fn rebase_descendants( +fn rebase_descendants( tx: &mut WorkspaceCommandTransaction, settings: &UserSettings, new_parents: Vec, diff --git a/cli/src/commands/split.rs b/cli/src/commands/split.rs index dc5608c669d..8718339899e 100644 --- a/cli/src/commands/split.rs +++ b/cli/src/commands/split.rs @@ -13,18 +13,13 @@ // limitations under the License. use std::io::Write; -use itertools::Itertools; -use jj_lib::commit::Commit; use jj_lib::object_id::ObjectId; use jj_lib::repo::Repo; -use jj_lib::revset::{RevsetExpression, RevsetIteratorExt}; use jj_lib::rewrite::merge_commit_trees; -use jj_lib::settings::UserSettings; use tracing::instrument; -use crate::cli_util::{CommandHelper, RevisionArg, WorkspaceCommandTransaction}; +use crate::cli_util::{CommandHelper, RevisionArg}; use crate::command_error::CommandError; -use crate::commands::rebase::rebase_descendants; use crate::description_util::{description_template_for_commit, edit_description}; use crate::ui::Ui; @@ -179,16 +174,33 @@ the operation will be aborted. // commit. tx.mut_repo() .set_rewritten_commit(commit.id().clone(), second_commit.id().clone()); - let num_rebased = if args.siblings { - rebase_children_for_siblings_split( - &mut tx, - command.settings(), - &commit, - vec![first_commit.clone(), second_commit.clone()], - )? - } else { - tx.mut_repo().rebase_descendants(command.settings())? - }; + let mut num_rebased = 0; + tx.mut_repo().transform_descendants( + command.settings(), + vec![commit.id().clone()], + |mut rewriter| { + let old_parents = rewriter.old_commit().parent_ids(); + // Reserve space up front since we know we're adding at most one more parent. + let mut new_parents = Vec::with_capacity(old_parents.len() + 1); + for parent in old_parents { + if parent != commit.id() { + new_parents.push(parent.clone()); + continue; + } + if args.siblings { + new_parents.push(first_commit.id().clone()); + } + new_parents.push(second_commit.id().clone()); + num_rebased += 1; + } + rewriter.set_new_rewritten_parents(new_parents); + if rewriter.parents_changed() { + let builder = rewriter.rebase(command.settings())?; + builder.write()?; + } + Ok(()) + }, + )?; if let Some(mut formatter) = ui.status_formatter() { if num_rebased > 0 { @@ -203,36 +215,3 @@ the operation will be aborted. tx.finish(ui, format!("split commit {}", commit.id().hex()))?; Ok(()) } - -// Rebases the children of `original_commit` by replacing `original_commit` with -// `new_siblings`. Any parents other than `original_commit` will remain after -// the rebase. -fn rebase_children_for_siblings_split( - tx: &mut WorkspaceCommandTransaction, - settings: &UserSettings, - original_commit: &Commit, - new_siblings: Vec, -) -> Result { - let children: Vec = RevsetExpression::commit(original_commit.id().clone()) - .children() - .evaluate_programmatic(tx.base_repo().as_ref())? - .iter() - .commits(tx.base_repo().store()) - .try_collect()?; - let mut num_rebased = 0; - for child in children { - let new_parents = child - .parents() - .into_iter() - .flat_map(|c| { - if c.id() == original_commit.id() { - new_siblings.clone() - } else { - vec![c] - } - }) - .collect_vec(); - num_rebased += rebase_descendants(tx, settings, new_parents, &[child], Default::default())?; - } - Ok(num_rebased) -}