Repository files navigation

gitmetry

git + telemetry. Your own developer-efficiency report, built from git history — on your machine, for your eyes.

CILicense: MITPython 3.9+

gitmetry turns your git history into a private performance review you run on yourself — 11 dimensions mapped to the DORA, SPACE and CodeScene frameworks, then narrated by an LLM into a readable report with 🟢/🟡/🔴 verdicts and trends.

No cloud. No account. No dashboard for your manager. It's read-only over git (git archive / git show) — it never touches your working tree, and your data never leaves your laptop. The whole generator is a single zero-dependency stdlib Python file.

Think of it as Git Wrapped for your engineering habits, but with a method behind it: instead of vanity stats, you get throughput, rework rate, function complexity, defect hotspots, change coupling, work rhythm and bus-factor — the things that actually tell you whether the code you write lasts.

Why gitmetry?

Almost every tool in this space — LinearB, Swarmia, Haystack, Code Climate Velocity, Waydev — is a team dashboard for managers: cloud-hosted, paid, and pointed at developers. gitmetry is the opposite.

Team analytics SaaSgitmetry
Audiencemanagers, leadsyou, about your own work
Where data livestheir cloudyour machine, read-only over git
Cost / setuppaid, integrationsone Python file, git only
Metricsoften vanity KPIsDORA / SPACE / CodeScene-backed
Outputlive dashboardsan LLM-narrated report you keep

Good for: a personal retro, prep for a 1:1 or performance review, sanity-checking your own habits, or just curiosity about how you actually work.

What you get

A two-phase workflow:

  1. gitmetry scans your local repo(s) and emits raw data — markdown tables and/or JSON.
  2. An LLM (or you) turns that into a readable, interpreted report with flags and trends. See examples/sample-report.md for the target — here's a taste:
## 🟢 Summary
Stable volume, small batches and declining rework — a healthy profile.
Watch one knowledge concentration.
| Dimension | Verdict | Trend ||-------------------------------|------------------|------------------------|| First-pass quality (rework) | 🟢 better | 31 % → 24 % || Defect/complexity hotspots | 🟡 one dominant | Controller/Order.php || Ownership / bus factor | 🟡 concentration | 41 solo files |

⚠️ Metrics are proxies, not truth. Most trustworthy: commit throughput, rework %, function CCN, ownership. Indicative only (skewed by generated code / commit discipline): raw line sums. gitmetry leans on trends, not absolute numbers.

Quick start

The generator is a single stdlib Python 3 script — no install required:

git clone https://github.com/vzoha/gitmetry
cd gitmetry
./gitmetry.py # last 24 months of the repo in the CWD, markdown to stdout

Or install it as a gitmetry command with pipx:

pipx install git+https://github.com/vzoha/gitmetry
gitmetry --version

Then hand the output to your LLM of choice (Claude Code, etc.) with the prompt "interpret this gitmetry raw data into a report" — the conventions live in CLAUDE.md and the structure in the section below.

Usage

# last 24 months of the repo in the current directory, markdown to stdout
gitmetry
# explicit window + save both md and json
gitmetry --since 2021-06 --until 2026-06 --format both --out report.md
# a JS/TS codebase for the deep-analysis layers
gitmetry --main-ext ts --paths src
# + slow code-health trend (scc snapshots, runs for minutes)
gitmetry --since 2021-06 --health-trend --format both --out report.md

By default gitmetry analyzes the git repo in the current directory. Point --root at a parent folder to analyze several repos at once (throughput / rework / sustainability are cross-project; the deep layers run on one --main-repo).

Key options

OptionDefaultDescription
--root.folder holding the repos (*/.git); may itself be a repo
--main-repothe only repo foundrepo (under --root) for deep analysis (layers 5,6,7,8,9,11)
--authorgit config user.nameregex for git --author (case-insensitive)
--main-extphpprimary language extension for the deep layers (php, js, ts, py, go, rb…)
--since / --untillast 24 monthsYYYY-MM or YYYY-MM-DD
--paths.paths within the main repo passed to lizard/scc
--formatmdmd | json | both
--outstdoutoutput file (both.md + .json)
--health-trendoffscc complexity snapshots over time (slow)
--quarterlyoffalso emit a per-quarter overview table (on top of yearly)
--rework-days14rework window: churn on code anyone touched within N days
--off-hours8-19working hours START-END; commits outside count as off-hours
--big-batch400churn (add+del) above which a commit counts toward big %
--coupling-min-shared5min co-changes for a file pair to show in change coupling
--include-docsoffalso count non-code files in line metrics
--no-excludeoffdon't exclude test/generated code

The script has no config files and no hardcoded paths beyond the option defaults. Copy it anywhere and point the options at your repos.

Note: the deep-analysis layers (5 defect hotspots, 6 functional changes, 7 complexity hotspots, 8 change coupling, 9 code-health) operate on a single primary language selected via --main-ext (default php). The cross-project / language-agnostic layers are throughput, rework, test co-change, corrective, sustainability and ownership.

Personal config

So you don't retype --author / --root / --main-repo / --main-ext every run (and never commit them to a shared repo), put your defaults in a JSON file:

cp .gitmetry.example.json .gitmetry.json # then edit it
{ "author": "you", "root": "~/code", "main_repo": "my-app", "main_ext": "ts", "paths": ["src"] }

The tunable thresholds (rework_days, off_hours, big_batch, coupling_min_shared) can live here too. gitmetry loads the first file it finds — $GITMETRY_CONFIG, then ./.gitmetry.json, then $XDG_CONFIG_HOME/gitmetry/config.json — and uses it as defaults; any flag you pass on the command line still overrides it. .gitmetry.json and CLAUDE.local.md are gitignored, so your settings stay local.

Don't commit your generated reports — they contain your real author name and private file paths. Keep them outside the repo (e.g. ~/reports/) or in a local ./reports/ folder, which is already gitignored (along with gitmetry-*.md / gitmetry-*.json). Using gitmetry on a private fork? Drop those lines from .gitignore to version your reports.

Dependencies

Only git is required. The two analysis tools below are optional — if a tool is missing, gitmetry just skips its layer and the rest of the report still runs, so you can start with nothing extra installed.

ToolPowersRequired?
giteverythingyes
lizardlayer 2 — function CCNoptional
scclayers 6 & 10 — complexity hotspots & code-health trendoptional
tar--health-trend only (usually preinstalled)optional

Install lizard (Python, cross-platform):

pipx install lizard # or: pip install --user lizard
pip install -e ".[analysis]"# already covered by the project's "analysis" extra

Install scc (a Go binary — pick one):

brew install scc # macOS / Linux (Homebrew)
go install github.com/boyter/scc/v3@latest # any Go toolchain → ~/go/bin
scoop install scc # Windows (Scoop)

Or grab a prebuilt binary from the scc releases and put it on your PATH. gitmetry also looks in ~/bin/scc, so this works too:

mkdir -p ~/bin && mv scc ~/bin/ && chmod +x ~/bin/scc

How the raw data becomes a report

Don't copy the raw tables wholesale — distill a story from them. Target structure (see examples/sample-report.md):

  1. Header — author, window, repo count, main repo, commit count; a line on the standards; a warning that metrics are proxies, not truth (most trustworthy: throughput, rework %, CCN, ownership; indicative only: line sums, corr %).
  2. 🟢/🟡/🔴 Summary — one headline sentence, then a Dimension | Verdict | Trend table flagging each of the 11 dimensions, then 2–3 sentences on what to watch.
  3. Yearly overview — distil the tool's pre-aggregated rollup (window totals + per-year, optionally per-quarter) rather than re-deriving it: commits, median batch, big %, rework %, corr %, hotfixes, reverts, avg CCN, Δcx, severe fns, off-hours %, weekend %, active days, test co-change %. Partial years are pre-marked with *.
  4. Per dimension (1–11) — each gets a short Legend: + Assessment: with a flag and concrete files/numbers.
  5. Footer — note that it was generated from gitmetry (read-only over git) + where the raw data lives.

Flags: 🟢 healthy/improving · 🟡 watch · 🔴 problem. Be concrete (file names, numbers, "X → Y" trends). Trend > absolute number.

The 11 dimensions (what each measures)

Grouped into four themes — Activity (1) · First-pass quality (2–5) · Code structure (6–9) · People (10–11):

Activity

  1. Throughput — commits/month cross-project + batch-size distribution (med/p90 churn, big %) and commits per active day. SPACE Activity.

First-pass quality

  1. Rework rate — churn on code anyone touched within --rework-days (default 14). CodeScene / MS relative churn.
  2. Test co-change — of your commits touching production code, the share that also touch a test file — a message-independent first-pass-quality habit.
  3. Corrective vs value-add — Feature/Refactoring vs Fix vs Hotfix, with reverts surfaced separately (subset of Fix); hotfix = DORA Change-Failure proxy.
  4. Defect hotspots — files in your Fix/Hotfix commits × complexity.

Code structure / complexity

  1. Functional changes — CCN of the functions you actually touched plus Δcx, the net function-complexity your commits add vs remove (file totals after − before parent; negative = you simplified). lizard, main repo.
  2. Complexity hotspots — change frequency × complexity (score = touches × cx). CodeScene.
  3. Change coupling — files changed together in one commit (temporal coupling).
  4. Code-health trend — complexity/kLOC over time via git-archive snapshots (--health-trend).

Sustainability & people

  1. Sustainability — when you commit (off-hours/weekend rhythm; off-hours window via --off-hours). SPACE well-being.
  2. Ownership / bus factor — authorship share per file across full history, both churn-weighted and recency-weighted (1y half-life), plus who touched it last (solo ≥80 % = risk).

On top of the per-dimension monthly tables, gitmetry emits pre-aggregated overviews — window totals plus a per-year table (--quarterly adds a per-quarter one) — so yearly figures and YoY deltas come straight from raw counts, not from re-averaging the rounded monthly rows.

⚠️ Line metrics (added/deleted) are skewed by generated code (AI tests, docs, lock files). Most trustworthy signals: commit throughput, rework rate, function CCN, ownership.

Commit-type classification

Corrective/value-add (layer 4) and defect hotspots (layer 5) classify commits by their subject prefix: Feature/Refactoring/feat/refactor/perf → value, Fix/revert → fix, Hotfix → hotfix, Chore/Docs/test/build/ci/style → other. Reverts (git's auto-generated Revert "…" or a revert: prefix) stay in the fix bucket but are also counted separately, so the report can flag undo churn on its own. Conventional-Commits scope and the breaking marker are stripped first (feat(api)!:feat), so both the golemos convention and full Conventional Commits classify correctly. Any unknown prefix (or a subject with no Type: prefix) falls to other. If your repo uses a different convention, those two layers will under-count; the other eight don't depend on commit messages.

Development

pip install -e ".[dev]"# pytest + ruff
ruff check .# lint
pytest # run the unit tests (tests/)

The tests cover the pure, git-free helpers (commit-type classification, multi-language test-file detection, percentile math, path filtering, date arithmetic) plus an integration suite that builds a throwaway repo. CI runs ruff + pytest on Python 3.9 / 3.11 / 3.12 — see .github/workflows/ci.yml.

License

MIT © 2026 Vojtěch Žoha

About

Your private developer-efficiency report from git history — 11 dimensions (DORA / SPACE / CodeScene), local & read-only, narrated by an LLM.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

gitmetry

git + telemetry. Your own developer-efficiency report, built from git history — on your machine, for your eyes.

CILicense: MITPython 3.9+

gitmetry turns your git history into a private performance review you run on yourself — 11 dimensions mapped to the DORA, SPACE and CodeScene frameworks, then narrated by an LLM into a readable report with 🟢/🟡/🔴 verdicts and trends.

No cloud. No account. No dashboard for your manager. It's read-only over git (git archive / git show) — it never touches your working tree, and your data never leaves your laptop. The whole generator is a single zero-dependency stdlib Python file.

Think of it as Git Wrapped for your engineering habits, but with a method behind it: instead of vanity stats, you get throughput, rework rate, function complexity, defect hotspots, change coupling, work rhythm and bus-factor — the things that actually tell you whether the code you write lasts.

Why gitmetry?

Almost every tool in this space — LinearB, Swarmia, Haystack, Code Climate Velocity, Waydev — is a team dashboard for managers: cloud-hosted, paid, and pointed at developers. gitmetry is the opposite.

Team analytics SaaSgitmetry
Audiencemanagers, leadsyou, about your own work
Where data livestheir cloudyour machine, read-only over git
Cost / setuppaid, integrationsone Python file, git only
Metricsoften vanity KPIsDORA / SPACE / CodeScene-backed
Outputlive dashboardsan LLM-narrated report you keep

Good for: a personal retro, prep for a 1:1 or performance review, sanity-checking your own habits, or just curiosity about how you actually work.

What you get

A two-phase workflow:

  1. gitmetry scans your local repo(s) and emits raw data — markdown tables and/or JSON.
  2. An LLM (or you) turns that into a readable, interpreted report with flags and trends. See examples/sample-report.md for the target — here's a taste:
## 🟢 Summary
Stable volume, small batches and declining rework — a healthy profile.
Watch one knowledge concentration.
| Dimension | Verdict | Trend ||-------------------------------|------------------|------------------------|| First-pass quality (rework) | 🟢 better | 31 % → 24 % || Defect/complexity hotspots | 🟡 one dominant | Controller/Order.php || Ownership / bus factor | 🟡 concentration | 41 solo files |

⚠️ Metrics are proxies, not truth. Most trustworthy: commit throughput, rework %, function CCN, ownership. Indicative only (skewed by generated code / commit discipline): raw line sums. gitmetry leans on trends, not absolute numbers.

Quick start

The generator is a single stdlib Python 3 script — no install required:

git clone https://github.com/vzoha/gitmetry
cd gitmetry
./gitmetry.py # last 24 months of the repo in the CWD, markdown to stdout

Or install it as a gitmetry command with pipx:

pipx install git+https://github.com/vzoha/gitmetry
gitmetry --version

Then hand the output to your LLM of choice (Claude Code, etc.) with the prompt "interpret this gitmetry raw data into a report" — the conventions live in CLAUDE.md and the structure in the section below.

Usage

# last 24 months of the repo in the current directory, markdown to stdout
gitmetry
# explicit window + save both md and json
gitmetry --since 2021-06 --until 2026-06 --format both --out report.md
# a JS/TS codebase for the deep-analysis layers
gitmetry --main-ext ts --paths src
# + slow code-health trend (scc snapshots, runs for minutes)
gitmetry --since 2021-06 --health-trend --format both --out report.md

By default gitmetry analyzes the git repo in the current directory. Point --root at a parent folder to analyze several repos at once (throughput / rework / sustainability are cross-project; the deep layers run on one --main-repo).

Key options

OptionDefaultDescription
--root.folder holding the repos (*/.git); may itself be a repo
--main-repothe only repo foundrepo (under --root) for deep analysis (layers 5,6,7,8,9,11)
--authorgit config user.nameregex for git --author (case-insensitive)
--main-extphpprimary language extension for the deep layers (php, js, ts, py, go, rb…)
--since / --untillast 24 monthsYYYY-MM or YYYY-MM-DD
--paths.paths within the main repo passed to lizard/scc
--formatmdmd | json | both
--outstdoutoutput file (both.md + .json)
--health-trendoffscc complexity snapshots over time (slow)
--quarterlyoffalso emit a per-quarter overview table (on top of yearly)
--rework-days14rework window: churn on code anyone touched within N days
--off-hours8-19working hours START-END; commits outside count as off-hours
--big-batch400churn (add+del) above which a commit counts toward big %
--coupling-min-shared5min co-changes for a file pair to show in change coupling
--include-docsoffalso count non-code files in line metrics
--no-excludeoffdon't exclude test/generated code

The script has no config files and no hardcoded paths beyond the option defaults. Copy it anywhere and point the options at your repos.

Note: the deep-analysis layers (5 defect hotspots, 6 functional changes, 7 complexity hotspots, 8 change coupling, 9 code-health) operate on a single primary language selected via --main-ext (default php). The cross-project / language-agnostic layers are throughput, rework, test co-change, corrective, sustainability and ownership.

Personal config

So you don't retype --author / --root / --main-repo / --main-ext every run (and never commit them to a shared repo), put your defaults in a JSON file:

cp .gitmetry.example.json .gitmetry.json # then edit it
{ "author": "you", "root": "~/code", "main_repo": "my-app", "main_ext": "ts", "paths": ["src"] }

The tunable thresholds (rework_days, off_hours, big_batch, coupling_min_shared) can live here too. gitmetry loads the first file it finds — $GITMETRY_CONFIG, then ./.gitmetry.json, then $XDG_CONFIG_HOME/gitmetry/config.json — and uses it as defaults; any flag you pass on the command line still overrides it. .gitmetry.json and CLAUDE.local.md are gitignored, so your settings stay local.

Don't commit your generated reports — they contain your real author name and private file paths. Keep them outside the repo (e.g. ~/reports/) or in a local ./reports/ folder, which is already gitignored (along with gitmetry-*.md / gitmetry-*.json). Using gitmetry on a private fork? Drop those lines from .gitignore to version your reports.

Dependencies

Only git is required. The two analysis tools below are optional — if a tool is missing, gitmetry just skips its layer and the rest of the report still runs, so you can start with nothing extra installed.

ToolPowersRequired?
giteverythingyes
lizardlayer 2 — function CCNoptional
scclayers 6 & 10 — complexity hotspots & code-health trendoptional
tar--health-trend only (usually preinstalled)optional

Install lizard (Python, cross-platform):

pipx install lizard # or: pip install --user lizard
pip install -e ".[analysis]"# already covered by the project's "analysis" extra

Install scc (a Go binary — pick one):

brew install scc # macOS / Linux (Homebrew)
go install github.com/boyter/scc/v3@latest # any Go toolchain → ~/go/bin
scoop install scc # Windows (Scoop)

Or grab a prebuilt binary from the scc releases and put it on your PATH. gitmetry also looks in ~/bin/scc, so this works too:

mkdir -p ~/bin && mv scc ~/bin/ && chmod +x ~/bin/scc

How the raw data becomes a report

Don't copy the raw tables wholesale — distill a story from them. Target structure (see examples/sample-report.md):

  1. Header — author, window, repo count, main repo, commit count; a line on the standards; a warning that metrics are proxies, not truth (most trustworthy: throughput, rework %, CCN, ownership; indicative only: line sums, corr %).
  2. 🟢/🟡/🔴 Summary — one headline sentence, then a Dimension | Verdict | Trend table flagging each of the 11 dimensions, then 2–3 sentences on what to watch.
  3. Yearly overview — distil the tool's pre-aggregated rollup (window totals + per-year, optionally per-quarter) rather than re-deriving it: commits, median batch, big %, rework %, corr %, hotfixes, reverts, avg CCN, Δcx, severe fns, off-hours %, weekend %, active days, test co-change %. Partial years are pre-marked with *.
  4. Per dimension (1–11) — each gets a short Legend: + Assessment: with a flag and concrete files/numbers.
  5. Footer — note that it was generated from gitmetry (read-only over git) + where the raw data lives.

Flags: 🟢 healthy/improving · 🟡 watch · 🔴 problem. Be concrete (file names, numbers, "X → Y" trends). Trend > absolute number.

The 11 dimensions (what each measures)

Grouped into four themes — Activity (1) · First-pass quality (2–5) · Code structure (6–9) · People (10–11):

Activity

  1. Throughput — commits/month cross-project + batch-size distribution (med/p90 churn, big %) and commits per active day. SPACE Activity.

First-pass quality

  1. Rework rate — churn on code anyone touched within --rework-days (default 14). CodeScene / MS relative churn.
  2. Test co-change — of your commits touching production code, the share that also touch a test file — a message-independent first-pass-quality habit.
  3. Corrective vs value-add — Feature/Refactoring vs Fix vs Hotfix, with reverts surfaced separately (subset of Fix); hotfix = DORA Change-Failure proxy.
  4. Defect hotspots — files in your Fix/Hotfix commits × complexity.

Code structure / complexity

  1. Functional changes — CCN of the functions you actually touched plus Δcx, the net function-complexity your commits add vs remove (file totals after − before parent; negative = you simplified). lizard, main repo.
  2. Complexity hotspots — change frequency × complexity (score = touches × cx). CodeScene.
  3. Change coupling — files changed together in one commit (temporal coupling).
  4. Code-health trend — complexity/kLOC over time via git-archive snapshots (--health-trend).

Sustainability & people

  1. Sustainability — when you commit (off-hours/weekend rhythm; off-hours window via --off-hours). SPACE well-being.
  2. Ownership / bus factor — authorship share per file across full history, both churn-weighted and recency-weighted (1y half-life), plus who touched it last (solo ≥80 % = risk).

On top of the per-dimension monthly tables, gitmetry emits pre-aggregated overviews — window totals plus a per-year table (--quarterly adds a per-quarter one) — so yearly figures and YoY deltas come straight from raw counts, not from re-averaging the rounded monthly rows.

⚠️ Line metrics (added/deleted) are skewed by generated code (AI tests, docs, lock files). Most trustworthy signals: commit throughput, rework rate, function CCN, ownership.

Commit-type classification

Corrective/value-add (layer 4) and defect hotspots (layer 5) classify commits by their subject prefix: Feature/Refactoring/feat/refactor/perf → value, Fix/revert → fix, Hotfix → hotfix, Chore/Docs/test/build/ci/style → other. Reverts (git's auto-generated Revert "…" or a revert: prefix) stay in the fix bucket but are also counted separately, so the report can flag undo churn on its own. Conventional-Commits scope and the breaking marker are stripped first (feat(api)!:feat), so both the golemos convention and full Conventional Commits classify correctly. Any unknown prefix (or a subject with no Type: prefix) falls to other. If your repo uses a different convention, those two layers will under-count; the other eight don't depend on commit messages.

Development

pip install -e ".[dev]"# pytest + ruff
ruff check .# lint
pytest # run the unit tests (tests/)

The tests cover the pure, git-free helpers (commit-type classification, multi-language test-file detection, percentile math, path filtering, date arithmetic) plus an integration suite that builds a throwaway repo. CI runs ruff + pytest on Python 3.9 / 3.11 / 3.12 — see .github/workflows/ci.yml.

License

MIT © 2026 Vojtěch Žoha

About

Your private developer-efficiency report from git history — 11 dimensions (DORA / SPACE / CodeScene), local & read-only, narrated by an LLM.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

gitmetry

git + telemetry. Your own developer-efficiency report, built from git history — on your machine, for your eyes.

CILicense: MITPython 3.9+

gitmetry turns your git history into a private performance review you run on yourself — 11 dimensions mapped to the DORA, SPACE and CodeScene frameworks, then narrated by an LLM into a readable report with 🟢/🟡/🔴 verdicts and trends.

No cloud. No account. No dashboard for your manager. It's read-only over git (git archive / git show) — it never touches your working tree, and your data never leaves your laptop. The whole generator is a single zero-dependency stdlib Python file.

Think of it as Git Wrapped for your engineering habits, but with a method behind it: instead of vanity stats, you get throughput, rework rate, function complexity, defect hotspots, change coupling, work rhythm and bus-factor — the things that actually tell you whether the code you write lasts.

Why gitmetry?

Almost every tool in this space — LinearB, Swarmia, Haystack, Code Climate Velocity, Waydev — is a team dashboard for managers: cloud-hosted, paid, and pointed at developers. gitmetry is the opposite.

Team analytics SaaSgitmetry
Audiencemanagers, leadsyou, about your own work
Where data livestheir cloudyour machine, read-only over git
Cost / setuppaid, integrationsone Python file, git only
Metricsoften vanity KPIsDORA / SPACE / CodeScene-backed
Outputlive dashboardsan LLM-narrated report you keep

Good for: a personal retro, prep for a 1:1 or performance review, sanity-checking your own habits, or just curiosity about how you actually work.

What you get

A two-phase workflow:

  1. gitmetry scans your local repo(s) and emits raw data — markdown tables and/or JSON.
  2. An LLM (or you) turns that into a readable, interpreted report with flags and trends. See examples/sample-report.md for the target — here's a taste:
## 🟢 Summary
Stable volume, small batches and declining rework — a healthy profile.
Watch one knowledge concentration.
| Dimension | Verdict | Trend ||-------------------------------|------------------|------------------------|| First-pass quality (rework) | 🟢 better | 31 % → 24 % || Defect/complexity hotspots | 🟡 one dominant | Controller/Order.php || Ownership / bus factor | 🟡 concentration | 41 solo files |

⚠️ Metrics are proxies, not truth. Most trustworthy: commit throughput, rework %, function CCN, ownership. Indicative only (skewed by generated code / commit discipline): raw line sums. gitmetry leans on trends, not absolute numbers.

Quick start

The generator is a single stdlib Python 3 script — no install required:

git clone https://github.com/vzoha/gitmetry
cd gitmetry
./gitmetry.py # last 24 months of the repo in the CWD, markdown to stdout

Or install it as a gitmetry command with pipx:

pipx install git+https://github.com/vzoha/gitmetry
gitmetry --version

Then hand the output to your LLM of choice (Claude Code, etc.) with the prompt "interpret this gitmetry raw data into a report" — the conventions live in CLAUDE.md and the structure in the section below.

Usage

# last 24 months of the repo in the current directory, markdown to stdout
gitmetry
# explicit window + save both md and json
gitmetry --since 2021-06 --until 2026-06 --format both --out report.md
# a JS/TS codebase for the deep-analysis layers
gitmetry --main-ext ts --paths src
# + slow code-health trend (scc snapshots, runs for minutes)
gitmetry --since 2021-06 --health-trend --format both --out report.md

By default gitmetry analyzes the git repo in the current directory. Point --root at a parent folder to analyze several repos at once (throughput / rework / sustainability are cross-project; the deep layers run on one --main-repo).

Key options

OptionDefaultDescription
--root.folder holding the repos (*/.git); may itself be a repo
--main-repothe only repo foundrepo (under --root) for deep analysis (layers 5,6,7,8,9,11)
--authorgit config user.nameregex for git --author (case-insensitive)
--main-extphpprimary language extension for the deep layers (php, js, ts, py, go, rb…)
--since / --untillast 24 monthsYYYY-MM or YYYY-MM-DD
--paths.paths within the main repo passed to lizard/scc
--formatmdmd | json | both
--outstdoutoutput file (both.md + .json)
--health-trendoffscc complexity snapshots over time (slow)
--quarterlyoffalso emit a per-quarter overview table (on top of yearly)
--rework-days14rework window: churn on code anyone touched within N days
--off-hours8-19working hours START-END; commits outside count as off-hours
--big-batch400churn (add+del) above which a commit counts toward big %
--coupling-min-shared5min co-changes for a file pair to show in change coupling
--include-docsoffalso count non-code files in line metrics
--no-excludeoffdon't exclude test/generated code

The script has no config files and no hardcoded paths beyond the option defaults. Copy it anywhere and point the options at your repos.

Note: the deep-analysis layers (5 defect hotspots, 6 functional changes, 7 complexity hotspots, 8 change coupling, 9 code-health) operate on a single primary language selected via --main-ext (default php). The cross-project / language-agnostic layers are throughput, rework, test co-change, corrective, sustainability and ownership.

Personal config

So you don't retype --author / --root / --main-repo / --main-ext every run (and never commit them to a shared repo), put your defaults in a JSON file:

cp .gitmetry.example.json .gitmetry.json # then edit it
{ "author": "you", "root": "~/code", "main_repo": "my-app", "main_ext": "ts", "paths": ["src"] }

The tunable thresholds (rework_days, off_hours, big_batch, coupling_min_shared) can live here too. gitmetry loads the first file it finds — $GITMETRY_CONFIG, then ./.gitmetry.json, then $XDG_CONFIG_HOME/gitmetry/config.json — and uses it as defaults; any flag you pass on the command line still overrides it. .gitmetry.json and CLAUDE.local.md are gitignored, so your settings stay local.

Don't commit your generated reports — they contain your real author name and private file paths. Keep them outside the repo (e.g. ~/reports/) or in a local ./reports/ folder, which is already gitignored (along with gitmetry-*.md / gitmetry-*.json). Using gitmetry on a private fork? Drop those lines from .gitignore to version your reports.

Dependencies

Only git is required. The two analysis tools below are optional — if a tool is missing, gitmetry just skips its layer and the rest of the report still runs, so you can start with nothing extra installed.

ToolPowersRequired?
giteverythingyes
lizardlayer 2 — function CCNoptional
scclayers 6 & 10 — complexity hotspots & code-health trendoptional
tar--health-trend only (usually preinstalled)optional

Install lizard (Python, cross-platform):

pipx install lizard # or: pip install --user lizard
pip install -e ".[analysis]"# already covered by the project's "analysis" extra

Install scc (a Go binary — pick one):

brew install scc # macOS / Linux (Homebrew)
go install github.com/boyter/scc/v3@latest # any Go toolchain → ~/go/bin
scoop install scc # Windows (Scoop)

Or grab a prebuilt binary from the scc releases and put it on your PATH. gitmetry also looks in ~/bin/scc, so this works too:

mkdir -p ~/bin && mv scc ~/bin/ && chmod +x ~/bin/scc

How the raw data becomes a report

Don't copy the raw tables wholesale — distill a story from them. Target structure (see examples/sample-report.md):

  1. Header — author, window, repo count, main repo, commit count; a line on the standards; a warning that metrics are proxies, not truth (most trustworthy: throughput, rework %, CCN, ownership; indicative only: line sums, corr %).
  2. 🟢/🟡/🔴 Summary — one headline sentence, then a Dimension | Verdict | Trend table flagging each of the 11 dimensions, then 2–3 sentences on what to watch.
  3. Yearly overview — distil the tool's pre-aggregated rollup (window totals + per-year, optionally per-quarter) rather than re-deriving it: commits, median batch, big %, rework %, corr %, hotfixes, reverts, avg CCN, Δcx, severe fns, off-hours %, weekend %, active days, test co-change %. Partial years are pre-marked with *.
  4. Per dimension (1–11) — each gets a short Legend: + Assessment: with a flag and concrete files/numbers.
  5. Footer — note that it was generated from gitmetry (read-only over git) + where the raw data lives.

Flags: 🟢 healthy/improving · 🟡 watch · 🔴 problem. Be concrete (file names, numbers, "X → Y" trends). Trend > absolute number.

The 11 dimensions (what each measures)

Grouped into four themes — Activity (1) · First-pass quality (2–5) · Code structure (6–9) · People (10–11):

Activity

  1. Throughput — commits/month cross-project + batch-size distribution (med/p90 churn, big %) and commits per active day. SPACE Activity.

First-pass quality

  1. Rework rate — churn on code anyone touched within --rework-days (default 14). CodeScene / MS relative churn.
  2. Test co-change — of your commits touching production code, the share that also touch a test file — a message-independent first-pass-quality habit.
  3. Corrective vs value-add — Feature/Refactoring vs Fix vs Hotfix, with reverts surfaced separately (subset of Fix); hotfix = DORA Change-Failure proxy.
  4. Defect hotspots — files in your Fix/Hotfix commits × complexity.

Code structure / complexity

  1. Functional changes — CCN of the functions you actually touched plus Δcx, the net function-complexity your commits add vs remove (file totals after − before parent; negative = you simplified). lizard, main repo.
  2. Complexity hotspots — change frequency × complexity (score = touches × cx). CodeScene.
  3. Change coupling — files changed together in one commit (temporal coupling).
  4. Code-health trend — complexity/kLOC over time via git-archive snapshots (--health-trend).

Sustainability & people

  1. Sustainability — when you commit (off-hours/weekend rhythm; off-hours window via --off-hours). SPACE well-being.
  2. Ownership / bus factor — authorship share per file across full history, both churn-weighted and recency-weighted (1y half-life), plus who touched it last (solo ≥80 % = risk).

On top of the per-dimension monthly tables, gitmetry emits pre-aggregated overviews — window totals plus a per-year table (--quarterly adds a per-quarter one) — so yearly figures and YoY deltas come straight from raw counts, not from re-averaging the rounded monthly rows.

⚠️ Line metrics (added/deleted) are skewed by generated code (AI tests, docs, lock files). Most trustworthy signals: commit throughput, rework rate, function CCN, ownership.

Commit-type classification

Corrective/value-add (layer 4) and defect hotspots (layer 5) classify commits by their subject prefix: Feature/Refactoring/feat/refactor/perf → value, Fix/revert → fix, Hotfix → hotfix, Chore/Docs/test/build/ci/style → other. Reverts (git's auto-generated Revert "…" or a revert: prefix) stay in the fix bucket but are also counted separately, so the report can flag undo churn on its own. Conventional-Commits scope and the breaking marker are stripped first (feat(api)!:feat), so both the golemos convention and full Conventional Commits classify correctly. Any unknown prefix (or a subject with no Type: prefix) falls to other. If your repo uses a different convention, those two layers will under-count; the other eight don't depend on commit messages.

Development

pip install -e ".[dev]"# pytest + ruff
ruff check .# lint
pytest # run the unit tests (tests/)

The tests cover the pure, git-free helpers (commit-type classification, multi-language test-file detection, percentile math, path filtering, date arithmetic) plus an integration suite that builds a throwaway repo. CI runs ruff + pytest on Python 3.9 / 3.11 / 3.12 — see .github/workflows/ci.yml.

License

MIT © 2026 Vojtěch Žoha

About

Your private developer-efficiency report from git history — 11 dimensions (DORA / SPACE / CodeScene), local & read-only, narrated by an LLM.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

gitmetry

git + telemetry. Your own developer-efficiency report, built from git history — on your machine, for your eyes.

CILicense: MITPython 3.9+

gitmetry turns your git history into a private performance review you run on yourself — 11 dimensions mapped to the DORA, SPACE and CodeScene frameworks, then narrated by an LLM into a readable report with 🟢/🟡/🔴 verdicts and trends.

No cloud. No account. No dashboard for your manager. It's read-only over git (git archive / git show) — it never touches your working tree, and your data never leaves your laptop. The whole generator is a single zero-dependency stdlib Python file.

Think of it as Git Wrapped for your engineering habits, but with a method behind it: instead of vanity stats, you get throughput, rework rate, function complexity, defect hotspots, change coupling, work rhythm and bus-factor — the things that actually tell you whether the code you write lasts.

Why gitmetry?

Almost every tool in this space — LinearB, Swarmia, Haystack, Code Climate Velocity, Waydev — is a team dashboard for managers: cloud-hosted, paid, and pointed at developers. gitmetry is the opposite.

Team analytics SaaSgitmetry
Audiencemanagers, leadsyou, about your own work
Where data livestheir cloudyour machine, read-only over git
Cost / setuppaid, integrationsone Python file, git only
Metricsoften vanity KPIsDORA / SPACE / CodeScene-backed
Outputlive dashboardsan LLM-narrated report you keep

Good for: a personal retro, prep for a 1:1 or performance review, sanity-checking your own habits, or just curiosity about how you actually work.

What you get

A two-phase workflow:

  1. gitmetry scans your local repo(s) and emits raw data — markdown tables and/or JSON.
  2. An LLM (or you) turns that into a readable, interpreted report with flags and trends. See examples/sample-report.md for the target — here's a taste:
## 🟢 Summary
Stable volume, small batches and declining rework — a healthy profile.
Watch one knowledge concentration.
| Dimension | Verdict | Trend ||-------------------------------|------------------|------------------------|| First-pass quality (rework) | 🟢 better | 31 % → 24 % || Defect/complexity hotspots | 🟡 one dominant | Controller/Order.php || Ownership / bus factor | 🟡 concentration | 41 solo files |

⚠️ Metrics are proxies, not truth. Most trustworthy: commit throughput, rework %, function CCN, ownership. Indicative only (skewed by generated code / commit discipline): raw line sums. gitmetry leans on trends, not absolute numbers.

Quick start

The generator is a single stdlib Python 3 script — no install required:

git clone https://github.com/vzoha/gitmetry
cd gitmetry
./gitmetry.py # last 24 months of the repo in the CWD, markdown to stdout

Or install it as a gitmetry command with pipx:

pipx install git+https://github.com/vzoha/gitmetry
gitmetry --version

Then hand the output to your LLM of choice (Claude Code, etc.) with the prompt "interpret this gitmetry raw data into a report" — the conventions live in CLAUDE.md and the structure in the section below.

Usage

# last 24 months of the repo in the current directory, markdown to stdout
gitmetry
# explicit window + save both md and json
gitmetry --since 2021-06 --until 2026-06 --format both --out report.md
# a JS/TS codebase for the deep-analysis layers
gitmetry --main-ext ts --paths src
# + slow code-health trend (scc snapshots, runs for minutes)
gitmetry --since 2021-06 --health-trend --format both --out report.md

By default gitmetry analyzes the git repo in the current directory. Point --root at a parent folder to analyze several repos at once (throughput / rework / sustainability are cross-project; the deep layers run on one --main-repo).

Key options

OptionDefaultDescription
--root.folder holding the repos (*/.git); may itself be a repo
--main-repothe only repo foundrepo (under --root) for deep analysis (layers 5,6,7,8,9,11)
--authorgit config user.nameregex for git --author (case-insensitive)
--main-extphpprimary language extension for the deep layers (php, js, ts, py, go, rb…)
--since / --untillast 24 monthsYYYY-MM or YYYY-MM-DD
--paths.paths within the main repo passed to lizard/scc
--formatmdmd | json | both
--outstdoutoutput file (both.md + .json)
--health-trendoffscc complexity snapshots over time (slow)
--quarterlyoffalso emit a per-quarter overview table (on top of yearly)
--rework-days14rework window: churn on code anyone touched within N days
--off-hours8-19working hours START-END; commits outside count as off-hours
--big-batch400churn (add+del) above which a commit counts toward big %
--coupling-min-shared5min co-changes for a file pair to show in change coupling
--include-docsoffalso count non-code files in line metrics
--no-excludeoffdon't exclude test/generated code

The script has no config files and no hardcoded paths beyond the option defaults. Copy it anywhere and point the options at your repos.

Note: the deep-analysis layers (5 defect hotspots, 6 functional changes, 7 complexity hotspots, 8 change coupling, 9 code-health) operate on a single primary language selected via --main-ext (default php). The cross-project / language-agnostic layers are throughput, rework, test co-change, corrective, sustainability and ownership.

Personal config

So you don't retype --author / --root / --main-repo / --main-ext every run (and never commit them to a shared repo), put your defaults in a JSON file:

cp .gitmetry.example.json .gitmetry.json # then edit it
{ "author": "you", "root": "~/code", "main_repo": "my-app", "main_ext": "ts", "paths": ["src"] }

The tunable thresholds (rework_days, off_hours, big_batch, coupling_min_shared) can live here too. gitmetry loads the first file it finds — $GITMETRY_CONFIG, then ./.gitmetry.json, then $XDG_CONFIG_HOME/gitmetry/config.json — and uses it as defaults; any flag you pass on the command line still overrides it. .gitmetry.json and CLAUDE.local.md are gitignored, so your settings stay local.

Don't commit your generated reports — they contain your real author name and private file paths. Keep them outside the repo (e.g. ~/reports/) or in a local ./reports/ folder, which is already gitignored (along with gitmetry-*.md / gitmetry-*.json). Using gitmetry on a private fork? Drop those lines from .gitignore to version your reports.

Dependencies

Only git is required. The two analysis tools below are optional — if a tool is missing, gitmetry just skips its layer and the rest of the report still runs, so you can start with nothing extra installed.

ToolPowersRequired?
giteverythingyes
lizardlayer 2 — function CCNoptional
scclayers 6 & 10 — complexity hotspots & code-health trendoptional
tar--health-trend only (usually preinstalled)optional

Install lizard (Python, cross-platform):

pipx install lizard # or: pip install --user lizard
pip install -e ".[analysis]"# already covered by the project's "analysis" extra

Install scc (a Go binary — pick one):

brew install scc # macOS / Linux (Homebrew)
go install github.com/boyter/scc/v3@latest # any Go toolchain → ~/go/bin
scoop install scc # Windows (Scoop)

Or grab a prebuilt binary from the scc releases and put it on your PATH. gitmetry also looks in ~/bin/scc, so this works too:

mkdir -p ~/bin && mv scc ~/bin/ && chmod +x ~/bin/scc

How the raw data becomes a report

Don't copy the raw tables wholesale — distill a story from them. Target structure (see examples/sample-report.md):

  1. Header — author, window, repo count, main repo, commit count; a line on the standards; a warning that metrics are proxies, not truth (most trustworthy: throughput, rework %, CCN, ownership; indicative only: line sums, corr %).
  2. 🟢/🟡/🔴 Summary — one headline sentence, then a Dimension | Verdict | Trend table flagging each of the 11 dimensions, then 2–3 sentences on what to watch.
  3. Yearly overview — distil the tool's pre-aggregated rollup (window totals + per-year, optionally per-quarter) rather than re-deriving it: commits, median batch, big %, rework %, corr %, hotfixes, reverts, avg CCN, Δcx, severe fns, off-hours %, weekend %, active days, test co-change %. Partial years are pre-marked with *.
  4. Per dimension (1–11) — each gets a short Legend: + Assessment: with a flag and concrete files/numbers.
  5. Footer — note that it was generated from gitmetry (read-only over git) + where the raw data lives.

Flags: 🟢 healthy/improving · 🟡 watch · 🔴 problem. Be concrete (file names, numbers, "X → Y" trends). Trend > absolute number.

The 11 dimensions (what each measures)

Grouped into four themes — Activity (1) · First-pass quality (2–5) · Code structure (6–9) · People (10–11):

Activity

  1. Throughput — commits/month cross-project + batch-size distribution (med/p90 churn, big %) and commits per active day. SPACE Activity.

First-pass quality

  1. Rework rate — churn on code anyone touched within --rework-days (default 14). CodeScene / MS relative churn.
  2. Test co-change — of your commits touching production code, the share that also touch a test file — a message-independent first-pass-quality habit.
  3. Corrective vs value-add — Feature/Refactoring vs Fix vs Hotfix, with reverts surfaced separately (subset of Fix); hotfix = DORA Change-Failure proxy.
  4. Defect hotspots — files in your Fix/Hotfix commits × complexity.

Code structure / complexity

  1. Functional changes — CCN of the functions you actually touched plus Δcx, the net function-complexity your commits add vs remove (file totals after − before parent; negative = you simplified). lizard, main repo.
  2. Complexity hotspots — change frequency × complexity (score = touches × cx). CodeScene.
  3. Change coupling — files changed together in one commit (temporal coupling).
  4. Code-health trend — complexity/kLOC over time via git-archive snapshots (--health-trend).

Sustainability & people

  1. Sustainability — when you commit (off-hours/weekend rhythm; off-hours window via --off-hours). SPACE well-being.
  2. Ownership / bus factor — authorship share per file across full history, both churn-weighted and recency-weighted (1y half-life), plus who touched it last (solo ≥80 % = risk).

On top of the per-dimension monthly tables, gitmetry emits pre-aggregated overviews — window totals plus a per-year table (--quarterly adds a per-quarter one) — so yearly figures and YoY deltas come straight from raw counts, not from re-averaging the rounded monthly rows.

⚠️ Line metrics (added/deleted) are skewed by generated code (AI tests, docs, lock files). Most trustworthy signals: commit throughput, rework rate, function CCN, ownership.

Commit-type classification

Corrective/value-add (layer 4) and defect hotspots (layer 5) classify commits by their subject prefix: Feature/Refactoring/feat/refactor/perf → value, Fix/revert → fix, Hotfix → hotfix, Chore/Docs/test/build/ci/style → other. Reverts (git's auto-generated Revert "…" or a revert: prefix) stay in the fix bucket but are also counted separately, so the report can flag undo churn on its own. Conventional-Commits scope and the breaking marker are stripped first (feat(api)!:feat), so both the golemos convention and full Conventional Commits classify correctly. Any unknown prefix (or a subject with no Type: prefix) falls to other. If your repo uses a different convention, those two layers will under-count; the other eight don't depend on commit messages.

Development

pip install -e ".[dev]"# pytest + ruff
ruff check .# lint
pytest # run the unit tests (tests/)

The tests cover the pure, git-free helpers (commit-type classification, multi-language test-file detection, percentile math, path filtering, date arithmetic) plus an integration suite that builds a throwaway repo. CI runs ruff + pytest on Python 3.9 / 3.11 / 3.12 — see .github/workflows/ci.yml.

License

MIT © 2026 Vojtěch Žoha

About

Your private developer-efficiency report from git history — 11 dimensions (DORA / SPACE / CodeScene), local & read-only, narrated by an LLM.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

gitmetry

git + telemetry. Your own developer-efficiency report, built from git history — on your machine, for your eyes.

CILicense: MITPython 3.9+

gitmetry turns your git history into a private performance review you run on yourself — 11 dimensions mapped to the DORA, SPACE and CodeScene frameworks, then narrated by an LLM into a readable report with 🟢/🟡/🔴 verdicts and trends.

No cloud. No account. No dashboard for your manager. It's read-only over git (git archive / git show) — it never touches your working tree, and your data never leaves your laptop. The whole generator is a single zero-dependency stdlib Python file.

Think of it as Git Wrapped for your engineering habits, but with a method behind it: instead of vanity stats, you get throughput, rework rate, function complexity, defect hotspots, change coupling, work rhythm and bus-factor — the things that actually tell you whether the code you write lasts.

Why gitmetry?

Almost every tool in this space — LinearB, Swarmia, Haystack, Code Climate Velocity, Waydev — is a team dashboard for managers: cloud-hosted, paid, and pointed at developers. gitmetry is the opposite.

Team analytics SaaSgitmetry
Audiencemanagers, leadsyou, about your own work
Where data livestheir cloudyour machine, read-only over git
Cost / setuppaid, integrationsone Python file, git only
Metricsoften vanity KPIsDORA / SPACE / CodeScene-backed
Outputlive dashboardsan LLM-narrated report you keep

Good for: a personal retro, prep for a 1:1 or performance review, sanity-checking your own habits, or just curiosity about how you actually work.

What you get

A two-phase workflow:

  1. gitmetry scans your local repo(s) and emits raw data — markdown tables and/or JSON.
  2. An LLM (or you) turns that into a readable, interpreted report with flags and trends. See examples/sample-report.md for the target — here's a taste:
## 🟢 Summary
Stable volume, small batches and declining rework — a healthy profile.
Watch one knowledge concentration.
| Dimension | Verdict | Trend ||-------------------------------|------------------|------------------------|| First-pass quality (rework) | 🟢 better | 31 % → 24 % || Defect/complexity hotspots | 🟡 one dominant | Controller/Order.php || Ownership / bus factor | 🟡 concentration | 41 solo files |

⚠️ Metrics are proxies, not truth. Most trustworthy: commit throughput, rework %, function CCN, ownership. Indicative only (skewed by generated code / commit discipline): raw line sums. gitmetry leans on trends, not absolute numbers.

Quick start

The generator is a single stdlib Python 3 script — no install required:

git clone https://github.com/vzoha/gitmetry
cd gitmetry
./gitmetry.py # last 24 months of the repo in the CWD, markdown to stdout

Or install it as a gitmetry command with pipx:

pipx install git+https://github.com/vzoha/gitmetry
gitmetry --version

Then hand the output to your LLM of choice (Claude Code, etc.) with the prompt "interpret this gitmetry raw data into a report" — the conventions live in CLAUDE.md and the structure in the section below.

Usage

# last 24 months of the repo in the current directory, markdown to stdout
gitmetry
# explicit window + save both md and json
gitmetry --since 2021-06 --until 2026-06 --format both --out report.md
# a JS/TS codebase for the deep-analysis layers
gitmetry --main-ext ts --paths src
# + slow code-health trend (scc snapshots, runs for minutes)
gitmetry --since 2021-06 --health-trend --format both --out report.md

By default gitmetry analyzes the git repo in the current directory. Point --root at a parent folder to analyze several repos at once (throughput / rework / sustainability are cross-project; the deep layers run on one --main-repo).

Key options

OptionDefaultDescription
--root.folder holding the repos (*/.git); may itself be a repo
--main-repothe only repo foundrepo (under --root) for deep analysis (layers 5,6,7,8,9,11)
--authorgit config user.nameregex for git --author (case-insensitive)
--main-extphpprimary language extension for the deep layers (php, js, ts, py, go, rb…)
--since / --untillast 24 monthsYYYY-MM or YYYY-MM-DD
--paths.paths within the main repo passed to lizard/scc
--formatmdmd | json | both
--outstdoutoutput file (both.md + .json)
--health-trendoffscc complexity snapshots over time (slow)
--quarterlyoffalso emit a per-quarter overview table (on top of yearly)
--rework-days14rework window: churn on code anyone touched within N days
--off-hours8-19working hours START-END; commits outside count as off-hours
--big-batch400churn (add+del) above which a commit counts toward big %
--coupling-min-shared5min co-changes for a file pair to show in change coupling
--include-docsoffalso count non-code files in line metrics
--no-excludeoffdon't exclude test/generated code

The script has no config files and no hardcoded paths beyond the option defaults. Copy it anywhere and point the options at your repos.

Note: the deep-analysis layers (5 defect hotspots, 6 functional changes, 7 complexity hotspots, 8 change coupling, 9 code-health) operate on a single primary language selected via --main-ext (default php). The cross-project / language-agnostic layers are throughput, rework, test co-change, corrective, sustainability and ownership.

Personal config

So you don't retype --author / --root / --main-repo / --main-ext every run (and never commit them to a shared repo), put your defaults in a JSON file:

cp .gitmetry.example.json .gitmetry.json # then edit it
{ "author": "you", "root": "~/code", "main_repo": "my-app", "main_ext": "ts", "paths": ["src"] }

The tunable thresholds (rework_days, off_hours, big_batch, coupling_min_shared) can live here too. gitmetry loads the first file it finds — $GITMETRY_CONFIG, then ./.gitmetry.json, then $XDG_CONFIG_HOME/gitmetry/config.json — and uses it as defaults; any flag you pass on the command line still overrides it. .gitmetry.json and CLAUDE.local.md are gitignored, so your settings stay local.

Don't commit your generated reports — they contain your real author name and private file paths. Keep them outside the repo (e.g. ~/reports/) or in a local ./reports/ folder, which is already gitignored (along with gitmetry-*.md / gitmetry-*.json). Using gitmetry on a private fork? Drop those lines from .gitignore to version your reports.

Dependencies

Only git is required. The two analysis tools below are optional — if a tool is missing, gitmetry just skips its layer and the rest of the report still runs, so you can start with nothing extra installed.

ToolPowersRequired?
giteverythingyes
lizardlayer 2 — function CCNoptional
scclayers 6 & 10 — complexity hotspots & code-health trendoptional
tar--health-trend only (usually preinstalled)optional

Install lizard (Python, cross-platform):

pipx install lizard # or: pip install --user lizard
pip install -e ".[analysis]"# already covered by the project's "analysis" extra

Install scc (a Go binary — pick one):

brew install scc # macOS / Linux (Homebrew)
go install github.com/boyter/scc/v3@latest # any Go toolchain → ~/go/bin
scoop install scc # Windows (Scoop)

Or grab a prebuilt binary from the scc releases and put it on your PATH. gitmetry also looks in ~/bin/scc, so this works too:

mkdir -p ~/bin && mv scc ~/bin/ && chmod +x ~/bin/scc

How the raw data becomes a report

Don't copy the raw tables wholesale — distill a story from them. Target structure (see examples/sample-report.md):

  1. Header — author, window, repo count, main repo, commit count; a line on the standards; a warning that metrics are proxies, not truth (most trustworthy: throughput, rework %, CCN, ownership; indicative only: line sums, corr %).
  2. 🟢/🟡/🔴 Summary — one headline sentence, then a Dimension | Verdict | Trend table flagging each of the 11 dimensions, then 2–3 sentences on what to watch.
  3. Yearly overview — distil the tool's pre-aggregated rollup (window totals + per-year, optionally per-quarter) rather than re-deriving it: commits, median batch, big %, rework %, corr %, hotfixes, reverts, avg CCN, Δcx, severe fns, off-hours %, weekend %, active days, test co-change %. Partial years are pre-marked with *.
  4. Per dimension (1–11) — each gets a short Legend: + Assessment: with a flag and concrete files/numbers.
  5. Footer — note that it was generated from gitmetry (read-only over git) + where the raw data lives.

Flags: 🟢 healthy/improving · 🟡 watch · 🔴 problem. Be concrete (file names, numbers, "X → Y" trends). Trend > absolute number.

The 11 dimensions (what each measures)

Grouped into four themes — Activity (1) · First-pass quality (2–5) · Code structure (6–9) · People (10–11):

Activity

  1. Throughput — commits/month cross-project + batch-size distribution (med/p90 churn, big %) and commits per active day. SPACE Activity.

First-pass quality

  1. Rework rate — churn on code anyone touched within --rework-days (default 14). CodeScene / MS relative churn.
  2. Test co-change — of your commits touching production code, the share that also touch a test file — a message-independent first-pass-quality habit.
  3. Corrective vs value-add — Feature/Refactoring vs Fix vs Hotfix, with reverts surfaced separately (subset of Fix); hotfix = DORA Change-Failure proxy.
  4. Defect hotspots — files in your Fix/Hotfix commits × complexity.

Code structure / complexity

  1. Functional changes — CCN of the functions you actually touched plus Δcx, the net function-complexity your commits add vs remove (file totals after − before parent; negative = you simplified). lizard, main repo.
  2. Complexity hotspots — change frequency × complexity (score = touches × cx). CodeScene.
  3. Change coupling — files changed together in one commit (temporal coupling).
  4. Code-health trend — complexity/kLOC over time via git-archive snapshots (--health-trend).

Sustainability & people

  1. Sustainability — when you commit (off-hours/weekend rhythm; off-hours window via --off-hours). SPACE well-being.
  2. Ownership / bus factor — authorship share per file across full history, both churn-weighted and recency-weighted (1y half-life), plus who touched it last (solo ≥80 % = risk).

On top of the per-dimension monthly tables, gitmetry emits pre-aggregated overviews — window totals plus a per-year table (--quarterly adds a per-quarter one) — so yearly figures and YoY deltas come straight from raw counts, not from re-averaging the rounded monthly rows.

⚠️ Line metrics (added/deleted) are skewed by generated code (AI tests, docs, lock files). Most trustworthy signals: commit throughput, rework rate, function CCN, ownership.

Commit-type classification

Corrective/value-add (layer 4) and defect hotspots (layer 5) classify commits by their subject prefix: Feature/Refactoring/feat/refactor/perf → value, Fix/revert → fix, Hotfix → hotfix, Chore/Docs/test/build/ci/style → other. Reverts (git's auto-generated Revert "…" or a revert: prefix) stay in the fix bucket but are also counted separately, so the report can flag undo churn on its own. Conventional-Commits scope and the breaking marker are stripped first (feat(api)!:feat), so both the golemos convention and full Conventional Commits classify correctly. Any unknown prefix (or a subject with no Type: prefix) falls to other. If your repo uses a different convention, those two layers will under-count; the other eight don't depend on commit messages.

Development

pip install -e ".[dev]"# pytest + ruff
ruff check .# lint
pytest # run the unit tests (tests/)

The tests cover the pure, git-free helpers (commit-type classification, multi-language test-file detection, percentile math, path filtering, date arithmetic) plus an integration suite that builds a throwaway repo. CI runs ruff + pytest on Python 3.9 / 3.11 / 3.12 — see .github/workflows/ci.yml.

License

MIT © 2026 Vojtěch Žoha

About

Your private developer-efficiency report from git history — 11 dimensions (DORA / SPACE / CodeScene), local & read-only, narrated by an LLM.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

gitmetry

git + telemetry. Your own developer-efficiency report, built from git history — on your machine, for your eyes.

CILicense: MITPython 3.9+

gitmetry turns your git history into a private performance review you run on yourself — 11 dimensions mapped to the DORA, SPACE and CodeScene frameworks, then narrated by an LLM into a readable report with 🟢/🟡/🔴 verdicts and trends.

No cloud. No account. No dashboard for your manager. It's read-only over git (git archive / git show) — it never touches your working tree, and your data never leaves your laptop. The whole generator is a single zero-dependency stdlib Python file.

Think of it as Git Wrapped for your engineering habits, but with a method behind it: instead of vanity stats, you get throughput, rework rate, function complexity, defect hotspots, change coupling, work rhythm and bus-factor — the things that actually tell you whether the code you write lasts.

Why gitmetry?

Almost every tool in this space — LinearB, Swarmia, Haystack, Code Climate Velocity, Waydev — is a team dashboard for managers: cloud-hosted, paid, and pointed at developers. gitmetry is the opposite.

Team analytics SaaSgitmetry
Audiencemanagers, leadsyou, about your own work
Where data livestheir cloudyour machine, read-only over git
Cost / setuppaid, integrationsone Python file, git only
Metricsoften vanity KPIsDORA / SPACE / CodeScene-backed
Outputlive dashboardsan LLM-narrated report you keep

Good for: a personal retro, prep for a 1:1 or performance review, sanity-checking your own habits, or just curiosity about how you actually work.

What you get

A two-phase workflow:

  1. gitmetry scans your local repo(s) and emits raw data — markdown tables and/or JSON.
  2. An LLM (or you) turns that into a readable, interpreted report with flags and trends. See examples/sample-report.md for the target — here's a taste:
## 🟢 Summary
Stable volume, small batches and declining rework — a healthy profile.
Watch one knowledge concentration.
| Dimension | Verdict | Trend ||-------------------------------|------------------|------------------------|| First-pass quality (rework) | 🟢 better | 31 % → 24 % || Defect/complexity hotspots | 🟡 one dominant | Controller/Order.php || Ownership / bus factor | 🟡 concentration | 41 solo files |

⚠️ Metrics are proxies, not truth. Most trustworthy: commit throughput, rework %, function CCN, ownership. Indicative only (skewed by generated code / commit discipline): raw line sums. gitmetry leans on trends, not absolute numbers.

Quick start

The generator is a single stdlib Python 3 script — no install required:

git clone https://github.com/vzoha/gitmetry
cd gitmetry
./gitmetry.py # last 24 months of the repo in the CWD, markdown to stdout

Or install it as a gitmetry command with pipx:

pipx install git+https://github.com/vzoha/gitmetry
gitmetry --version

Then hand the output to your LLM of choice (Claude Code, etc.) with the prompt "interpret this gitmetry raw data into a report" — the conventions live in CLAUDE.md and the structure in the section below.

Usage

# last 24 months of the repo in the current directory, markdown to stdout
gitmetry
# explicit window + save both md and json
gitmetry --since 2021-06 --until 2026-06 --format both --out report.md
# a JS/TS codebase for the deep-analysis layers
gitmetry --main-ext ts --paths src
# + slow code-health trend (scc snapshots, runs for minutes)
gitmetry --since 2021-06 --health-trend --format both --out report.md

By default gitmetry analyzes the git repo in the current directory. Point --root at a parent folder to analyze several repos at once (throughput / rework / sustainability are cross-project; the deep layers run on one --main-repo).

Key options

OptionDefaultDescription
--root.folder holding the repos (*/.git); may itself be a repo
--main-repothe only repo foundrepo (under --root) for deep analysis (layers 5,6,7,8,9,11)
--authorgit config user.nameregex for git --author (case-insensitive)
--main-extphpprimary language extension for the deep layers (php, js, ts, py, go, rb…)
--since / --untillast 24 monthsYYYY-MM or YYYY-MM-DD
--paths.paths within the main repo passed to lizard/scc
--formatmdmd | json | both
--outstdoutoutput file (both.md + .json)
--health-trendoffscc complexity snapshots over time (slow)
--quarterlyoffalso emit a per-quarter overview table (on top of yearly)
--rework-days14rework window: churn on code anyone touched within N days
--off-hours8-19working hours START-END; commits outside count as off-hours
--big-batch400churn (add+del) above which a commit counts toward big %
--coupling-min-shared5min co-changes for a file pair to show in change coupling
--include-docsoffalso count non-code files in line metrics
--no-excludeoffdon't exclude test/generated code

The script has no config files and no hardcoded paths beyond the option defaults. Copy it anywhere and point the options at your repos.

Note: the deep-analysis layers (5 defect hotspots, 6 functional changes, 7 complexity hotspots, 8 change coupling, 9 code-health) operate on a single primary language selected via --main-ext (default php). The cross-project / language-agnostic layers are throughput, rework, test co-change, corrective, sustainability and ownership.

Personal config

So you don't retype --author / --root / --main-repo / --main-ext every run (and never commit them to a shared repo), put your defaults in a JSON file:

cp .gitmetry.example.json .gitmetry.json # then edit it
{ "author": "you", "root": "~/code", "main_repo": "my-app", "main_ext": "ts", "paths": ["src"] }

The tunable thresholds (rework_days, off_hours, big_batch, coupling_min_shared) can live here too. gitmetry loads the first file it finds — $GITMETRY_CONFIG, then ./.gitmetry.json, then $XDG_CONFIG_HOME/gitmetry/config.json — and uses it as defaults; any flag you pass on the command line still overrides it. .gitmetry.json and CLAUDE.local.md are gitignored, so your settings stay local.

Don't commit your generated reports — they contain your real author name and private file paths. Keep them outside the repo (e.g. ~/reports/) or in a local ./reports/ folder, which is already gitignored (along with gitmetry-*.md / gitmetry-*.json). Using gitmetry on a private fork? Drop those lines from .gitignore to version your reports.

Dependencies

Only git is required. The two analysis tools below are optional — if a tool is missing, gitmetry just skips its layer and the rest of the report still runs, so you can start with nothing extra installed.

ToolPowersRequired?
giteverythingyes
lizardlayer 2 — function CCNoptional
scclayers 6 & 10 — complexity hotspots & code-health trendoptional
tar--health-trend only (usually preinstalled)optional

Install lizard (Python, cross-platform):

pipx install lizard # or: pip install --user lizard
pip install -e ".[analysis]"# already covered by the project's "analysis" extra

Install scc (a Go binary — pick one):

brew install scc # macOS / Linux (Homebrew)
go install github.com/boyter/scc/v3@latest # any Go toolchain → ~/go/bin
scoop install scc # Windows (Scoop)

Or grab a prebuilt binary from the scc releases and put it on your PATH. gitmetry also looks in ~/bin/scc, so this works too:

mkdir -p ~/bin && mv scc ~/bin/ && chmod +x ~/bin/scc

How the raw data becomes a report

Don't copy the raw tables wholesale — distill a story from them. Target structure (see examples/sample-report.md):

  1. Header — author, window, repo count, main repo, commit count; a line on the standards; a warning that metrics are proxies, not truth (most trustworthy: throughput, rework %, CCN, ownership; indicative only: line sums, corr %).
  2. 🟢/🟡/🔴 Summary — one headline sentence, then a Dimension | Verdict | Trend table flagging each of the 11 dimensions, then 2–3 sentences on what to watch.
  3. Yearly overview — distil the tool's pre-aggregated rollup (window totals + per-year, optionally per-quarter) rather than re-deriving it: commits, median batch, big %, rework %, corr %, hotfixes, reverts, avg CCN, Δcx, severe fns, off-hours %, weekend %, active days, test co-change %. Partial years are pre-marked with *.
  4. Per dimension (1–11) — each gets a short Legend: + Assessment: with a flag and concrete files/numbers.
  5. Footer — note that it was generated from gitmetry (read-only over git) + where the raw data lives.

Flags: 🟢 healthy/improving · 🟡 watch · 🔴 problem. Be concrete (file names, numbers, "X → Y" trends). Trend > absolute number.

The 11 dimensions (what each measures)

Grouped into four themes — Activity (1) · First-pass quality (2–5) · Code structure (6–9) · People (10–11):

Activity

  1. Throughput — commits/month cross-project + batch-size distribution (med/p90 churn, big %) and commits per active day. SPACE Activity.

First-pass quality

  1. Rework rate — churn on code anyone touched within --rework-days (default 14). CodeScene / MS relative churn.
  2. Test co-change — of your commits touching production code, the share that also touch a test file — a message-independent first-pass-quality habit.
  3. Corrective vs value-add — Feature/Refactoring vs Fix vs Hotfix, with reverts surfaced separately (subset of Fix); hotfix = DORA Change-Failure proxy.
  4. Defect hotspots — files in your Fix/Hotfix commits × complexity.

Code structure / complexity

  1. Functional changes — CCN of the functions you actually touched plus Δcx, the net function-complexity your commits add vs remove (file totals after − before parent; negative = you simplified). lizard, main repo.
  2. Complexity hotspots — change frequency × complexity (score = touches × cx). CodeScene.
  3. Change coupling — files changed together in one commit (temporal coupling).
  4. Code-health trend — complexity/kLOC over time via git-archive snapshots (--health-trend).

Sustainability & people

  1. Sustainability — when you commit (off-hours/weekend rhythm; off-hours window via --off-hours). SPACE well-being.
  2. Ownership / bus factor — authorship share per file across full history, both churn-weighted and recency-weighted (1y half-life), plus who touched it last (solo ≥80 % = risk).

On top of the per-dimension monthly tables, gitmetry emits pre-aggregated overviews — window totals plus a per-year table (--quarterly adds a per-quarter one) — so yearly figures and YoY deltas come straight from raw counts, not from re-averaging the rounded monthly rows.

⚠️ Line metrics (added/deleted) are skewed by generated code (AI tests, docs, lock files). Most trustworthy signals: commit throughput, rework rate, function CCN, ownership.

Commit-type classification

Corrective/value-add (layer 4) and defect hotspots (layer 5) classify commits by their subject prefix: Feature/Refactoring/feat/refactor/perf → value, Fix/revert → fix, Hotfix → hotfix, Chore/Docs/test/build/ci/style → other. Reverts (git's auto-generated Revert "…" or a revert: prefix) stay in the fix bucket but are also counted separately, so the report can flag undo churn on its own. Conventional-Commits scope and the breaking marker are stripped first (feat(api)!:feat), so both the golemos convention and full Conventional Commits classify correctly. Any unknown prefix (or a subject with no Type: prefix) falls to other. If your repo uses a different convention, those two layers will under-count; the other eight don't depend on commit messages.

Development

pip install -e ".[dev]"# pytest + ruff
ruff check .# lint
pytest # run the unit tests (tests/)

The tests cover the pure, git-free helpers (commit-type classification, multi-language test-file detection, percentile math, path filtering, date arithmetic) plus an integration suite that builds a throwaway repo. CI runs ruff + pytest on Python 3.9 / 3.11 / 3.12 — see .github/workflows/ci.yml.

License

MIT © 2026 Vojtěch Žoha

About

Your private developer-efficiency report from git history — 11 dimensions (DORA / SPACE / CodeScene), local & read-only, narrated by an LLM.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

gitmetry

git + telemetry. Your own developer-efficiency report, built from git history — on your machine, for your eyes.

CILicense: MITPython 3.9+

gitmetry turns your git history into a private performance review you run on yourself — 11 dimensions mapped to the DORA, SPACE and CodeScene frameworks, then narrated by an LLM into a readable report with 🟢/🟡/🔴 verdicts and trends.

No cloud. No account. No dashboard for your manager. It's read-only over git (git archive / git show) — it never touches your working tree, and your data never leaves your laptop. The whole generator is a single zero-dependency stdlib Python file.

Think of it as Git Wrapped for your engineering habits, but with a method behind it: instead of vanity stats, you get throughput, rework rate, function complexity, defect hotspots, change coupling, work rhythm and bus-factor — the things that actually tell you whether the code you write lasts.

Why gitmetry?

Almost every tool in this space — LinearB, Swarmia, Haystack, Code Climate Velocity, Waydev — is a team dashboard for managers: cloud-hosted, paid, and pointed at developers. gitmetry is the opposite.

Team analytics SaaSgitmetry
Audiencemanagers, leadsyou, about your own work
Where data livestheir cloudyour machine, read-only over git
Cost / setuppaid, integrationsone Python file, git only
Metricsoften vanity KPIsDORA / SPACE / CodeScene-backed
Outputlive dashboardsan LLM-narrated report you keep

Good for: a personal retro, prep for a 1:1 or performance review, sanity-checking your own habits, or just curiosity about how you actually work.

What you get

A two-phase workflow:

  1. gitmetry scans your local repo(s) and emits raw data — markdown tables and/or JSON.
  2. An LLM (or you) turns that into a readable, interpreted report with flags and trends. See examples/sample-report.md for the target — here's a taste:
## 🟢 Summary
Stable volume, small batches and declining rework — a healthy profile.
Watch one knowledge concentration.
| Dimension | Verdict | Trend ||-------------------------------|------------------|------------------------|| First-pass quality (rework) | 🟢 better | 31 % → 24 % || Defect/complexity hotspots | 🟡 one dominant | Controller/Order.php || Ownership / bus factor | 🟡 concentration | 41 solo files |

⚠️ Metrics are proxies, not truth. Most trustworthy: commit throughput, rework %, function CCN, ownership. Indicative only (skewed by generated code / commit discipline): raw line sums. gitmetry leans on trends, not absolute numbers.

Quick start

The generator is a single stdlib Python 3 script — no install required:

git clone https://github.com/vzoha/gitmetry
cd gitmetry
./gitmetry.py # last 24 months of the repo in the CWD, markdown to stdout

Or install it as a gitmetry command with pipx:

pipx install git+https://github.com/vzoha/gitmetry
gitmetry --version

Then hand the output to your LLM of choice (Claude Code, etc.) with the prompt "interpret this gitmetry raw data into a report" — the conventions live in CLAUDE.md and the structure in the section below.

Usage

# last 24 months of the repo in the current directory, markdown to stdout
gitmetry
# explicit window + save both md and json
gitmetry --since 2021-06 --until 2026-06 --format both --out report.md
# a JS/TS codebase for the deep-analysis layers
gitmetry --main-ext ts --paths src
# + slow code-health trend (scc snapshots, runs for minutes)
gitmetry --since 2021-06 --health-trend --format both --out report.md

By default gitmetry analyzes the git repo in the current directory. Point --root at a parent folder to analyze several repos at once (throughput / rework / sustainability are cross-project; the deep layers run on one --main-repo).

Key options

OptionDefaultDescription
--root.folder holding the repos (*/.git); may itself be a repo
--main-repothe only repo foundrepo (under --root) for deep analysis (layers 5,6,7,8,9,11)
--authorgit config user.nameregex for git --author (case-insensitive)
--main-extphpprimary language extension for the deep layers (php, js, ts, py, go, rb…)
--since / --untillast 24 monthsYYYY-MM or YYYY-MM-DD
--paths.paths within the main repo passed to lizard/scc
--formatmdmd | json | both
--outstdoutoutput file (both.md + .json)
--health-trendoffscc complexity snapshots over time (slow)
--quarterlyoffalso emit a per-quarter overview table (on top of yearly)
--rework-days14rework window: churn on code anyone touched within N days
--off-hours8-19working hours START-END; commits outside count as off-hours
--big-batch400churn (add+del) above which a commit counts toward big %
--coupling-min-shared5min co-changes for a file pair to show in change coupling
--include-docsoffalso count non-code files in line metrics
--no-excludeoffdon't exclude test/generated code

The script has no config files and no hardcoded paths beyond the option defaults. Copy it anywhere and point the options at your repos.

Note: the deep-analysis layers (5 defect hotspots, 6 functional changes, 7 complexity hotspots, 8 change coupling, 9 code-health) operate on a single primary language selected via --main-ext (default php). The cross-project / language-agnostic layers are throughput, rework, test co-change, corrective, sustainability and ownership.

Personal config

So you don't retype --author / --root / --main-repo / --main-ext every run (and never commit them to a shared repo), put your defaults in a JSON file:

cp .gitmetry.example.json .gitmetry.json # then edit it
{ "author": "you", "root": "~/code", "main_repo": "my-app", "main_ext": "ts", "paths": ["src"] }

The tunable thresholds (rework_days, off_hours, big_batch, coupling_min_shared) can live here too. gitmetry loads the first file it finds — $GITMETRY_CONFIG, then ./.gitmetry.json, then $XDG_CONFIG_HOME/gitmetry/config.json — and uses it as defaults; any flag you pass on the command line still overrides it. .gitmetry.json and CLAUDE.local.md are gitignored, so your settings stay local.

Don't commit your generated reports — they contain your real author name and private file paths. Keep them outside the repo (e.g. ~/reports/) or in a local ./reports/ folder, which is already gitignored (along with gitmetry-*.md / gitmetry-*.json). Using gitmetry on a private fork? Drop those lines from .gitignore to version your reports.

Dependencies

Only git is required. The two analysis tools below are optional — if a tool is missing, gitmetry just skips its layer and the rest of the report still runs, so you can start with nothing extra installed.

ToolPowersRequired?
giteverythingyes
lizardlayer 2 — function CCNoptional
scclayers 6 & 10 — complexity hotspots & code-health trendoptional
tar--health-trend only (usually preinstalled)optional

Install lizard (Python, cross-platform):

pipx install lizard # or: pip install --user lizard
pip install -e ".[analysis]"# already covered by the project's "analysis" extra

Install scc (a Go binary — pick one):

brew install scc # macOS / Linux (Homebrew)
go install github.com/boyter/scc/v3@latest # any Go toolchain → ~/go/bin
scoop install scc # Windows (Scoop)

Or grab a prebuilt binary from the scc releases and put it on your PATH. gitmetry also looks in ~/bin/scc, so this works too:

mkdir -p ~/bin && mv scc ~/bin/ && chmod +x ~/bin/scc

How the raw data becomes a report

Don't copy the raw tables wholesale — distill a story from them. Target structure (see examples/sample-report.md):

  1. Header — author, window, repo count, main repo, commit count; a line on the standards; a warning that metrics are proxies, not truth (most trustworthy: throughput, rework %, CCN, ownership; indicative only: line sums, corr %).
  2. 🟢/🟡/🔴 Summary — one headline sentence, then a Dimension | Verdict | Trend table flagging each of the 11 dimensions, then 2–3 sentences on what to watch.
  3. Yearly overview — distil the tool's pre-aggregated rollup (window totals + per-year, optionally per-quarter) rather than re-deriving it: commits, median batch, big %, rework %, corr %, hotfixes, reverts, avg CCN, Δcx, severe fns, off-hours %, weekend %, active days, test co-change %. Partial years are pre-marked with *.
  4. Per dimension (1–11) — each gets a short Legend: + Assessment: with a flag and concrete files/numbers.
  5. Footer — note that it was generated from gitmetry (read-only over git) + where the raw data lives.

Flags: 🟢 healthy/improving · 🟡 watch · 🔴 problem. Be concrete (file names, numbers, "X → Y" trends). Trend > absolute number.

The 11 dimensions (what each measures)

Grouped into four themes — Activity (1) · First-pass quality (2–5) · Code structure (6–9) · People (10–11):

Activity

  1. Throughput — commits/month cross-project + batch-size distribution (med/p90 churn, big %) and commits per active day. SPACE Activity.

First-pass quality

  1. Rework rate — churn on code anyone touched within --rework-days (default 14). CodeScene / MS relative churn.
  2. Test co-change — of your commits touching production code, the share that also touch a test file — a message-independent first-pass-quality habit.
  3. Corrective vs value-add — Feature/Refactoring vs Fix vs Hotfix, with reverts surfaced separately (subset of Fix); hotfix = DORA Change-Failure proxy.
  4. Defect hotspots — files in your Fix/Hotfix commits × complexity.

Code structure / complexity

  1. Functional changes — CCN of the functions you actually touched plus Δcx, the net function-complexity your commits add vs remove (file totals after − before parent; negative = you simplified). lizard, main repo.
  2. Complexity hotspots — change frequency × complexity (score = touches × cx). CodeScene.
  3. Change coupling — files changed together in one commit (temporal coupling).
  4. Code-health trend — complexity/kLOC over time via git-archive snapshots (--health-trend).

Sustainability & people

  1. Sustainability — when you commit (off-hours/weekend rhythm; off-hours window via --off-hours). SPACE well-being.
  2. Ownership / bus factor — authorship share per file across full history, both churn-weighted and recency-weighted (1y half-life), plus who touched it last (solo ≥80 % = risk).

On top of the per-dimension monthly tables, gitmetry emits pre-aggregated overviews — window totals plus a per-year table (--quarterly adds a per-quarter one) — so yearly figures and YoY deltas come straight from raw counts, not from re-averaging the rounded monthly rows.

⚠️ Line metrics (added/deleted) are skewed by generated code (AI tests, docs, lock files). Most trustworthy signals: commit throughput, rework rate, function CCN, ownership.

Commit-type classification

Corrective/value-add (layer 4) and defect hotspots (layer 5) classify commits by their subject prefix: Feature/Refactoring/feat/refactor/perf → value, Fix/revert → fix, Hotfix → hotfix, Chore/Docs/test/build/ci/style → other. Reverts (git's auto-generated Revert "…" or a revert: prefix) stay in the fix bucket but are also counted separately, so the report can flag undo churn on its own. Conventional-Commits scope and the breaking marker are stripped first (feat(api)!:feat), so both the golemos convention and full Conventional Commits classify correctly. Any unknown prefix (or a subject with no Type: prefix) falls to other. If your repo uses a different convention, those two layers will under-count; the other eight don't depend on commit messages.

Development

pip install -e ".[dev]"# pytest + ruff
ruff check .# lint
pytest # run the unit tests (tests/)

The tests cover the pure, git-free helpers (commit-type classification, multi-language test-file detection, percentile math, path filtering, date arithmetic) plus an integration suite that builds a throwaway repo. CI runs ruff + pytest on Python 3.9 / 3.11 / 3.12 — see .github/workflows/ci.yml.

License

MIT © 2026 Vojtěch Žoha

About

Your private developer-efficiency report from git history — 11 dimensions (DORA / SPACE / CodeScene), local & read-only, narrated by an LLM.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

gitmetry

git + telemetry. Your own developer-efficiency report, built from git history — on your machine, for your eyes.

CILicense: MITPython 3.9+

gitmetry turns your git history into a private performance review you run on yourself — 11 dimensions mapped to the DORA, SPACE and CodeScene frameworks, then narrated by an LLM into a readable report with 🟢/🟡/🔴 verdicts and trends.

No cloud. No account. No dashboard for your manager. It's read-only over git (git archive / git show) — it never touches your working tree, and your data never leaves your laptop. The whole generator is a single zero-dependency stdlib Python file.

Think of it as Git Wrapped for your engineering habits, but with a method behind it: instead of vanity stats, you get throughput, rework rate, function complexity, defect hotspots, change coupling, work rhythm and bus-factor — the things that actually tell you whether the code you write lasts.

Why gitmetry?

Almost every tool in this space — LinearB, Swarmia, Haystack, Code Climate Velocity, Waydev — is a team dashboard for managers: cloud-hosted, paid, and pointed at developers. gitmetry is the opposite.

Team analytics SaaSgitmetry
Audiencemanagers, leadsyou, about your own work
Where data livestheir cloudyour machine, read-only over git
Cost / setuppaid, integrationsone Python file, git only
Metricsoften vanity KPIsDORA / SPACE / CodeScene-backed
Outputlive dashboardsan LLM-narrated report you keep

Good for: a personal retro, prep for a 1:1 or performance review, sanity-checking your own habits, or just curiosity about how you actually work.

What you get

A two-phase workflow:

  1. gitmetry scans your local repo(s) and emits raw data — markdown tables and/or JSON.
  2. An LLM (or you) turns that into a readable, interpreted report with flags and trends. See examples/sample-report.md for the target — here's a taste:
## 🟢 Summary
Stable volume, small batches and declining rework — a healthy profile.
Watch one knowledge concentration.
| Dimension | Verdict | Trend ||-------------------------------|------------------|------------------------|| First-pass quality (rework) | 🟢 better | 31 % → 24 % || Defect/complexity hotspots | 🟡 one dominant | Controller/Order.php || Ownership / bus factor | 🟡 concentration | 41 solo files |

⚠️ Metrics are proxies, not truth. Most trustworthy: commit throughput, rework %, function CCN, ownership. Indicative only (skewed by generated code / commit discipline): raw line sums. gitmetry leans on trends, not absolute numbers.

Quick start

The generator is a single stdlib Python 3 script — no install required:

git clone https://github.com/vzoha/gitmetry
cd gitmetry
./gitmetry.py # last 24 months of the repo in the CWD, markdown to stdout

Or install it as a gitmetry command with pipx:

pipx install git+https://github.com/vzoha/gitmetry
gitmetry --version

Then hand the output to your LLM of choice (Claude Code, etc.) with the prompt "interpret this gitmetry raw data into a report" — the conventions live in CLAUDE.md and the structure in the section below.

Usage

# last 24 months of the repo in the current directory, markdown to stdout
gitmetry
# explicit window + save both md and json
gitmetry --since 2021-06 --until 2026-06 --format both --out report.md
# a JS/TS codebase for the deep-analysis layers
gitmetry --main-ext ts --paths src
# + slow code-health trend (scc snapshots, runs for minutes)
gitmetry --since 2021-06 --health-trend --format both --out report.md

By default gitmetry analyzes the git repo in the current directory. Point --root at a parent folder to analyze several repos at once (throughput / rework / sustainability are cross-project; the deep layers run on one --main-repo).

Key options

OptionDefaultDescription
--root.folder holding the repos (*/.git); may itself be a repo
--main-repothe only repo foundrepo (under --root) for deep analysis (layers 5,6,7,8,9,11)
--authorgit config user.nameregex for git --author (case-insensitive)
--main-extphpprimary language extension for the deep layers (php, js, ts, py, go, rb…)
--since / --untillast 24 monthsYYYY-MM or YYYY-MM-DD
--paths.paths within the main repo passed to lizard/scc
--formatmdmd | json | both
--outstdoutoutput file (both.md + .json)
--health-trendoffscc complexity snapshots over time (slow)
--quarterlyoffalso emit a per-quarter overview table (on top of yearly)
--rework-days14rework window: churn on code anyone touched within N days
--off-hours8-19working hours START-END; commits outside count as off-hours
--big-batch400churn (add+del) above which a commit counts toward big %
--coupling-min-shared5min co-changes for a file pair to show in change coupling
--include-docsoffalso count non-code files in line metrics
--no-excludeoffdon't exclude test/generated code

The script has no config files and no hardcoded paths beyond the option defaults. Copy it anywhere and point the options at your repos.

Note: the deep-analysis layers (5 defect hotspots, 6 functional changes, 7 complexity hotspots, 8 change coupling, 9 code-health) operate on a single primary language selected via --main-ext (default php). The cross-project / language-agnostic layers are throughput, rework, test co-change, corrective, sustainability and ownership.

Personal config

So you don't retype --author / --root / --main-repo / --main-ext every run (and never commit them to a shared repo), put your defaults in a JSON file:

cp .gitmetry.example.json .gitmetry.json # then edit it
{ "author": "you", "root": "~/code", "main_repo": "my-app", "main_ext": "ts", "paths": ["src"] }

The tunable thresholds (rework_days, off_hours, big_batch, coupling_min_shared) can live here too. gitmetry loads the first file it finds — $GITMETRY_CONFIG, then ./.gitmetry.json, then $XDG_CONFIG_HOME/gitmetry/config.json — and uses it as defaults; any flag you pass on the command line still overrides it. .gitmetry.json and CLAUDE.local.md are gitignored, so your settings stay local.

Don't commit your generated reports — they contain your real author name and private file paths. Keep them outside the repo (e.g. ~/reports/) or in a local ./reports/ folder, which is already gitignored (along with gitmetry-*.md / gitmetry-*.json). Using gitmetry on a private fork? Drop those lines from .gitignore to version your reports.

Dependencies

Only git is required. The two analysis tools below are optional — if a tool is missing, gitmetry just skips its layer and the rest of the report still runs, so you can start with nothing extra installed.

ToolPowersRequired?
giteverythingyes
lizardlayer 2 — function CCNoptional
scclayers 6 & 10 — complexity hotspots & code-health trendoptional
tar--health-trend only (usually preinstalled)optional

Install lizard (Python, cross-platform):

pipx install lizard # or: pip install --user lizard
pip install -e ".[analysis]"# already covered by the project's "analysis" extra

Install scc (a Go binary — pick one):

brew install scc # macOS / Linux (Homebrew)
go install github.com/boyter/scc/v3@latest # any Go toolchain → ~/go/bin
scoop install scc # Windows (Scoop)

Or grab a prebuilt binary from the scc releases and put it on your PATH. gitmetry also looks in ~/bin/scc, so this works too:

mkdir -p ~/bin && mv scc ~/bin/ && chmod +x ~/bin/scc

How the raw data becomes a report

Don't copy the raw tables wholesale — distill a story from them. Target structure (see examples/sample-report.md):

  1. Header — author, window, repo count, main repo, commit count; a line on the standards; a warning that metrics are proxies, not truth (most trustworthy: throughput, rework %, CCN, ownership; indicative only: line sums, corr %).
  2. 🟢/🟡/🔴 Summary — one headline sentence, then a Dimension | Verdict | Trend table flagging each of the 11 dimensions, then 2–3 sentences on what to watch.
  3. Yearly overview — distil the tool's pre-aggregated rollup (window totals + per-year, optionally per-quarter) rather than re-deriving it: commits, median batch, big %, rework %, corr %, hotfixes, reverts, avg CCN, Δcx, severe fns, off-hours %, weekend %, active days, test co-change %. Partial years are pre-marked with *.
  4. Per dimension (1–11) — each gets a short Legend: + Assessment: with a flag and concrete files/numbers.
  5. Footer — note that it was generated from gitmetry (read-only over git) + where the raw data lives.

Flags: 🟢 healthy/improving · 🟡 watch · 🔴 problem. Be concrete (file names, numbers, "X → Y" trends). Trend > absolute number.

The 11 dimensions (what each measures)

Grouped into four themes — Activity (1) · First-pass quality (2–5) · Code structure (6–9) · People (10–11):

Activity

  1. Throughput — commits/month cross-project + batch-size distribution (med/p90 churn, big %) and commits per active day. SPACE Activity.

First-pass quality

  1. Rework rate — churn on code anyone touched within --rework-days (default 14). CodeScene / MS relative churn.
  2. Test co-change — of your commits touching production code, the share that also touch a test file — a message-independent first-pass-quality habit.
  3. Corrective vs value-add — Feature/Refactoring vs Fix vs Hotfix, with reverts surfaced separately (subset of Fix); hotfix = DORA Change-Failure proxy.
  4. Defect hotspots — files in your Fix/Hotfix commits × complexity.

Code structure / complexity

  1. Functional changes — CCN of the functions you actually touched plus Δcx, the net function-complexity your commits add vs remove (file totals after − before parent; negative = you simplified). lizard, main repo.
  2. Complexity hotspots — change frequency × complexity (score = touches × cx). CodeScene.
  3. Change coupling — files changed together in one commit (temporal coupling).
  4. Code-health trend — complexity/kLOC over time via git-archive snapshots (--health-trend).

Sustainability & people

  1. Sustainability — when you commit (off-hours/weekend rhythm; off-hours window via --off-hours). SPACE well-being.
  2. Ownership / bus factor — authorship share per file across full history, both churn-weighted and recency-weighted (1y half-life), plus who touched it last (solo ≥80 % = risk).

On top of the per-dimension monthly tables, gitmetry emits pre-aggregated overviews — window totals plus a per-year table (--quarterly adds a per-quarter one) — so yearly figures and YoY deltas come straight from raw counts, not from re-averaging the rounded monthly rows.

⚠️ Line metrics (added/deleted) are skewed by generated code (AI tests, docs, lock files). Most trustworthy signals: commit throughput, rework rate, function CCN, ownership.

Commit-type classification

Corrective/value-add (layer 4) and defect hotspots (layer 5) classify commits by their subject prefix: Feature/Refactoring/feat/refactor/perf → value, Fix/revert → fix, Hotfix → hotfix, Chore/Docs/test/build/ci/style → other. Reverts (git's auto-generated Revert "…" or a revert: prefix) stay in the fix bucket but are also counted separately, so the report can flag undo churn on its own. Conventional-Commits scope and the breaking marker are stripped first (feat(api)!:feat), so both the golemos convention and full Conventional Commits classify correctly. Any unknown prefix (or a subject with no Type: prefix) falls to other. If your repo uses a different convention, those two layers will under-count; the other eight don't depend on commit messages.

Development

pip install -e ".[dev]"# pytest + ruff
ruff check .# lint
pytest # run the unit tests (tests/)

The tests cover the pure, git-free helpers (commit-type classification, multi-language test-file detection, percentile math, path filtering, date arithmetic) plus an integration suite that builds a throwaway repo. CI runs ruff + pytest on Python 3.9 / 3.11 / 3.12 — see .github/workflows/ci.yml.

License

MIT © 2026 Vojtěch Žoha

About

Your private developer-efficiency report from git history — 11 dimensions (DORA / SPACE / CodeScene), local & read-only, narrated by an LLM.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages