diff --git a/packages/git/src/format.js b/packages/git/src/format.js index b01c5bd11b..da3d320af8 100644 --- a/packages/git/src/format.js +++ b/packages/git/src/format.js @@ -268,7 +268,7 @@ export const diff_formatting_options = { * @param options Parsed command-line options. * @returns {{raw: boolean, numstat: boolean, summary: boolean, patch: boolean, context_lines: number, no_patch: boolean, source_prefix: string, dest_prefix: string }} */ -export const process_diff_formatting_options = (options) => { +export const process_diff_formatting_options = (options, { show_patch_by_default = true } = {}) => { const result = { raw: false, numstat: false, @@ -280,6 +280,10 @@ export const process_diff_formatting_options = (options) => { dest_prefix: 'b/', }; + result.display_diff = () => { + return !result.no_patch && (result.raw || result.numstat || result.summary || result.patch); + }; + if (options['raw']) result.raw = true; if (options['numstat']) @@ -312,7 +316,7 @@ export const process_diff_formatting_options = (options) => { } // If nothing is specified, default to --patch - if (!result.raw && !result.numstat && !result.summary && !result.patch) + if (show_patch_by_default && !result.raw && !result.numstat && !result.summary && !result.patch) result.patch = true; // --no-patch overrides the others diff --git a/packages/git/src/subcommands/log.js b/packages/git/src/subcommands/log.js index 6f14fa1976..470f8d8dcb 100644 --- a/packages/git/src/subcommands/log.js +++ b/packages/git/src/subcommands/log.js @@ -16,10 +16,18 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import git from 'isomorphic-git'; +import git, { TREE } from 'isomorphic-git'; import { find_repo_root, group_positional_arguments } from '../git-helpers.js'; -import { commit_formatting_options, format_commit, process_commit_formatting_options } from '../format.js'; +import { + commit_formatting_options, + diff_formatting_options, + format_commit, format_diffs, + process_commit_formatting_options, + process_diff_formatting_options, +} from '../format.js'; +import path from 'path-browserify'; import { SHOW_USAGE } from '../help.js'; +import { diff_git_trees } from '../diff.js'; export default { name: 'log', @@ -30,6 +38,7 @@ export default { tokens: true, options: { ...commit_formatting_options, + ...diff_formatting_options, 'max-count': { description: 'Maximum number of commits to output.', type: 'string', @@ -41,8 +50,10 @@ export default { const { io, fs, env, args } = ctx; const { stdout, stderr } = io; const { options, positionals, tokens } = args; + const cache = {}; process_commit_formatting_options(options); + const diff_options = process_diff_formatting_options(options, { show_patch_by_default: false }); const depth = Number(options['max-count']) || undefined; @@ -62,9 +73,27 @@ export default { ref: refs[0], filepath: paths[0], }); + const diff_ctx = { + fs, dir, gitdir, cache, env, + context_lines: diff_options.context_lines, + path_filters: paths.map(it => path.resolve(env.PWD, it)), + }; + const read_tree = walker => walker?.content()?.then(it => new TextDecoder().decode(it)); for (const commit of log) { stdout(format_commit(commit.commit, commit.oid, options)); + if (diff_options.display_diff()) { + const diffs = await diff_git_trees({ + ...diff_ctx, + // NOTE: Using an empty string for a non-existent parent prevents the default value 'HEAD' getting used. + // TREE() then fails to resolve that ref, and defaults to the empty commit, which is what we want. + a_tree: TREE({ ref: commit.commit.parent[0] ?? '' }), + b_tree: TREE({ ref: commit.oid }), + read_a: read_tree, + read_b: read_tree, + }); + stdout(format_diffs(diffs, diff_options)); + } } } } diff --git a/packages/git/src/subcommands/show.js b/packages/git/src/subcommands/show.js index d705905468..b14c538894 100644 --- a/packages/git/src/subcommands/show.js +++ b/packages/git/src/subcommands/show.js @@ -16,9 +16,18 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import git from 'isomorphic-git'; +import git, { TREE } from 'isomorphic-git'; import { find_repo_root } from '../git-helpers.js'; -import { commit_formatting_options, process_commit_formatting_options, format_commit, format_tag, format_tree } from '../format.js'; +import { + commit_formatting_options, + diff_formatting_options, + format_commit, format_diffs, + format_tag, + format_tree, + process_commit_formatting_options, + process_diff_formatting_options, +} from '../format.js'; +import { diff_git_trees } from '../diff.js'; export default { name: 'show', @@ -28,6 +37,7 @@ export default { allowPositionals: true, options: { ...commit_formatting_options, + ...diff_formatting_options, }, }, execute: async (ctx) => { @@ -36,19 +46,41 @@ export default { const { options, positionals } = args; process_commit_formatting_options(options); + const diff_options = process_diff_formatting_options(options); const { dir, gitdir } = await find_repo_root(fs, env.PWD); const objects = [...positionals]; const cache = {}; + const diff_ctx = { + fs, dir, gitdir, cache, env, + context_lines: diff_options.context_lines, + path_filters: [], + }; - const format_object = async (parsed_object, options) => { + const read_tree = walker => walker?.content()?.then(it => new TextDecoder().decode(it)); + + const format_object = async (parsed_object) => { switch (parsed_object.type) { case 'blob': return parsed_object.object; - case 'commit': - return format_commit(parsed_object.object, parsed_object.oid, options); + case 'commit': { + let s = format_commit(parsed_object.object, parsed_object.oid, options); + if (diff_options.display_diff()) { + const diffs = await diff_git_trees({ + ...diff_ctx, + // NOTE: Using an empty string for a non-existent parent prevents the default value 'HEAD' getting used. + // TREE() then fails to resolve that ref, and defaults to the empty commit, which is what we want. + a_tree: TREE({ ref: parsed_object.object.parent[0] ?? '' }), + b_tree: TREE({ ref: parsed_object.oid }), + read_a: read_tree, + read_b: read_tree, + }); + s += format_diffs(diffs, diff_options); + } + return s; + } case 'tree': return format_tree(parsed_object.oid, parsed_object.object, options); case 'tag': { @@ -64,7 +96,7 @@ export default { format: 'parsed', cache, }); - s += await format_object(target, options); + s += await format_object(target); return s; } } @@ -90,7 +122,7 @@ export default { }); // Then, print it out - stdout(await format_object(parsed_object, options)); + stdout(await format_object(parsed_object)); } } }