Fix #19: support --summary in show, log and diff
Fixes #19
Summary
git show, git log and git diff now accept --summary. Before this change all three rejected it with Unknown option "--summary". The summary lists the files a change created, deleted, renamed or changed mode on, which is often all an agent needs from a commit.
Supported surface:
git show --summary [--stat | --shortstat | --numstat | -p] [<object>]
git log --summary [--stat | --shortstat | --numstat | -p] [--oneline | --format=<fmt>] [--graph] ...
git diff --summary [--stat | --shortstat | --numstat] [--cached] [<commit> [<commit>]]
The lines match git 2.34.1 byte for byte:
create mode 100644 n
delete mode 100755 m
mode change 100644 => 100755 n
mode change 100755 => 120000 n (type change)
create mode 120000 link
rename z => z2 (100%)
rename dir/sub/{a => b} (100%)
rename big => big2 (70%)
mode change 100644 => 100755 (rename that also changed the mode)
create mode 100644 "q\"uote"
create mode 100644 "\303\251.txt"
Ordering follows git:
--summaryon its own replaces the patch.- After
--stat,--shortstator--numstatit prints right after their output. - With
-pit prints before the patch, with a blank line between them. --name-onlyand--name-statusdrop it, and so doesshow --no-patch.logprints nothing for merges, since it doesn't diff them by default.- A commit with changes but no summary lines, such as a content-only edit, still gets the blank line after its message. That is why
git log --summaryshows two blank lines after such a commit in medium format.
Before and after
$ git show --summary HEAD
# before (1.9.1): Unknown option "--summary". rc=1
# after:
commit e91cbdcf157f110f5a97fdc92e2c9b0a1c21fab9
Author: a <a@b>
Date: ...
sum
delete mode 100755 m
create mode 100644 n
rename z => z2 (100%)
How it works
formatSummaryLines in src/lib/commit-summary.ts is the only formatter for these lines. commit, merge, show, log and diff all call it. computeDiffStats used to build the create/delete lines for commit and merge as a side output. It now returns only the file stats, and the summary lines come from the new function.
Sharing the formatter changes the output of commit and merge in three cases, and in each case the new output is what git prints:
- A mode change used to print as
create mode 100755 nplusdelete mode 100644 n. It now printsmode change 100644 => 100755 n. - A rename that also changed the mode now prints the pathless
mode changeline under the rename. - Paths that need it are C-quoted the way git's
quote_c_stylequotes them. If either side of a rename needs quoting, both sides print in full ("a" => "b") without the{a => b}form, as git'spprint_renamedoes.
In show and log the diff options now resolve to a main format plus a summary flag, and withSummary puts the two in git's order. log's formatCommitDiff returns null when it shows nothing at all (no diff option, a merge, an empty diff) and "" when the commit has changes but the output is empty. The difference is the blank line described above. diff maps its items to the same inputs and appends the summary.
The PR has two more commits, split out so they are easy to review or drop:
log --graph --format=<fmt>blank line. With--graphand a custom format, the diff output came right under the formatted line. Git puts a padded blank line there, the same as without--graph. Only--onelineskips it. This showed up as soon as I comparedlog --graph --format=%s --summarywith git, and--stathad the same bug.showon a merge. Git shows a merge's patch as a combined diff, but--stat,--shortstat,--numstatand--summarycompare the merge with its first parent. just-git printed nothing for those formats on a merge, with a comment saying that matched git. It doesn't in 2.34.1, soshow --summary <merge>would have printed nothing where git lists the merged-in files. Both now use the first parent. The name formats still print nothing on a merge.
Tests
- In-memory tests with exact stdout, stderr and exit code.
test/commands/show.test.tshas 11 new tests: summary alone, after--stat/--shortstat/--numstat, before-p, symlinks and quoted names,dir/sub/{a => b}, a type change, the blank line on a content-only commit, dropped by the name formats and--no-patch, through an annotated tag, and merges against the first parent.log.test.tshas 6,diff.test.tshas 6 (two commits,--cached, unstaged deletions, stat formats) andcommit.test.tshas 1 for the mode-change lines. They share a history builder,setupSummaryHistoryintest/util.ts. test/interop/summary.test.tsbuilds a repo with real git, including an executable delete, a 70% rename that also gets+x, a symlink, a gitlink, a type change, names with a space, a quote, a tab andé, and a merge on its own branch. It runs 39 invocations ofshow,loganddiffthrough both and asserts identical stdout, stderr and exit code. I checked that it catches defects. Turning off path quoting failed 9 cases, and dropping the pathless mode line under renames failed 14.test/graph/scenarios/16-graph-with-summary.tscompareslog --graph --summarywith real git in medium,--oneline,--formatand--statforms. Scenario 09 gets two--graph --formatcases for the blank-line fix.- Every new test failed before its change.
bun test: 3576 pass, 29 skip, 0 fail. Onorigin/main(b509001) it was 3512 pass, 29 skip, 0 fail, with local git 2.34.1.bun checkis clean, andbun gen-docsupdateddocs/CLI.mdanddocs/FILE_REFERENCE.md.
Not included
These are gaps I hit while comparing with git. None of them come from --summary, and --stat or --name-status already show them on main:
git diff <commit>(commit against worktree) andgit diff HEADdon't run rename detection, so a staged rename shows as a delete plus a create.--name-statusdoes the same today.git diffandgit diff --cacheddon't see mode-only changes in the worktree or index. #15 fixes that indiff.ts, and the summary lines will show them once it lands.-qwith--summaryprints the summary, the same way just-git already handles-q --stat. Git 2.34.1 prints nothing for both. I left this alone because just-git's-qhandling follows newer git.--stat,--numstatand-pfail on a commit that adds or removes a gitlink, because they try to read the submodule commit as a blob.--summaryalone works (create mode 160000 gm).- The
-ppart ofshow -p --summary/log -p --summaryinherits the existing patch gaps: noold mode/new modelines, and combined diffs drop the hunk for a file both parents lack. The summary part matches. show --name-statuson a merge prints nothing where git prints combined status (MM f).--compact-summaryisn't supported, andshow -p --statstill prints only the stat.