Skip to content

line-log: support stat and check diff formats with -L#2152

Open
mmontalbo wants to merge 4 commits into
gitgitgadget:masterfrom
mmontalbo:mm/line-log-stat-formats-followup
Open

line-log: support stat and check diff formats with -L#2152
mmontalbo wants to merge 4 commits into
gitgitgadget:masterfrom
mmontalbo:mm/line-log-stat-formats-followup

Conversation

@mmontalbo

@mmontalbo mmontalbo commented Jun 15, 2026

Copy link
Copy Markdown

This series extends git log -L to support the diff stat formats and
--check, with all output scoped to the tracked line ranges.

It builds on top of the mm/line-log-cleanup topic [1], which integrated
-L with the standard log output pipeline and taught it the non-patch
formats --raw, --name-only, --name-status, and --summary.

With these patches the following formats also work with -L and report
range-scoped results:

  • --stat, --numstat, --shortstat: counts cover only the lines inside
    the tracked range, not the whole file.

  • --check: whitespace errors are reported only for added lines inside
    the tracked range, with the correct file line numbers.

--dirstat is deliberately rejected: a per-directory percentage is
degenerate for the handful of line ranges -L tracks (a single tracked
file is always 100% of its directory), and its default changed-bytes
mode is not range-scoped at all. --numstat already gives the exact
range-scoped per-file counts.

The first two patches are preparatory refactors of the line-range
filter in diff.c so it can be reused; the last two add the stat and
check support.

  • Patch 1: simplify the line-range filter by classifying removals as
    they arrive, dropping the pending_rm buffer and a latent
    flush_rhunk() bug that leaked deletions just past the range.
    Note that this patch was submitted by itself previously [2], but
    did not pick up traction so it is re-included with this series.

  • Patch 2: rename line_range_callback to line_range_filter, now that
    the struct is a general-purpose filter.

  • Patch 3: reuse the filter in builtin_diffstat() for the stat
    formats, extend the -L output-format allowlist, and reject --dirstat.

  • Patch 4: reuse the filter in builtin_checkdiff() and extend the
    allowlist for --check.

[1] https://lore.kernel.org/git/pull.2094.v3.git.1780001267.gitgitgadget@gmail.com/
[2] https://lore.kernel.org/git/pull.2099.git.1777230630020.gitgitgadget@gmail.com/

The line-range filter buffered '-' (removal) lines in a pending_rm
strbuf, deferring their classification until a '+' or ' ' line
arrived to reveal the post-image position.

This buffering is unnecessary.  Removal lines are pre-image content
that occupies no post-image space, so they do not advance lno_post.
Within a hunk, xdiff emits removals before additions for each
change, so a '-' line always arrives while lno_post is at the same
position that the following '+' or ' ' line will occupy.  Each
line can therefore be classified against the tracked ranges as it
arrives, without waiting for a non-removal line to confirm the
position.

The buffering also had a bug: flush_rhunk() unconditionally drained
the pending buffer when the range hunk was active, even if lno_post
had advanced past the tracked range.  This caused deletions
immediately after the tracked function to be incorrectly included
in patch output.

Remove the pending_rm buffer and classify '-' lines using the same
in_range check applied to '+' and ' ' lines.  This simplifies the
filter, removes three struct fields and a helper function, and
makes the flush_rhunk() bug impossible by construction.

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
The struct carries filter state through xdiff callbacks, tracking
post-image position and forwarding only in-range lines to the
output callback.  Rename to line_range_filter to reflect this
role, and update the comment to describe the struct as a generic
filter rather than a wrapper specific to fn_out_consume().

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
Reuse the line_range_filter in builtin_diffstat() to produce
range-scoped statistics.  When a filepair carries line_ranges,
the filter wraps diffstat_consume() as its output callback,
forwarding only in-range lines for counting.  flush_rhunk()
replays buffered content through diffstat_consume(), which
ignores synthetic @@ headers since it only counts '+' and '-'
lines.

To avoid duplicating the filter setup and teardown that
builtin_diff() already has, extract line_range_filter_init(),
line_range_filter_flush(), and line_range_filter_release()
and use them in both call sites.

Expand the output format allowlist in setup_revisions() to
accept --stat, --numstat, and --shortstat with -L.

Reject --dirstat explicitly.  It summarizes change as a
per-directory percentage, which is degenerate for the usual
single tracked file (always 100% of its directory) and, in its
default changed-bytes mode, would measure whole-file damage that
ignores the tracked range entirely.  --numstat already reports
the exact range-scoped per-file counts, so -L gains nothing from
--dirstat.  Give it its own message rather than the generic "does
not yet support" wording, since this is a deliberate exclusion
rather than a missing feature.

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
builtin_checkdiff() runs its own xdiff pass to detect whitespace
errors in newly added lines.  When -L is active, the check should
be scoped to the tracked line ranges rather than the whole file.

Reuse the line_range_filter to wrap checkdiff_consume(), the same
pattern already used for patch output and diffstat.  The filter
forwards only in-range lines for whitespace checking.

checkdiff reports the file line number of each error, which it
normally learns from the hunk header via checkdiff_consume_hunk().
The filter synthesizes its own hunk headers, so give it an optional
hunk callback and route checkdiff_consume_hunk() through it; this
sets the post-image position before the in-range lines are
replayed.  Without it the reported line numbers would count from
the start of the range hunk rather than the start of the file.

Add DIFF_FORMAT_CHECKDIFF to the -L output format allowlist in
setup_revisions() so that -L --check is accepted, and list --check
among the supported formats in the documentation.  Add tests
covering that whitespace errors are reported, scoped to the tracked
range, and labeled with the correct file line number.

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant