cli: Add an option to diff to output only paths.

This commit is contained in:
Matt Kulukundis 2024-06-19 13:19:51 -04:00 committed by Matt Fowles Kulukundis
parent f8b87f6499
commit 33ab8d4371
4 changed files with 73 additions and 1 deletions

View file

@ -55,6 +55,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* New command `jj branch move` let you update branches by name pattern or source
revision.
* New diff option `jj diff --name-only` allows for easier shell scripting.
### Fixed bugs
## [0.18.0] - 2024-06-05

View file

@ -48,7 +48,7 @@ const DEFAULT_CONTEXT_LINES: usize = 3;
#[derive(clap::Args, Clone, Debug)]
#[command(next_help_heading = "Diff Formatting Options")]
#[command(group(clap::ArgGroup::new("short-format").args(&["summary", "stat", "types"])))]
#[command(group(clap::ArgGroup::new("short-format").args(&["summary", "stat", "types", "name_only"])))]
#[command(group(clap::ArgGroup::new("long-format").args(&["git", "color_words", "tool"])))]
pub struct DiffFormatArgs {
/// For each path, show only whether it was modified, added, or deleted
@ -66,6 +66,12 @@ pub struct DiffFormatArgs {
/// Git submodule.
#[arg(long)]
pub types: bool,
/// For each path, show only its path
///
/// Typically useful for shell commands like:
/// `jj diff -r @- --name_only | xargs perl -pi -e's/OLD/NEW/g`
#[arg(long)]
pub name_only: bool,
/// Show a Git-format diff
#[arg(long)]
pub git: bool,
@ -85,6 +91,7 @@ pub enum DiffFormat {
Summary,
Stat,
Types,
NameOnly,
Git { context: usize },
ColorWords { context: usize },
Tool(Box<ExternalMergeTool>),
@ -126,6 +133,7 @@ fn diff_formats_from_args(
let mut formats = [
(args.summary, DiffFormat::Summary),
(args.types, DiffFormat::Types),
(args.name_only, DiffFormat::NameOnly),
(
args.git,
DiffFormat::Git {
@ -176,6 +184,7 @@ fn default_diff_format(
match name.as_ref() {
"summary" => Ok(DiffFormat::Summary),
"types" => Ok(DiffFormat::Types),
"name-only" => Ok(DiffFormat::NameOnly),
"git" => Ok(DiffFormat::Git {
context: num_context_lines.unwrap_or(DEFAULT_CONTEXT_LINES),
}),
@ -251,6 +260,10 @@ impl<'a> DiffRenderer<'a> {
let tree_diff = from_tree.diff_stream(to_tree, matcher);
show_types(formatter, tree_diff, path_converter)?;
}
DiffFormat::NameOnly => {
let tree_diff = from_tree.diff_stream(to_tree, matcher);
show_names(formatter, tree_diff, path_converter)?;
}
DiffFormat::Git { context } => {
let tree_diff = from_tree.diff_stream(to_tree, matcher);
show_git_diff(repo, formatter, *context, tree_diff)?;
@ -1105,3 +1118,17 @@ fn diff_summary_char(value: &MergedTreeValue) -> char {
}
}
}
pub fn show_names(
formatter: &mut dyn Formatter,
mut tree_diff: TreeDiffStream,
path_converter: &RepoPathUiConverter,
) -> io::Result<()> {
async {
while let Some((repo_path, _)) = tree_diff.next().await {
writeln!(formatter, "{}", path_converter.format_file_path(&repo_path))?;
}
Ok(())
}
.block_on()
}

View file

@ -614,6 +614,9 @@ With the `--from` and/or `--to` options, shows the difference from/to the given
* `--types` — For each path, show only its type before and after
The diff is shown as two letters. The first letter indicates the type before and the second letter indicates the type after. '-' indicates that the path was not present, 'F' represents a regular file, `L' represents a symlink, 'C' represents a conflict, and 'G' represents a Git submodule.
* `--name-only` — For each path, show only its path
Typically useful for shell commands like: `jj diff -r @- --name_only | xargs perl -pi -e's/OLD/NEW/g`
* `--git` — Show a Git-format diff
* `--color-words` — Show a word-level diff with changes indicated only by color
* `--tool <TOOL>` — Generate diff by external command
@ -1038,6 +1041,9 @@ This excludes changes from other commits by temporarily rebasing `--from` onto `
* `--types` — For each path, show only its type before and after
The diff is shown as two letters. The first letter indicates the type before and the second letter indicates the type after. '-' indicates that the path was not present, 'F' represents a regular file, `L' represents a symlink, 'C' represents a conflict, and 'G' represents a Git submodule.
* `--name-only` — For each path, show only its path
Typically useful for shell commands like: `jj diff -r @- --name_only | xargs perl -pi -e's/OLD/NEW/g`
* `--git` — Show a Git-format diff
* `--color-words` — Show a word-level diff with changes indicated only by color
* `--tool <TOOL>` — Generate diff by external command
@ -1076,6 +1082,9 @@ Spans of revisions that are not included in the graph per `--revisions` are rend
* `--types` — For each path, show only its type before and after
The diff is shown as two letters. The first letter indicates the type before and the second letter indicates the type after. '-' indicates that the path was not present, 'F' represents a regular file, `L' represents a symlink, 'C' represents a conflict, and 'G' represents a Git submodule.
* `--name-only` — For each path, show only its path
Typically useful for shell commands like: `jj diff -r @- --name_only | xargs perl -pi -e's/OLD/NEW/g`
* `--git` — Show a Git-format diff
* `--color-words` — Show a word-level diff with changes indicated only by color
* `--tool <TOOL>` — Generate diff by external command
@ -1185,6 +1194,9 @@ Name is derived from Merciual's obsolescence markers.
* `--types` — For each path, show only its type before and after
The diff is shown as two letters. The first letter indicates the type before and the second letter indicates the type after. '-' indicates that the path was not present, 'F' represents a regular file, `L' represents a symlink, 'C' represents a conflict, and 'G' represents a Git submodule.
* `--name-only` — For each path, show only its path
Typically useful for shell commands like: `jj diff -r @- --name_only | xargs perl -pi -e's/OLD/NEW/g`
* `--git` — Show a Git-format diff
* `--color-words` — Show a word-level diff with changes indicated only by color
* `--tool <TOOL>` — Generate diff by external command
@ -1592,6 +1604,9 @@ Show commit description and changes in a revision
* `--types` — For each path, show only its type before and after
The diff is shown as two letters. The first letter indicates the type before and the second letter indicates the type after. '-' indicates that the path was not present, 'F' represents a regular file, `L' represents a symlink, 'C' represents a conflict, and 'G' represents a Git submodule.
* `--name-only` — For each path, show only its path
Typically useful for shell commands like: `jj diff -r @- --name_only | xargs perl -pi -e's/OLD/NEW/g`
* `--git` — Show a Git-format diff
* `--color-words` — Show a word-level diff with changes indicated only by color
* `--tool <TOOL>` — Generate diff by external command

View file

@ -290,6 +290,34 @@ fn test_diff_types() {
}
}
#[test]
fn test_diff_name_only() {
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");
test_env.jj_cmd_ok(&repo_path, &["new"]);
std::fs::write(repo_path.join("deleted"), "d").unwrap();
std::fs::write(repo_path.join("modified"), "m").unwrap();
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--name-only"]), @r###"
deleted
modified
"###);
test_env.jj_cmd_ok(&repo_path, &["commit", "-mfirst"]);
std::fs::remove_file(repo_path.join("deleted")).unwrap();
std::fs::write(repo_path.join("modified"), "mod").unwrap();
std::fs::write(repo_path.join("added"), "add").unwrap();
std::fs::create_dir(repo_path.join("sub")).unwrap();
std::fs::write(repo_path.join("sub/added"), "sub/add").unwrap();
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--name-only"]).replace('\\', "/"),
@r###"
added
deleted
modified
sub/added
"###);
}
#[test]
fn test_diff_bad_args() {
let test_env = TestEnvironment::default();