forked from mirrors/jj
move: extract bulk of logic to function for reuse by jj squash
This commit is contained in:
parent
7f101c4023
commit
018a871ce9
2 changed files with 86 additions and 70 deletions
|
@ -14,13 +14,11 @@
|
|||
|
||||
use clap::ArgGroup;
|
||||
use jj_lib::object_id::ObjectId;
|
||||
use jj_lib::repo::Repo;
|
||||
use jj_lib::rewrite::merge_commit_trees;
|
||||
use tracing::instrument;
|
||||
|
||||
use super::squash::move_diff;
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::description_util::combine_messages;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Move changes from one revision into another
|
||||
|
@ -66,12 +64,10 @@ pub(crate) fn cmd_move(
|
|||
) -> Result<(), CommandError> {
|
||||
let mut workspace_command = command.workspace_helper(ui)?;
|
||||
let source = workspace_command.resolve_single_rev(args.from.as_deref().unwrap_or("@"))?;
|
||||
let mut destination =
|
||||
workspace_command.resolve_single_rev(args.to.as_deref().unwrap_or("@"))?;
|
||||
let destination = workspace_command.resolve_single_rev(args.to.as_deref().unwrap_or("@"))?;
|
||||
if source.id() == destination.id() {
|
||||
return Err(user_error("Source and destination cannot be the same."));
|
||||
}
|
||||
workspace_command.check_rewritable([&source, &destination])?;
|
||||
let matcher = workspace_command.matcher_from_values(&args.paths)?;
|
||||
let diff_selector =
|
||||
workspace_command.diff_selector(ui, args.tool.as_deref(), args.interactive)?;
|
||||
|
@ -81,71 +77,14 @@ pub(crate) fn cmd_move(
|
|||
source.id().hex(),
|
||||
destination.id().hex()
|
||||
);
|
||||
let parent_tree = merge_commit_trees(tx.repo(), &source.parents())?;
|
||||
let source_tree = source.tree()?;
|
||||
let instructions = format!(
|
||||
"\
|
||||
You are moving changes from: {}
|
||||
into commit: {}
|
||||
|
||||
The left side of the diff shows the contents of the parent commit. The
|
||||
right side initially shows the contents of the commit you're moving
|
||||
changes from.
|
||||
|
||||
Adjust the right side until the diff shows the changes you want to move
|
||||
to the destination. If you don't make any changes, then all the changes
|
||||
from the source will be moved into the destination.
|
||||
",
|
||||
tx.format_commit_summary(&source),
|
||||
tx.format_commit_summary(&destination)
|
||||
);
|
||||
let new_parent_tree_id = diff_selector.select(
|
||||
&parent_tree,
|
||||
&source_tree,
|
||||
matcher.as_ref(),
|
||||
Some(&instructions),
|
||||
)?;
|
||||
if diff_selector.is_interactive() && new_parent_tree_id == parent_tree.id() {
|
||||
return Err(user_error("No changes to move"));
|
||||
}
|
||||
let new_parent_tree = tx.repo().store().get_root_tree(&new_parent_tree_id)?;
|
||||
// Apply the reverse of the selected changes onto the source
|
||||
let new_source_tree = source_tree.merge(&new_parent_tree, &parent_tree)?;
|
||||
let abandon_source = new_source_tree.id() == parent_tree.id();
|
||||
if abandon_source {
|
||||
tx.mut_repo().record_abandoned_commit(source.id().clone());
|
||||
} else {
|
||||
tx.mut_repo()
|
||||
.rewrite_commit(command.settings(), &source)
|
||||
.set_tree_id(new_source_tree.id().clone())
|
||||
.write()?;
|
||||
}
|
||||
if tx.repo().index().is_ancestor(source.id(), destination.id()) {
|
||||
// If we're moving changes to a descendant, first rebase descendants onto the
|
||||
// rewritten source. Otherwise it will likely already have the content
|
||||
// changes we're moving, so applying them will have no effect and the
|
||||
// changes will disappear.
|
||||
let rebase_map = tx
|
||||
.mut_repo()
|
||||
.rebase_descendants_return_map(command.settings())?;
|
||||
let rebased_destination_id = rebase_map.get(destination.id()).unwrap().clone();
|
||||
destination = tx.mut_repo().store().get_commit(&rebased_destination_id)?;
|
||||
}
|
||||
// Apply the selected changes onto the destination
|
||||
let destination_tree = destination.tree()?;
|
||||
let new_destination_tree = destination_tree.merge(&parent_tree, &new_parent_tree)?;
|
||||
let description = combine_messages(
|
||||
tx.base_repo(),
|
||||
&source,
|
||||
&destination,
|
||||
move_diff(
|
||||
&mut tx,
|
||||
command.settings(),
|
||||
abandon_source,
|
||||
source,
|
||||
destination,
|
||||
matcher.as_ref(),
|
||||
&diff_selector,
|
||||
)?;
|
||||
tx.mut_repo()
|
||||
.rewrite_commit(command.settings(), &destination)
|
||||
.set_tree_id(new_destination_tree.id().clone())
|
||||
.set_description(description)
|
||||
.write()?;
|
||||
tx.finish(ui, tx_description)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -13,11 +13,16 @@
|
|||
// limitations under the License.
|
||||
|
||||
use clap::parser::ValueSource;
|
||||
use jj_lib::commit::Commit;
|
||||
use jj_lib::matchers::Matcher;
|
||||
use jj_lib::object_id::ObjectId;
|
||||
use jj_lib::repo::Repo;
|
||||
use jj_lib::revset;
|
||||
use jj_lib::rewrite::merge_commit_trees;
|
||||
use jj_lib::settings::UserSettings;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, DiffSelector, RevisionArg, WorkspaceCommandTransaction};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::description_util::{combine_messages, join_message_paragraphs};
|
||||
use crate::ui::Ui;
|
||||
|
@ -147,3 +152,75 @@ from the source will be moved into the parent.
|
|||
tx.finish(ui, format!("squash commit {}", commit.id().hex()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn move_diff(
|
||||
tx: &mut WorkspaceCommandTransaction,
|
||||
settings: &UserSettings,
|
||||
source: Commit,
|
||||
mut destination: Commit,
|
||||
matcher: &dyn Matcher,
|
||||
diff_selector: &DiffSelector,
|
||||
) -> Result<(), CommandError> {
|
||||
tx.base_workspace_helper()
|
||||
.check_rewritable([&source, &destination])?;
|
||||
let parent_tree = merge_commit_trees(tx.repo(), &source.parents())?;
|
||||
let source_tree = source.tree()?;
|
||||
let instructions = format!(
|
||||
"\
|
||||
You are moving changes from: {}
|
||||
into commit: {}
|
||||
|
||||
The left side of the diff shows the contents of the parent commit. The
|
||||
right side initially shows the contents of the commit you're moving
|
||||
changes from.
|
||||
|
||||
Adjust the right side until the diff shows the changes you want to move
|
||||
to the destination. If you don't make any changes, then all the changes
|
||||
from the source will be moved into the destination.
|
||||
",
|
||||
tx.format_commit_summary(&source),
|
||||
tx.format_commit_summary(&destination)
|
||||
);
|
||||
let new_parent_tree_id =
|
||||
diff_selector.select(&parent_tree, &source_tree, matcher, Some(&instructions))?;
|
||||
if diff_selector.is_interactive() && new_parent_tree_id == parent_tree.id() {
|
||||
return Err(user_error("No changes to move"));
|
||||
}
|
||||
let new_parent_tree = tx.repo().store().get_root_tree(&new_parent_tree_id)?;
|
||||
// Apply the reverse of the selected changes onto the source
|
||||
let new_source_tree = source_tree.merge(&new_parent_tree, &parent_tree)?;
|
||||
let abandon_source = new_source_tree.id() == parent_tree.id();
|
||||
if abandon_source {
|
||||
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 tx.repo().index().is_ancestor(source.id(), destination.id()) {
|
||||
// If we're moving changes to a descendant, first rebase descendants onto the
|
||||
// rewritten source. Otherwise it will likely already have the content
|
||||
// changes we're moving, so applying them will have no effect and the
|
||||
// changes will disappear.
|
||||
let rebase_map = tx.mut_repo().rebase_descendants_return_map(settings)?;
|
||||
let rebased_destination_id = rebase_map.get(destination.id()).unwrap().clone();
|
||||
destination = tx.mut_repo().store().get_commit(&rebased_destination_id)?;
|
||||
}
|
||||
// Apply the selected changes onto the destination
|
||||
let destination_tree = destination.tree()?;
|
||||
let new_destination_tree = destination_tree.merge(&parent_tree, &new_parent_tree)?;
|
||||
let description = combine_messages(
|
||||
tx.base_repo(),
|
||||
&source,
|
||||
&destination,
|
||||
settings,
|
||||
abandon_source,
|
||||
)?;
|
||||
tx.mut_repo()
|
||||
.rewrite_commit(settings, &destination)
|
||||
.set_tree_id(new_destination_tree.id().clone())
|
||||
.set_description(description)
|
||||
.write()?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue