All articles

Why commit counts mislead, and what to measure instead

Commit volume is the easiest engineering metric to collect and the easiest to game. Here is what it actually measures, where it breaks, and the estimate we use in its place.

DevGhost Team · Published

Every engineering dashboard starts in the same place: commits per developer, per week. It is the one number every git host hands you for free. It is also the number most likely to send a team in the wrong direction.

This is not an argument for measuring nothing. It is an argument for measuring the thing you actually care about — how much engineering effort went into the codebase — instead of the thing that happens to be easy to count.

What a commit count actually measures

A commit is a save point. Nothing in git says a commit must correspond to a unit of work, a feature, or an hour of thought. What a commit count measures is how often a developer chooses to write to history, and that is a habit, not an output.

Two developers can ship the same feature with wildly different commit counts:

  • one commits after every passing test, ending the week with 60 commits;
  • one rebases the branch into three clean commits before opening the pull request.

The second developer did not do less work. They did the same work and then spent additional effort making the history readable for everyone who comes after them. A commit-count dashboard penalizes exactly that.

The moment a metric becomes a target, people optimize the metric. With commits, the optimization is trivial and invisible: commit more often. Nothing about the product improves.

Where it breaks in practice

Squash merges erase the signal entirely

If your team squash-merges pull requests, the entire branch collapses into one commit attributed to whoever pressed the button. A two-week feature and a typo fix are now indistinguishable — both are one commit. Any team on a squash workflow is measuring their merge policy, not their engineering.

Line counts do not rescue it

The usual fix is to switch to lines changed. That is worse. Lines changed rewards verbosity, punishes deletion, and treats a generated lockfile as a month of work:

Change Lines Actual effort
Regenerate pnpm-lock.yaml +4,120 / −3,987 seconds
Delete a dead subsystem −2,400 days of tracing callers
Fix an off-by-one in a scheduler +1 / −1 possibly a week

The third row is the one that matters, and it is the one both metrics score as zero.

Vendored and generated code drowns the real work

A single npm install or a checked-in migration can outweigh every hand-written change in the same period. Unless generated content is identified and excluded, the metric mostly tracks tooling noise.

What to measure instead

The honest question is not "how many changes were made" but "how much engineering effort would it take to produce this codebase". That is a different quantity, and it has to be estimated rather than counted.

DevGhost estimates it per change, using the properties of the change itself rather than its size:

effort(change) = f(
  novelty,          # new logic vs. mechanical edit
  structural depth, # how far the change reaches into the system
  context load,     # how much surrounding code must be understood
  generated?        # excluded when the content is machine-produced
)

Two constraints keep the result grounded:

  1. A per-change ceiling. No single change can absorb more effort than a developer could plausibly have spent on it, so one large refactor cannot distort a quarter.
  2. A per-day ceiling. Effort is spread across the days a developer could actually have worked, never stacked into a single date because that is when the commit landed.

The result is comparable across squash and merge workflows, across verbose and terse committers, and across languages — because none of those things change how much thinking a change required.

How to read the estimate

Treat it as an order of magnitude, not a timesheet. It answers questions that commit counts cannot:

  • Which parts of the system consumed effort that nobody planned for?
  • How much of last quarter went into work that is no longer in the codebase?
  • Where is the gap between where the team spent time and where the roadmap said it would?

Those are the questions worth having a number for. "Who committed most this week" is not one of them.

Further reading