diff --git a/docs/git-comparison.md b/docs/git-comparison.md index 8fe563ebf..8f16cedf0 100644 --- a/docs/git-comparison.md +++ b/docs/git-comparison.md @@ -64,6 +64,11 @@ parent. jj diff -r <revision> git diff <revision>^ <revision> + + Show description and diff of a change + jj show <revision> + git show <revision> + Add a file to the current change touch filename diff --git a/src/commands.rs b/src/commands.rs index 533912e4b..410d84b56 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -814,6 +814,34 @@ With the `--from` and/or `--to` options, shows the difference from/to the given .help("Show changes to this revision"), ) .arg(paths_arg()); + let show_command = SubCommand::with_name("show") + .about("Show commit description and changes in a revision") + .long_about("Show commit description and changes in a revision") + .arg( + Arg::with_name("summary") + .long("summary") + .short("s") + .help("For each path, show only whether it was modified, added, or removed"), + ) + .arg( + Arg::with_name("git") + .long("git") + .conflicts_with("summary") + .help("Show a Git-format diff"), + ) + .arg( + Arg::with_name("color-words") + .long("color-words") + .conflicts_with("summary") + .conflicts_with("git") + .help("Show a word-level diff with changes indicated only by color"), + ) + .arg( + Arg::with_name("revision") + .index(1) + .default_value("@") + .help("Show changes changes in this revision, compared to its parent(s)"), + ); let status_command = SubCommand::with_name("status") .alias("st") .about("Show high-level repo status") @@ -1434,6 +1462,7 @@ It is possible to mutating commands when loading the repo at an earlier operatio untrack_command, files_command, diff_command, + show_command, status_command, log_command, obslog_command, @@ -1749,6 +1778,34 @@ fn cmd_diff(ui: &mut Ui, command: &CommandHelper, args: &ArgMatches) -> Result<( Ok(()) } +fn cmd_show(ui: &mut Ui, command: &CommandHelper, args: &ArgMatches) -> Result<(), CommandError> { + let mut workspace_command = command.workspace_helper(ui)?; + let commit = workspace_command.resolve_single_rev(ui, args.value_of("revision").unwrap())?; + let parents = commit.parents(); + let from_tree = merge_commit_trees(workspace_command.repo().as_repo_ref(), &parents); + let to_tree = commit.tree(); + let repo = workspace_command.repo(); + let diff_iterator = from_tree.diff(&to_tree, &EverythingMatcher); + let workspace_root = workspace_command.workspace_root(); + // TODO: Add branches, tags, etc + // TODO: Indent the description like Git does + let template_string = r#" + label(if(open, "open"), + "Commit ID: " commit_id "\n" + "Change ID: " change_id "\n" + "Author: " author " <" author.email() "> (" author.timestamp() ")\n" + "Committer: " committer " <" committer.email() "> (" committer.timestamp() ")\n" + "\n" + description + "\n" + )"#; + let template = + crate::template_parser::parse_commit_template(repo.as_repo_ref(), template_string); + template.format(&commit, ui.stdout_formatter().as_mut())?; + show_diff(ui, repo, workspace_root, args, diff_iterator)?; + Ok(()) +} + fn show_diff( ui: &mut Ui, repo: &Arc, @@ -1790,6 +1847,7 @@ fn show_diff( } Ok(()) } + fn diff_content( repo: &Arc, path: &RepoPath, @@ -4133,6 +4191,8 @@ where cmd_files(&mut ui, &command_helper, sub_args) } else if let Some(sub_args) = matches.subcommand_matches("diff") { cmd_diff(&mut ui, &command_helper, sub_args) + } else if let Some(sub_args) = matches.subcommand_matches("show") { + cmd_show(&mut ui, &command_helper, sub_args) } else if let Some(sub_args) = matches.subcommand_matches("status") { cmd_status(&mut ui, &command_helper, sub_args) } else if let Some(sub_args) = matches.subcommand_matches("log") {