CLI tool
asottile/git-code-debt avatar
asottile/git-code-debt

git-code-debt turns commit history into a dashboard of code debt

A dashboard for monitoring code debt in a git repository.

620 stars36 forksPythonMIT

At a glance

What is it?
git-code-debt is a small Python tool that walks a git repository, counts things like lines added per commit, and serves the result as a dashboard. It is a reporting aid for a human reader, not a metric with a universal definition.
Who is it for?
Adopt git-code-debt when you want a visible trend of code churn across a repository and you are willing to write your own metric classes in Python. Skip it if you need an audit-grade debt figure, a per-developer scorecard, or a tool that works on a platform other than git.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 10 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What it counts is defined by the metric classes, not by the project

git-code-debt describes itself as a dashboard for monitoring code debt in a git repository, and that description is accurate but thin. The interesting part is where the numbers come from. The repository ships with no GitHub releases, and the last push was on 2026-10-13. The layout shows a `git_code_debt` package, a `metric_config.yaml`, a `generate_config.yaml`, an `img` directory with two screenshots labelled Index and Graph, a `sample_widget_consumer.htm` and a `testing` directory. The package therefore holds the engine, the metrics, and a small server, and the two configuration files separate what to analyse from how to analyse it. There is no hardcoded definition of debt anywhere in that list. The practical consequence is that this is a reporting instrument whose output is only as meaningful as the metric classes behind it, and a team that does not read the metric code will get numbers without context.

Two commands, a config file and a database on disk

The workflow has three parts. You write a `generate_config.yaml`, you run a generator that walks the repository and writes a database, and you run a server that reads the database and serves the dashboard. The install is a normal pip install.

bash
pip install git-code-debt

The config file names the repository to clone, the path of the generated database, and a few switches.

yaml
# required: repository to clone (can be anything `git clone` understands) even
# a repository already on disk
repo: [email protected]:asottile/git-code-debt

# required: database generation path
database: database.db

# optional: default False
skip_default_metrics: false

# optional: default []
metric_package_names: []

# optional: default ^$ (python regex) to exclude paths such as '^vendor/'
exclude: ^$

The `exclude` key is a Python regular expression applied to paths, and the comment gives the shape of a useful value, excluding something like `^vendor/`. The `repo` value is deliberately flexible: anything `git clone` understands works, including a repository that already exists on disk, which means you can point the tool at a local checkout and avoid a network round trip. The two entry points then do the work.

bash
# Generate code metric data (substitute your own repo path)
$ git-code-debt-generate
# Start the server
$ git-code-debt-server database.db

One detail worth planning around: the generator is incremental. Running it again adds data to the existing database and picks up in the git history from where data was generated previously, so a second run on the same database continues the series rather than starting over.

Metrics are Python classes, which makes the tool extensible and the bugs yours

The extension mechanism is plain Python. You create a project that depends on git-code-debt, create a package for your metrics, and add that package to `metric_package_names` in your `generate_config.yaml`. The base class for the common case is `git_code_debt.metrics.base.SimpleLineCounterBase`, which asks you two things: whether a file should be counted, and whether a line matches.

python
from git_code_debt.metrics.base import SimpleLineCounterBase


class Python__init__LineCount(SimpleLineCounterBase):
    """Counts the number of lines in __init__.py"""

    def should_include_file(self, file_diff_stat: FileDiffStat) -> bool:
        return file_diff_stat.filename == b'__init__.py'

    def line_matches_metric(self, line: bytes, file_diff_stat -> FileDiffStat) -> bool:
        # All lines in __init__.py match
        return True

There is also a `TextLineCounterBase` variant that hands you lines as text rather than bytes.

python
from git_code_debt.metrics.base import TextLineCounterBase


class XXXLineCount(TextLineCounterBase):
    """Counts the number of lines which are XXX comments"""

    def text_line_matches_metric(self, line: str, file_diff_stat: FileDiffStat) -> bool:
        return '# XXX' in line

