squash: move updating of source commits out of diff-editing loop

This is just a little refactoring to prepare for using
`transform_descendants()`.
This commit is contained in:
Martin von Zweigbergk 2024-04-18 10:16:13 -07:00 committed by Martin von Zweigbergk
parent 7319479df9
commit 2bd2358d6a

View File

@ -15,6 +15,7 @@
use itertools::Itertools as _; use itertools::Itertools as _;
use jj_lib::commit::{Commit, CommitIteratorExt}; use jj_lib::commit::{Commit, CommitIteratorExt};
use jj_lib::matchers::Matcher; use jj_lib::matchers::Matcher;
use jj_lib::merged_tree::MergedTree;
use jj_lib::object_id::ObjectId; use jj_lib::object_id::ObjectId;
use jj_lib::repo::Repo; use jj_lib::repo::Repo;
use jj_lib::revset; use jj_lib::revset;
@ -181,9 +182,14 @@ pub fn move_diff(
) -> Result<(), CommandError> { ) -> Result<(), CommandError> {
tx.base_workspace_helper() tx.base_workspace_helper()
.check_rewritable(sources.iter().chain(std::iter::once(destination)).ids())?; .check_rewritable(sources.iter().chain(std::iter::once(destination)).ids())?;
// Tree diffs to apply to the destination
let mut tree_diffs = vec![]; struct SourceCommit<'a> {
let mut abandoned_commits = vec![]; commit: &'a Commit,
parent_tree: MergedTree,
selected_tree: MergedTree,
abandon: bool,
}
let mut source_commits = vec![];
for source in sources { for source in sources {
let parent_tree = merge_commit_trees(tx.repo(), &source.parents())?; let parent_tree = merge_commit_trees(tx.repo(), &source.parents())?;
let source_tree = source.tree()?; let source_tree = source.tree()?;
@ -206,26 +212,20 @@ from the source will be moved into the destination.
let selected_tree_id = let selected_tree_id =
diff_selector.select(&parent_tree, &source_tree, matcher, Some(&instructions))?; diff_selector.select(&parent_tree, &source_tree, matcher, Some(&instructions))?;
let selected_tree = tx.repo().store().get_root_tree(&selected_tree_id)?; let selected_tree = tx.repo().store().get_root_tree(&selected_tree_id)?;
let abandon_source = selected_tree.id() == source_tree.id(); let abandon = selected_tree.id() == source_tree.id();
// TODO: Do we want to optimize the case of moving to the parent commit (`jj // TODO: Do we want to optimize the case of moving to the parent commit (`jj
// squash -r`)? The source tree will be unchanged in that case. // squash -r`)? The source tree will be unchanged in that case.
source_commits.push(SourceCommit {
// Apply the reverse of the selected changes onto the source commit: source,
let new_source_tree = source_tree.merge(&selected_tree, &parent_tree)?; parent_tree,
if abandon_source { selected_tree,
abandoned_commits.push(source); abandon,
tx.mut_repo().record_abandoned_commit(source.id().clone()); });
} else {
tx.mut_repo()
.rewrite_commit(settings, source)
.set_tree_id(new_source_tree.id().clone())
.write()?;
} }
if selected_tree_id != parent_tree.id() { if source_commits
tree_diffs.push((parent_tree, selected_tree)); .iter()
} .all(|source| source.selected_tree == source.parent_tree)
} {
if tree_diffs.is_empty() {
if diff_selector.is_interactive() { if diff_selector.is_interactive() {
return Err(user_error("No changes selected")); return Err(user_error("No changes selected"));
} }
@ -246,6 +246,22 @@ from the source will be moved into the destination.
} }
} }
} }
for source in &source_commits {
if source.abandon {
tx.mut_repo()
.record_abandoned_commit(source.commit.id().clone());
} else {
let source_tree = source.commit.tree()?;
// Apply the reverse of the selected changes onto the source
let new_source_tree = source_tree.merge(&source.selected_tree, &source.parent_tree)?;
tx.mut_repo()
.rewrite_commit(settings, source.commit)
.set_tree_id(new_source_tree.id().clone())
.write()?;
}
}
let mut rewritten_destination = destination.clone(); let mut rewritten_destination = destination.clone();
if sources if sources
.iter() .iter()
@ -261,13 +277,17 @@ from the source will be moved into the destination.
} }
// Apply the selected changes onto the destination // Apply the selected changes onto the destination
let mut destination_tree = rewritten_destination.tree()?; let mut destination_tree = rewritten_destination.tree()?;
for (tree1, tree2) in tree_diffs { for source in &source_commits {
destination_tree = destination_tree.merge(&tree1, &tree2)?; destination_tree = destination_tree.merge(&source.parent_tree, &source.selected_tree)?;
} }
let description = match description { let description = match description {
SquashedDescription::Exact(description) => description, SquashedDescription::Exact(description) => description,
SquashedDescription::UseDestination => destination.description().to_owned(), SquashedDescription::UseDestination => destination.description().to_owned(),
SquashedDescription::Combine => { SquashedDescription::Combine => {
let abandoned_commits = source_commits
.iter()
.filter_map(|source| source.abandon.then_some(source.commit))
.collect_vec();
combine_messages(tx.base_repo(), &abandoned_commits, destination, settings)? combine_messages(tx.base_repo(), &abandoned_commits, destination, settings)?
} }
}; };