Skip to content

Commit

Permalink
Implement --drop-message for jj squash
Browse files Browse the repository at this point in the history
If `-d/--drop-message` is passed to `jj squash`, the descriptions of the
commits being squashed are dropped and the message of the destination commit is
used.
  • Loading branch information
emesterhazy committed Apr 2, 2024
1 parent e5b9e8f commit 5a9bacd
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 8 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
It can thereby be for all use cases where `jj move` can be used. The `--from`
argument accepts a revset that resolves to more than one revision.

* `jj squash` now accepts a `--drop-message/-d` option that discards the
descriptions of the commits being squashed.

* Commit templates now support `immutable` keyword.

* New template function `coalesce(content, ..)` is added.
Expand Down
4 changes: 2 additions & 2 deletions cli/src/commands/move.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use clap::ArgGroup;
use jj_lib::object_id::ObjectId;
use tracing::instrument;

use super::squash::move_diff;
use super::squash::{move_diff, SquashedDescription};
use crate::cli_util::{CommandHelper, RevisionArg};
use crate::command_error::{user_error, CommandError};
use crate::ui::Ui;
Expand Down Expand Up @@ -93,7 +93,7 @@ pub(crate) fn cmd_move(
&destination,
matcher.as_ref(),
&diff_selector,
None,
SquashedDescription::Combine,
false,
&args.paths,
)?;
Expand Down
40 changes: 34 additions & 6 deletions cli/src/commands/squash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ pub(crate) struct SquashArgs {
/// The description to use for squashed revision (don't open editor)
#[arg(long = "message", short, value_name = "MESSAGE")]
message_paragraphs: Vec<String>,
/// Discard the descriptions of the squashed revisions.
#[arg(long, short)]
drop_message: bool,
/// Interactively choose which parts to squash
#[arg(long, short)]
interactive: bool,
Expand Down Expand Up @@ -112,8 +115,6 @@ pub(crate) fn cmd_squash(
workspace_command.diff_selector(ui, args.tool.as_deref(), args.interactive)?;
let mut tx = workspace_command.start_transaction();
let tx_description = format!("squash commits into {}", destination.id().hex());
let description = (!args.message_paragraphs.is_empty())
.then(|| join_message_paragraphs(&args.message_paragraphs));
move_diff(
ui,
&mut tx,
Expand All @@ -122,14 +123,38 @@ pub(crate) fn cmd_squash(
&destination,
matcher.as_ref(),
&diff_selector,
description,
SquashedDescription::from_args(args),
args.revision.is_none() && args.from.is_none() && args.into.is_none(),
&args.paths,
)?;
tx.finish(ui, tx_description)?;
Ok(())
}

// TODO(#2882): Remove public visibility once `jj move` is deleted.
pub(crate) enum SquashedDescription {
// Use this exact description.
Exact(String),
// Use the destination's description and discard the descriptions of the
// source revisions.
UseDestination,
// Combine the descriptions of the source and destination revisions.
Combine,
}

// TODO(#2882): Remove public visibility once `jj move` is deleted.
impl SquashedDescription {
pub(crate) fn from_args(args: &SquashArgs) -> Self {
if !args.message_paragraphs.is_empty() {
SquashedDescription::Exact(join_message_paragraphs(&args.message_paragraphs))
} else if args.drop_message {
SquashedDescription::UseDestination
} else {
SquashedDescription::Combine
}
}
}

#[allow(clippy::too_many_arguments)]
pub fn move_diff(
ui: &mut Ui,
Expand All @@ -139,7 +164,7 @@ pub fn move_diff(
destination: &Commit,
matcher: &dyn Matcher,
diff_selector: &DiffSelector,
description: Option<String>,
description: SquashedDescription,
no_rev_arg: bool,
path_arg: &[String],
) -> Result<(), CommandError> {
Expand Down Expand Up @@ -229,8 +254,11 @@ from the source will be moved into the destination.
destination_tree = destination_tree.merge(&tree1, &tree2)?;
}
let description = match description {
Some(description) => description,
None => combine_messages(tx.base_repo(), &abandoned_commits, destination, settings)?,
SquashedDescription::Exact(description) => description,
SquashedDescription::UseDestination => destination.description().to_owned(),
SquashedDescription::Combine => {
combine_messages(tx.base_repo(), &abandoned_commits, destination, settings)?
}
};
let mut predecessors = vec![destination.id().clone()];
predecessors.extend(sources.iter().map(|source| source.id().clone()));
Expand Down
4 changes: 4 additions & 0 deletions cli/tests/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -1723,6 +1723,10 @@ If a working-copy commit gets abandoned, it will be given a new, empty commit. T
* `--from <FROM>` — Revision to squash from (default: @)
* `--into <INTO>` — Revision to squash into (default: @)
* `-m`, `--message <MESSAGE>` — The description to use for squashed revision (don't open editor)
* `-d`, `--discard-message` — Discard the descriptions of the squashed revisions
Possible values: `true`, `false`
* `-i`, `--interactive` — Interactively choose which parts to squash
Possible values: `true`, `false`
Expand Down
44 changes: 44 additions & 0 deletions cli/tests/test_squash_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -968,9 +968,53 @@ fn test_squash_empty() {
"###);
}

#[test]
fn test_squash_drop_messages() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");

test_env.jj_cmd_ok(&repo_path, &["commit", "-m=a"]);
test_env.jj_cmd_ok(&repo_path, &["commit", "-m=b"]);
test_env.jj_cmd_ok(&repo_path, &["describe", "-m=c"]);
// Test the setup
insta::assert_snapshot!(get_log_output_with_description(&test_env, &repo_path), @r###"
@ 71f7c810d8ed c
◉ 10dd87c3b4e2 b
◉ 4c5b3042d9e0 a
◉ 000000000000
"###);

// Squash the current revision using the short name for the option.
test_env.jj_cmd_ok(&repo_path, &["squash", "-d"]);
insta::assert_snapshot!(get_log_output_with_description(&test_env, &repo_path), @r###"
@ 10e30ce4a910
◉ 1c21278b775f b
◉ 4c5b3042d9e0 a
◉ 000000000000
"###);

// Undo and squash again, but this time squash both "b" and "c" into "a".
test_env.jj_cmd_ok(&repo_path, &["undo"]);
test_env.jj_cmd_ok(
&repo_path,
&["squash", "-d", "--from", "10d::", "--into", "4c5"],
);
insta::assert_snapshot!(get_log_output_with_description(&test_env, &repo_path), @r###"
@ da1507508bdf
◉ f1387f804776 a
◉ 000000000000
"###);
}

fn get_description(test_env: &TestEnvironment, repo_path: &Path, rev: &str) -> String {
test_env.jj_cmd_success(
repo_path,
&["log", "--no-graph", "-T", "description", "-r", rev],
)
}

fn get_log_output_with_description(test_env: &TestEnvironment, repo_path: &Path) -> String {
let template = r#"separate(" ", commit_id.short(), description)"#;
test_env.jj_cmd_success(repo_path, &["log", "-T", template])
}

0 comments on commit 5a9bacd

Please sign in to comment.