For anything that does not fit a line counter, the parent class `DiffParserBase` exposes `get_metrics_from_stat` for yielding metrics from a commit and its file diff stats, and `get_metrics_info` for describing them. Note the `__metric__ = False` flag on that class, which excludes a base class from being reported as a metric of its own. The upside of this design is obvious: a team can express a rule the standard tools do not have. The downside is equally plain. Your metric is your code, it runs inside the generator, and a mistake in it produces a wrong chart rather than an exception, because the base class documents a generator return value with a boolean type annotation that does not match what it yields.

Why a dashboard of churn is not a debt score

Here is the honest limitation. Code debt, in the sense most teams mean it, is work deferred or complexity carried forward. What this tool measures by default is derived from diffs and lines, which is closer to churn and size. The default metric set can be skipped entirely with `skip_default_metrics: true` in the config, which tells you two things at once: there is a default set, and you can turn it off. A repository with a large vendor directory or a generated client will look busy in the graph for reasons that have nothing to do with deferred work, and the `exclude` regex exists precisely because path filtering is a routine part of using this correctly. The other limitation is scale of adoption rather than of code. There is no authentication, no multi-user notion and no notification in the documented interface. The screenshot names, Index and Graph, describe a page you open and read. This fits a single maintainer or a small team reviewing a repository periodically, and it does not fit an organisation that wants per-service debt tracked continuously in a portal.

Comparing it with a hosted analytics service on your repository host

The realistic alternative for the same job is a hosted repository analytics service, where the vendor keeps the dashboard infrastructure and the metric definitions, and you get a URL instead of a Python process. The difference in approach is where the definition lives. With git-code-debt, the metric is a class you write and a config file you check into the repository, so the meaning of the number is reviewable in a pull request and travels with the code. With a hosted service, the definition is the vendor's, it changes when the vendor ships, and your only lever is which view you look at. The trade runs the other way too. The hosted option needs no local checkout, no `pip install`, no database file and no server process to keep alive, and it costs money and sends repository metadata to a third party. git-code-debt is a local process reading a local clone and writing a local SQLite-style database file, which is why it suits an engineer who wants a private number rather than a service that wants a subscription.

Licence, packaging and what the repository does not promise

The licence is MIT, which is permissive: you can use it inside a proprietary internal tool without any obligation to publish your work, though the copyright notice must travel with copies and substantial portions. Packaging is minimal. The `setup.py` is three lines that call `setuptools.setup()` with no arguments, so the real metadata lives in `setup.cfg`, and the presence of `tox.ini`, a `requirements-dev.txt` and a `.pre-commit-config.yaml` points to a project developed with the standard Python linting and test tooling rather than a packaged application. The repository has no GitHub releases, so version pinning comes from the package index rather than from release tags, and there is no changelog in the top-level listing to tell you what changed. The README also does not document a deployment story for the server, so how you expose the dashboard to other people, and what to do when the database is regenerated while someone is looking at the graph, is left to you. The screenshot file named `sample_widget_consumer.htm` hints at an embedding path, but the documentation does not describe it.

Editorial conclusion

Adopt git-code-debt when you want a visible trend of code churn across a repository and you are willing to write your own metric classes in Python. Skip it if you need an audit-grade debt figure, a per-developer scorecard, or a tool that works on a platform other than git. Before you rely on the dashboard, run git-code-debt-generate over a repository you already understand and check that the default metric set matches what your team actually considers debt.

Frequently asked questions

How do I install and run git-code-debt?

Install it with `pip install git-code-debt`, write a `generate_config.yaml` naming the `repo` and `database`, then run `git-code-debt-generate` followed by `git-code-debt-server database.db`.

How do I write a custom metric for git-code-debt?

Create a Python package that depends on git-code-debt, subclass `SimpleLineCounterBase` or `TextLineCounterBase`, and list the package in `metric_package_names` in your `generate_config.yaml`. More complex metrics can extend `DiffParserBase`.

Does running git-code-debt-generate again overwrite my data?

No. Adding data to the database is as simple as running generate again, and the tool picks up in the git history from where data was generated previously.

How do I exclude vendored code from the git-code-debt metrics?

Set the `exclude` key in `generate_config.yaml` to a Python regular expression. The config comment gives `^vendor/` as an example of a path pattern to exclude.

Official sources

  1. asottile/git-code-debt on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/asottile-git-code-debt.svg)](https://hysenlabs.com/projects/asottile-git-code-debt)

Was this useful?