Extended git diff stats for local workflows, exposed as the gdsx CLI.
gdsx preserves authoritative git totals and adds a categorized breakdown:
- implementation
- tests
- comments
- documentation
- configuration
It enforces strict reconciliation:
- implementation.insertions + tests.insertions + comments.insertions + documentation.insertions + configuration.insertions = total.insertions
- implementation.deletions + tests.deletions + comments.deletions + documentation.deletions + configuration.deletions = total.deletions
If reconciliation fails, gdsx prints diagnostics and exits non-zero.
git diff --shortstat gives trustworthy totals, but not the context needed to quickly understand where change effort went. gdsx keeps git as the source of truth while adding a practical implementation/test/comment breakdown that still reconciles exactly to global insertions and deletions.
- Uses git CLI as source of truth (
--raw -z,--shortstat, and patch hunks) - Handles add/modify/delete/rename/copy
- Safe path handling via NUL-delimited parsing and literal pathspecs
- Comment detection for JS/TS (via
@babel/parser) and 30+ other languages (regex-based) - Repeatable include/exclude glob filters
- Text table output with net column and git-style color defaults
- JSON mode for machine-readable integration
Each changed line is assigned to exactly one category. Classification is determined by file path, evaluated in priority order:
| Priority | Category | Matches |
|---|---|---|
| 1 | tests | Files inside test/, tests/, or __tests__/ directories, or filenames containing .test.* or .spec.* |
| 2 | documentation | .md, .txt, .rst, .adoc extensions, or bare filenames LICENSE, LICENCE, CHANGELOG, CHANGES, AUTHORS, CONTRIBUTORS, README |
| 3 | configuration | .json, .jsonc, .yaml, .yml, .toml, .ini, .env, .properties extensions; any dotfile (basename starting with .); or filenames matching *.config.* or *.rc.* |
| 4 | comments | Lines identified as comments in supported languages (see below) |
| 5 | implementation | Everything else (default) |
Earlier rules take precedence. A .test.js file is always tests, never
comments or implementation. Comment detection only applies to files
that are not already matched by a higher-priority rule.
| Parser | Extensions | Comment syntax |
|---|---|---|
| Babel | .js, .jsx, .ts, .tsx, .mjs, .cjs, .mts, .cts |
Full AST-based parsing |
| Generic | .c, .cpp, .h, .hpp, .cs, .go, .java, .rs, .swift, .kt, .scala, .groovy |
// line, /* */ block |
| Generic | .py, .sh, .bash, .rb, .pl, .r |
# line |
| Generic | .html, .htm, .xml, .svg, .vue |
<!-- --> block |
| Generic | .css, .scss, .less |
/* */ block |
| Generic | .sql, .lua, .hs |
-- line |
| Generic | .php |
// and # line, /* */ block |
npm install -g git-diff-stat-extendedFor development installation, see docs/development.md.
gdsx [options] [<git-diff-args>...]gdsx is a thin wrapper around git diff. Any arguments not consumed by
gdsx are forwarded directly to git diff, so commits, ranges, and
git-specific flags work exactly as you would expect.
Running bare gdsx with no arguments is equivalent to git diff HEAD, which
shows all uncommitted changes (staged and unstaged) compared to the last
commit.
| Flag | Type | Default | Description |
|---|---|---|---|
--include <glob> |
string | Include glob pattern (repeatable). For renames/copies, matches the new path | |
--exclude <glob> |
string | Exclude glob pattern (repeatable). For renames/copies, matches the new path | |
--json |
boolean | false |
Emit structured JSON output |
--show-reconciliation |
boolean | false |
Show the reconciliation line when it passes (always shown on fail) |
--group-by-extension |
boolean | false |
Group the category breakdown by file extension |
# All uncommitted changes vs last commit (default)
gdsx
# Last commit
gdsx HEAD~1..HEAD
# Compare branch tip against main
gdsx main..HEAD
# Symmetric range expression
gdsx main...HEAD
# Include only src and tests
gdsx --include 'src/**' --include 'tests/**' main..HEAD
# Exclude generated files
gdsx --exclude '**/*.snap' --exclude 'dist/**'
# JSON output
gdsx --json main..HEADPrints a category table with a header showing files changed and the comparison range:
┌──────────────────────────────────────────────────────┐
│ 38 files changed · c7729b0..HEAD │
├─────────────────┬────────────┬───────────┬───────────┤
│ Category │ Insertions │ Deletions │ Net │
├─────────────────┼────────────┼───────────┼───────────┤
│ implementation │ +1940 │ -771 │ +1169 │
├─────────────────┼────────────┼───────────┼───────────┤
│ tests │ +959 │ -201 │ +758 │
├─────────────────┼────────────┼───────────┼───────────┤
│ comments │ +406 │ -0 │ +406 │
├─────────────────┼────────────┼───────────┼───────────┤
│ documentation │ +0 │ -0 │ 0 │
├─────────────────┼────────────┼───────────┼───────────┤
│ configuration │ +0 │ -0 │ 0 │
├─────────────────┼────────────┼───────────┼───────────┤
│ total │ +3305 │ -972 │ +2333 │
└─────────────────┴────────────┴───────────┴───────────┘
When reconciliation fails, a FAIL line and diagnostics block are printed and the process exits non-zero. Use --show-reconciliation to also display the reconciliation line on pass.
Breaks down categories within each file extension group, sorted alphabetically:
┌───────────────────────────────────────────────────────┐
│ 38 files changed · c7729b0..HEAD │
├───────────────────┬────────────┬───────────┬──────────┤
│ Category │ Insertions │ Deletions │ Net │
├───────────────────┴────────────┴───────────┴──────────┤
│ .js (13 files) │
├───────────────────┬────────────┬───────────┬──────────┤
│ implementation │ +880 │ -525 │ +355 │
│ tests │ +959 │ -201 │ +758 │
│ comments │ +400 │ -0 │ +400 │
│ documentation │ +0 │ -0 │ 0 │
│ configuration │ +0 │ -0 │ 0 │
├───────────────────┴────────────┴───────────┴──────────┤
│ .json (7 files) │
├───────────────────┬────────────┬───────────┬──────────┤
│ implementation │ +0 │ -0 │ 0 │
│ tests │ +0 │ -0 │ 0 │
│ comments │ +0 │ -0 │ 0 │
│ documentation │ +0 │ -0 │ 0 │
│ configuration │ +125 │ -9 │ +116 │
├───────────────────┴────────────┴───────────┴──────────┤
│ .jsonc (2 files) │
├───────────────────┬────────────┬───────────┬──────────┤
│ implementation │ +0 │ -0 │ 0 │
│ tests │ +0 │ -0 │ 0 │
│ comments │ +0 │ -0 │ 0 │
│ documentation │ +0 │ -0 │ 0 │
│ configuration │ +8 │ -0 │ +8 │
├───────────────────┴────────────┴───────────┴──────────┤
│ .md (8 files) │
├───────────────────┬────────────┬───────────┬──────────┤
│ implementation │ +0 │ -0 │ 0 │
│ tests │ +0 │ -0 │ 0 │
│ comments │ +0 │ -0 │ 0 │
│ documentation │ +877 │ -10 │ +867 │
│ configuration │ +0 │ -0 │ 0 │
├───────────────────┴────────────┴───────────┴──────────┤
│ .mjs (1 file) │
├───────────────────┬────────────┬───────────┬──────────┤
│ implementation │ +25 │ -0 │ +25 │
│ tests │ +0 │ -0 │ 0 │
│ comments │ +6 │ -0 │ +6 │
│ documentation │ +0 │ -0 │ 0 │
│ configuration │ +0 │ -0 │ 0 │
├───────────────────┴────────────┴───────────┴──────────┤
│ (no extension) (7 files) │
├───────────────────┬────────────┬───────────┬──────────┤
│ implementation │ +25 │ -227 │ -202 │
│ tests │ +0 │ -0 │ 0 │
│ comments │ +0 │ -0 │ 0 │
│ documentation │ +0 │ -0 │ 0 │
│ configuration │ +0 │ -0 │ 0 │
├───────────────────┼────────────┼───────────┼──────────┤
│ total │ +3305 │ -972 │ +2333 │
└───────────────────┴────────────┴───────────┴──────────┘
JSON output includes:
shortstatLinetotalcategoriesreconciliationrangefiltersselectedFilesfileDetails— per-file category breakdowns
gdsx compares computed category sums to authoritative git totals.
When mismatch occurs:
- reconciliation status is
FAIL - diagnostics are printed
- process exit code is non-zero
This makes the tool safe for scripting and CI checks.
See docs/development.md for setup, testing, and release instructions.
- For unsupported file extensions, all non-test/doc/config lines are categorized as implementation
- The generic (non-JS/TS) comment parser uses regex-based scanning with basic string literal awareness; edge cases in complex string/template interpolation may cause misclassification
- Python docstrings (
"""..."""/'''...''') are string literals, not language-level comments, and are classified as implementation - Nested block comments (e.g. Haskell
{- {- -} -}) are not supported - For files with syntax parse failures, comment classification for that side falls back to implementation