Most definitions of code churn are vague enough to be useless and most measurements of it are line counts in disguise. Here is the metric done properly: what to count, what the healthy ranges are, and what it reveals.
Take two snapshots of a codebase — two releases, two dates, base and head of a pull request. Classify every changed statement into three piles: added (new statements), deleted (removed statements), and changed (statements edited in place). Total churn is the sum. Two ratios matter as much as the volume: REWORK, the share of churn spent editing what already exists, and its complement REP_CHURN, the share that was replacement.
Line-based churn lies. Reformat a file — change nothing — and a line counter reports dozens of lines of "churn" where the truth is zero changed statements. Measured at the level of logical statements (LLOC), a pure reformat scores exactly 0, and a one-statement behavioural change scores exactly 1. If a churn number is going to gate a merge or appear in front of an auditor, it has to be built on statements.
Measured across 136 of the largest public codebases, 2010–2026 (every figure reproducible from published commit hashes):
Volume finds the hotspots — where change concentrates, risk concentrates. Shape characterises the process — a codebase whose REWORK falls out of its own historical band has changed how it is developed. And per-file classification turns a release diff into an audit record: what changed, where, by how much, reproducible by anyone from the same two hashes.
CodeDelta measures churn at statement level across 43 languages, from a CLI, CI pipelines or a GitHub Action on every pull request — proven on single scans up to 43.5 million lines. Run it on your own repository, or start with the papers — the method and every benchmark above are published to be re-run, not believed.