diff --git a/cli/src/cli_util.rs b/cli/src/cli_util.rs index 62b23d86fc..924413d189 100644 --- a/cli/src/cli_util.rs +++ b/cli/src/cli_util.rs @@ -1722,6 +1722,32 @@ Discard the conflicting changes with `jj restore --from {}`.", Ok(()) } +/// Prints warning about explicit paths that don't match any of the tree +/// entries. +pub fn print_unmatched_explicit_paths<'a>( + ui: &Ui, + workspace_command: &WorkspaceCommandHelper, + expression: &FilesetExpression, + trees: impl IntoIterator, +) -> io::Result<()> { + let mut explicit_paths = expression.explicit_paths().collect_vec(); + for tree in trees { + explicit_paths.retain(|&path| tree.path_value(path).is_absent()); + if explicit_paths.is_empty() { + return Ok(()); + } + } + let ui_paths = explicit_paths + .iter() + .map(|&path| workspace_command.format_file_path(path)) + .join(", "); + writeln!( + ui.warning_default(), + "No matching entries for paths: {ui_paths}" + )?; + Ok(()) +} + pub fn print_trackable_remote_branches(ui: &Ui, view: &View) -> io::Result<()> { let remote_branch_names = view .branches() diff --git a/cli/src/commands/diff.rs b/cli/src/commands/diff.rs index 99ae066139..6a44f67b61 100644 --- a/cli/src/commands/diff.rs +++ b/cli/src/commands/diff.rs @@ -15,7 +15,7 @@ use jj_lib::rewrite::merge_commit_trees; use tracing::instrument; -use crate::cli_util::{CommandHelper, RevisionArg}; +use crate::cli_util::{print_unmatched_explicit_paths, CommandHelper, RevisionArg}; use crate::command_error::CommandError; use crate::diff_util::{diff_formats_for, show_diff, DiffFormatArgs}; use crate::ui::Ui; @@ -76,9 +76,8 @@ pub(crate) fn cmd_diff( from_tree = merge_commit_trees(workspace_command.repo().as_ref(), &parents)?; to_tree = commit.tree()? } - let matcher = workspace_command - .parse_file_patterns(&args.paths)? - .to_matcher(); + let fileset_expression = workspace_command.parse_file_patterns(&args.paths)?; + let matcher = fileset_expression.to_matcher(); let diff_formats = diff_formats_for(command.settings(), &args.format)?; ui.request_pager(); show_diff( @@ -90,5 +89,11 @@ pub(crate) fn cmd_diff( matcher.as_ref(), &diff_formats, )?; + print_unmatched_explicit_paths( + ui, + &workspace_command, + &fileset_expression, + [&from_tree, &to_tree], + )?; Ok(()) } diff --git a/cli/tests/test_diff_command.rs b/cli/tests/test_diff_command.rs index dac18276a3..e0a74b7bb0 100644 --- a/cli/tests/test_diff_command.rs +++ b/cli/tests/test_diff_command.rs @@ -149,6 +149,33 @@ fn test_diff_basic() { file3 | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) "###); + + // Unmatched paths should generate warnings + let (stdout, stderr) = test_env.jj_cmd_ok( + test_env.env_root(), + &[ + "diff", + "-Rrepo", + "-s", + "repo", // matches directory + "repo/file1", // deleted in to_tree, but exists in from_tree + "repo/x", + "repo/y/z", + ], + ); + insta::assert_snapshot!(stdout.replace('\\', "/"), @r###" + D repo/file1 + M repo/file2 + A repo/file3 + "###); + insta::assert_snapshot!(stderr.replace('\\', "/"), @r###" + Warning: No matching entries for paths: repo/x, repo/y/z + "###); + + // Unmodified paths shouldn't generate warnings + let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["diff", "-s", "--from=@", "file2"]); + insta::assert_snapshot!(stdout, @""); + insta::assert_snapshot!(stderr, @""); } #[test]