From 7135b2a89b77f38334dcabc1f5b44ec926c82d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20=C3=84lgmyr?= Date: Sat, 6 Jul 2024 11:37:44 +0200 Subject: [PATCH] Allow restricting diff/patch output to a specific revset. --- cli/src/commands/log.rs | 23 ++++++++++-- cli/tests/cli-reference@.md.snap | 3 ++ cli/tests/test_log_command.rs | 63 ++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/cli/src/commands/log.rs b/cli/src/commands/log.rs index 46fbcb1644..32280a8ab3 100644 --- a/cli/src/commands/log.rs +++ b/cli/src/commands/log.rs @@ -70,6 +70,11 @@ pub(crate) struct LogArgs { /// Show patch #[arg(long, short = 'p')] patch: bool, + /// Restrict diffs to the given revsets. + /// + /// Defaults to all(). + #[arg(long)] + diff_revisions: Vec, #[command(flatten)] diff_format: DiffFormatArgs, } @@ -102,6 +107,14 @@ pub(crate) fn cmd_log( } expression }; + let diff_revset_contains = { + let diff_revset_expression = if args.diff_revisions.is_empty() { + workspace_command.attach_revset_evaluator(RevsetExpression::all())? + } else { + workspace_command.parse_union_revsets(&args.diff_revisions)? + }; + diff_revset_expression.evaluate()?.containing_fn() + }; let repo = workspace_command.repo(); let matcher = fileset_expression.to_matcher(); @@ -202,8 +215,10 @@ pub(crate) fn cmd_log( buffer.push(b'\n'); } if let Some(renderer) = &diff_renderer { - let mut formatter = ui.new_formatter(&mut buffer); - renderer.show_patch(ui, formatter.as_mut(), &commit, matcher.as_ref())?; + if diff_revset_contains(commit.id()) { + let mut formatter = ui.new_formatter(&mut buffer); + renderer.show_patch(ui, formatter.as_mut(), &commit, matcher.as_ref())?; + } } let node_symbol = format_template(ui, &Some(commit), &node_template); @@ -243,7 +258,9 @@ pub(crate) fn cmd_log( with_content_format .write(formatter, |formatter| template.format(&commit, formatter))?; if let Some(renderer) = &diff_renderer { - renderer.show_patch(ui, formatter, &commit, matcher.as_ref())?; + if diff_revset_contains(commit.id()) { + renderer.show_patch(ui, formatter, &commit, matcher.as_ref())?; + } } } } diff --git a/cli/tests/cli-reference@.md.snap b/cli/tests/cli-reference@.md.snap index 66ab5779ae..9f96b7ad99 100644 --- a/cli/tests/cli-reference@.md.snap +++ b/cli/tests/cli-reference@.md.snap @@ -1099,6 +1099,9 @@ Spans of revisions that are not included in the graph per `--revisions` are rend For the syntax, see https://github.com/martinvonz/jj/blob/main/docs/templates.md * `-p`, `--patch` — Show patch +* `--diff-revisions ` — Restrict diffs to the given revsets. + + Defaults to all(). * `-s`, `--summary` — For each path, show only whether it was modified, added, or deleted * `--stat` — Show a histogram of the changes * `--types` — For each path, show only its type before and after diff --git a/cli/tests/test_log_command.rs b/cli/tests/test_log_command.rs index 0c4d47c0ce..785ad333a0 100644 --- a/cli/tests/test_log_command.rs +++ b/cli/tests/test_log_command.rs @@ -294,6 +294,69 @@ fn test_log_with_or_without_diff() { "###); } +#[test] +fn test_diff_revisions_restriction() { + let test_env = TestEnvironment::default(); + test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); + let repo_path = test_env.env_root().join("repo"); + + std::fs::write(repo_path.join("file1"), "foo\n").unwrap(); + test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "add a file"]); + test_env.jj_cmd_ok(&repo_path, &["new", "-m", "a new commit"]); + std::fs::write(repo_path.join("file1"), "foo\nbar\n").unwrap(); + + // diff-revisions doesn't affect output when summary or patch is not requested. + let stdout = test_env.jj_cmd_success( + &repo_path, + &["log", "-T", "description", "--diff-revisions=@"], + ); + insta::assert_snapshot!(stdout, @r###" + @ a new commit + ◉ add a file + ◉ + "###); + + // `-p` for default diff output, restrict to @ + let stdout = test_env.jj_cmd_success( + &repo_path, + &["log", "-T", "description", "-p", "--diff-revisions=@"], + ); + insta::assert_snapshot!(stdout, @r###" + @ a new commit + │ Modified regular file file1: + │ 1 1: foo, "--diff-revisions=@" + │ 2: bar + ◉ add a file + │ + ◉ + "###); + + // `-p` for default diff output, `-s` for summary, restrict to @ + let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", "description", "-p", "-s", "--diff-revisions=@"]); + insta::assert_snapshot!(stdout, @r###" + @ a new commit + │ M file1 + │ Modified regular file file1: + │ 1 1: foo + │ 2: bar + ◉ add a file + │ + ◉ + "###); + + // `-s` for summary, restrict to @- + let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", "description", "-p", "-s", "--diff-revisions=@-"]); + insta::assert_snapshot!(stdout, @r###" + @ a new commit + │ + ◉ add a file + │ A file1 + │ Added regular file file1: + │ 1: foo + ◉ + "###); +} + #[test] fn test_log_null_terminate_multiline_descriptions() { let test_env = TestEnvironment::default();