対応する変更履歴(VCS)メトリクス
This chapter describes the change-history metrics: the signals big-code-analysis derives from version-control history rather than from the source AST. Where the Supported Code Metrics chapter measures the shape of the code as it exists today, these metrics measure how that code got there: how often it changes, how much, by how many people, and in what kind of commits. Each section starts from the empirical paper that first connected the signal to defects, walks through how big-code-analysis computes it, and explains how to read the number in practice.
このファミリー全体は bca vcs コマンドで計算され、bca metrics --vcs の出力に付加されます。Commands → Change-history (VCS) metrics のページが、フラグ、ウィンドウ、出力形式、キャッシュを説明しています。この章が 「なぜ」 を、あちらのページが どうやって を担います。
Four framing notes:
- These metrics predict where defects cluster, not whether code is correct. The defect- and vulnerability-prediction literature consistently finds that process signals (how a file has been edited over time) out-predict product signals like size or complexity. Graves and colleagues put it bluntly in 2000: the number of times a module has been changed is a better predictor of its fault count than its length. None of these numbers measures correctness; they rank files by the probability that a bug is hiding in one.
- すべては 2 つのウィンドウで測定されます。 呼び出しごとの 1 回の履歴走査で、長期ウィンドウ(デフォルト
12mo≈ 365 日)と直近ウィンドウ(デフォルト90d)の両方についてすべてのシグナルが生成されます。直近性はジャストインタイム欠陥予測の系譜における最も強い単独シグナルであるため、全体を通じて直近の活動は古い活動より重く重み付けされます。 - 複合スコアは順序尺度であり、基数尺度ではありません。
risk_score、hotspot_score、コミットレベルの JIT スコアは温度計ではなく物差しです。意味を持つのは相対的な順位だけです。リポジトリのファイル(またはコミット)を互いに対して、あるいはそのリポジトリ自身の時間的な分布に対してランク付けしてください。絶対値を確率として読んだり、無関係なプロジェクト間で生のスコアを比較したりしないでください。 - レコードが存在しないことはゼロではありません。 追跡されていないファイルにはレコードがまったく存在せず、これはウィンドウ内の活動がゼロの追跡対象ファイルとは区別されます。計算結果としての
0.0(たとえば、常に単独でしか変更されなかったファイルの共変更エントロピーはゼロです)は実際の測定値です。
一覧
| メトリクス | 測定対象 | 最初に欠陥と結び付けた研究 |
|---|---|---|
| コミット頻度 | ファイルがどれくらいの頻度で変更されるか | Graves et al.、2000 年 |
| コードチャーン | 何行が変更されるか | Nagappan & Ball、2005 年 |
| バースト | 直近ウィンドウへの変更の集中度 | 直近性の原則(Graves、JIT の系譜) |
| 作者と所有権 | 何人の手がファイルに触れ、それがどれだけ集中しているか | Bird et al.、2011 年;Meneely & Williams、2009 年 |
| 修正・セキュリティ・リバートコミット | 是正的な変更の履歴 | Śliwerski, Zimmermann & Zeller、2005 年 |
| 経過時間と最終更新 | ファイルがいつ生まれ、いつ最後に触れられたか | ジャストインタイム欠陥予測の系譜 |
| 変更エントロピー | ファイルに触れるコミットがどれだけ 「分散」 しているか | Hassan, 2009 |
| 共変更エントロピー | ファイルの変更が波及する影響範囲がどれだけ広いか | arXiv 2504.18511, 2025 |
| 複合リスクスコア | 上記すべてのシグナルの重み付き集約 | 本プロジェクト(式 v2) |
| ホットスポットスコア | 複雑度 × 直近のチャーン | Tornhill, 2015 |
| バスファクター | ファイル集合全体での知識の集中度 | Avelino et al., 2016 |
| ジャストインタイムコミットスコア | 単一コミットの欠陥誘発リスク | Kamei et al., 2013 |
コミット頻度
最も単純な変更履歴シグナルは、ファイルにいくつの個別コミットが触れたかです。big-code-analysis はこれをウィンドウごとに commits_long と commits_recent として記録します。
このメトリクスの欠陥予測指標としての評価は、Todd Graves、Alan Karr、J. S. Marron、Harvey Siy による 2000 年の IEEE TSE 論文 Predicting Fault Incidence Using Software Change History に由来します。大規模な電話交換システムを研究した彼らは、変更履歴から導かれるプロセス指標が、コードそのもののどのプロダクトメトリクスよりも欠陥率をよく予測すること、なかでも過去の変更回数が最も強力な指標のひとつであることを見出しました。直観は単純です。誰も触れないファイルは、誰も壊していないファイルだということです。
アルゴリズム
A single history walk visits each commit reachable from the analysed ref (first-parent only by default; --full-history follows all parent links in the commit graph) and attributes it to every file it modifies. Merge commits are excluded unless --include-merges is passed, and renames are followed by default so a file’s history survives a move. The walk counts distinct commits per file per window, not diffs or hunks, so a commit that touches a file once and a commit that touches it in three hunks both count as one.
読み方
Commit frequency is a rate, so it is only meaningful relative to a baseline: this file versus its siblings, or this file this quarter versus last. A consistently high count flags a file that is under active feature development or structurally unstable; pairing it with code churn tells the two apart, since heavy churn on few commits is a different story from light churn on many.
コードチャーン
コードチャーンは変更の量です。ファイルに触れた追加行数と削除行数の合計で、ウィンドウごとに churn_long と churn_recent として記録されます。
チャーンの欠陥予測としての系譜は、Nachiappan Nagappan と Thomas Ball による 2005 年の ICSE 論文 Use of Relative Code Churn Measures to Predict System Defect Density にあります。Windows Server 2003 で検証された彼らの主要な発見は、絶対 チャーン単独では予測力が乏しい一方、ファイルサイズや変更の時間的な広がりに対する 相対 チャーンは欠陥密度を高い精度で予測する、というものです。big-code-analysis はウィンドウごとの生のチャーンをシグナルとして保持し、単一の絶対値を判定として報告するのではなく、複合スコアがそれをサイズや新しさと組み合わせられるようにしています。
アルゴリズム
For every in-window commit touching a file, the walk adds that diff’s added-plus-deleted line count to the file’s churn total for the window. Because added and deleted lines are summed, a one-line edit counts as two (one deletion, one addition): churn measures activity, not net growth.
読み方
Churn is the natural numerator for a density ratio. Churn per commit distinguishes steady editing from a few large rewrites; churn against file size recovers Nagappan and Ball’s relative measure. A file whose recent churn is high relative to its long-window churn is changing faster now than its history would predict, which is the burst signal below.
バースト
バーストは、ファイルの活動のうち直近ウィンドウに集中している割合で、commits_recent / commits_long を [0, 1] の比率として報告します。1 に近い値はファイルのコミットのほぼすべてが直近のものであることを、0 に近い値はファイルが昔は活発だったがその後静かになったことを意味します。
The signal follows from the recency principle that runs through the change-history literature. Graves and colleagues found that recent changes weigh more heavily on fault incidence than old ones, and the just-in-time defect-prediction line (see the JIT score) is built on the same observation. A file whose change history is front-loaded into the present is in active flux, and active flux is when defects enter.
読み方
バーストは単独の警報ではなく、判定の決め手(タイブレーカー)です。総履歴の少ないファイルでの高いバーストは、若く動きの速いファイルを意味します。深い履歴を持つファイルでの高いバーストは、突然目を覚ました古いファイルであり、多くの場合こちらの方が興味深いケースです。経過日数と合わせて読むことで両者を見分けられます。
作者数と所有権
関連する 2 つのシグナルが、ファイルを 誰が 変更しているかを表します。作者数(authors_long、authors_recent)は、各ウィンドウでそのファイルに触れた個別の人数を数えます。所有権(ownership_top_share、[0, 1] の比率)は、最も活発な単一の作者に帰属する編集の割合です。低いシェアは所有権が分散していることを、高いシェアは一人が支配的であることを意味します。
Both trace to empirical work on ownership and security. Christian Bird and colleagues’ 2011 FSE paper Don’t Touch My Code! Examining the Effects of Ownership on Software Quality found, on Windows Vista and 7, that diffuse ownership (many low-expertise contributors, a low top-owner share) predicts both pre-release faults and post-release failures. On the security side, Andrew Meneely and Laurie Williams’ 2009 CCS paper Secure Open Source Collaboration: An Empirical Study of Linus’ Law reported that Red Hat Enterprise Linux 4 files touched by nine or more developers were roughly sixteen times more likely to harbour a vulnerability.
アルゴリズム
Author identities are canonicalised through the repository .mailmap and counted by lowercased email, so a contributor who commits under two addresses counts once. Co-authored-by: trailers add participants. Bot identities (dependabot[bot], renovate[bot], github-actions[bot], and similar) are excluded by default so automated churn does not inflate the count. ownership_top_share is the top author’s edit count over the file’s total edits in the window.
読み方
A rising author count on a long-lived file is a knowledge-diffusion signal: more people are now obliged to understand it. The composite risk score folds this in two ways. It scales the author factor by an ownership-dilution term (1 - ownership_top_share), so the same head-count counts for more when ownership is spread thin, and it adds categorical bumps at the six- and nine-developer marks that encode Meneely and Williams’ RHEL4 thresholds. For knowledge concentration across a set of files rather than within one, see the bus factor.
修正・セキュリティ・リバートコミット
big-code-analysis は、ファイルに触れる長期ウィンドウ内の各コミットをメッセージの意図で分類し、3 つのカウントを保持します。bug_fix_commits(バグ修正キーワードに一致するメッセージ)、security_fix_commits(CVE-####、security、vuln、exploit、sanitize などに一致するメッセージ)、revert_commits(リバートまたはロールバックである件名)です。
Reading a commit’s purpose from its message is the technique introduced by Jacek Śliwerski, Thomas Zimmermann, and Andreas Zeller’s 2005 MSR paper When Do Changes Induce Fixes?, the work now abbreviated SZZ. The premise is that a file’s history of corrective change is itself predictive: a file that has needed many fixes is a file likely to need more. A security fix is a sharper signal than an ordinary bug fix, and a revert marks a change that had to be undone, a localized admission that something went wrong there.
アルゴリズム
Classification is keyword-based on the commit subject and body (see src/vcs/classify.rs). It is deliberately simple and language- and tracker-agnostic: there is no issue-tracker linkage and no blame back-tracing to the fix-inducing commit, so this is the message-classification half of SZZ, not the full algorithm. The counts are kept over the long window only.
読み方
A high bug_fix_commits count is a file that keeps needing repair. The weighted composite score combines bug-fix and security-fix counts in a log-scaled term, with security fixes double-weighted, so a file with a history of security fixes ranks above an otherwise-identical file with only ordinary bug fixes. The file-level formula does not use revert_commits; only the just-in-time commit score reads the revert classification. Because the classifier reads messages, its accuracy tracks your project’s commit hygiene: a repository with terse or templated messages will under-count.
経過日数と最終更新
2 つのタイミングシグナルがファイルの履歴を区切ります。age_days はファイルの 最初の ウィンドウ内コミットからの経過日数(長期ウィンドウを上限とする)、last_modified_days は 最新の ウィンドウ内コミットからの経過日数です。
These anchor the recency reasoning the rest of the family depends on. A small age_days marks a new file, and newly added code carries elevated risk, an observation from the just-in-time line and from Chromium’s own defect analysis, where freshly added features were disproportionately fault-prone. A small last_modified_days marks a file edited recently, which the windows already weight.
読み方
age_days の最大の用途は、リスクスコアに供給される新規ファイルトリガーです。直近ウィンドウ内で初めて観測されたファイルは小さな加点を得ます。これは、できたばかりのコードが実行やレビューを経る機会を最も持っていないことを反映しています。last_modified_days は逆方向の陳腐化の読み取りです。何か月も触れられていない高リスクファイルと、今日編集されているファイルとでは、保守上の位置付けが異なります。
変更エントロピー
変更エントロピーは、ファイルに触れるコミットがどれだけ 「分散」 しているかを測ります。ウィンドウごとに change_entropy_long と change_entropy_recent として、ビット単位で報告されます。
The metric is Ahmed Hassan’s History Complexity Metric from the 2009 ICSE paper Predicting Faults Using the Complexity of Code Changes. The idea adapts Shannon entropy to commits: for each commit, take the distribution of its churn across the files it touched and compute that distribution’s entropy in bits. A commit that touches one file scores 0; a commit that spreads its churn evenly across n files approaches log₂(n). A scattered, cross-cutting commit is harder to reason about than a focused one. Hassan reported that this change-process complexity predicts faults better than prior code-based or change-count models; later work measured file-level change entropy at a Pearson correlation up to 0.54 with defect counts on eight Apache projects (see co-change entropy).
アルゴリズム
For each commit, big-code-analysis computes the Shannon entropy H of its churn distribution across the touched files (see src/vcs/entropy.rs). Each participating file is then credited its churn share pᵢ·H of that commit (Hassan’s History Complexity Metric), and these shares are summed per file per window. A file repeatedly caught up in diffuse, multi-file changes accumulates high change entropy; a file that only ever changes in tightly focused commits stays low.
読み方
変更エントロピーは、生のチャーンが同一であっても、大きく散漫な編集の一部として 変更されるファイルと、自己完結したコミットで変更されるファイルを区別します。高い変更エントロピーは 横断的関心事 の兆候です。このファイルへの編集が、いつも多くの他ファイルを巻き込んでいるということです。これは直近ウィンドウのリスク項に加算的に入り、チャーンやコミット数の言い換えではなく補完として働きます。
共変更エントロピー
Co-change entropy measures how wide a file’s change blast radius is: how many different files it tends to change alongside. It is reported per window as cochange_entropy_long and cochange_entropy_recent, in bits.
The signal comes from the 2025 study Co-Change Graph Entropy: A New Process Metric for Defect Prediction (arXiv 2504.18511). Build a weighted graph in which two files share an edge whenever they change in the same commit, the weight being the number of shared commits. A file’s co-change entropy is the Shannon entropy of its edge-weight distribution: low when it always co-changes with the same one partner, high when its changes ripple out across many different files. The study found that adding co-change entropy to change entropy improved the area under the receiver operating characteristic curve (AUROC, a measure of ranking discrimination) in 82.5% of cases over the prior signal set across eight Apache projects.
アルゴリズム
The walk records, per commit, which in-scope files changed together and accumulates the co-change graph’s edge weights, then computes each file’s edge-weight entropy per window. Bulk-import commits touching more than 1000 files are excluded from the co-change graph, whose edge count grows with the square of commit width, though they still contribute their (linear-cost) change entropy. A computed 0.0 means the file has no co-change neighbours or only one neighbour in the window. It is a real measurement, not a missing record.
読み方
Where change entropy asks “how scattered are the commits that touch this file?”, co-change entropy asks “how many other files does touching this one drag along?”. A high value flags a file whose edits have unpredictable, far-reaching consequences: a coupling hotspot. The two entropy signals complement each other, and the risk score v2 adds both recent-window terms together.
複合リスクスコア
リスクスコアは、上記のすべてのシグナルをファイルごとの単一の数値 risk_score に集約します。これは bca vcs の主要な出力であり、ランキングテーブルのソートキーとなるフィールドです。2 つの式が用意されており、どちらも単一の risk_score_version(現在は 2)で一緒にバージョン付けされるため、下流の消費者は変更を検出できます。
重み付き式(デフォルト)
The default formula is a log-scaled weighted sum with categorical multiplicative bumps. Counts are passed through ln(1 + x) so that the difference between 10 and 20 commits matters more than the difference between 110 and 120, matching how change activity saturates:
base = 0.30 · ln(1 + churn_recent)
+ 0.25 · ln(1 + commits_recent)
+ 0.15 · ln(1 + commits_long)
+ 0.15 · ln(1 + authors_long) · (1 + dilution)
+ 0.10 · ln(1 + bug_fix_commits + 2 · security_fix_commits)
+ 0.05 · ln(1 + churn_long)
+ 0.10 · change_entropy_recent + 0.05 · cochange_entropy_recent
+ ln(1 + sloc)² / 100
risk_score = base · (1 + dev_bonus + new_file_bonus)
ここで dilution = 1 - ownership_top_share であり、dev_bonus は長期ウィンドウの作者が 9 人以上で 0.35、6 人以上で 0.15、new_file_bonus は直近ウィンドウ内で初めて観測されたファイルに対して 0.15 です。重みは、本章で引用した文献に項ごとに根拠づけられています。直近のチャーンとコミット頻度が最大の重みを持ち(Nagappan & Ball、JIT 系)、作者ファクターは所有権の希薄化でスケーリングされ(Bird et al.)、RHEL4 の開発者数しきい値で加点され(Meneely & Williams)、セキュリティ修正は 2 倍に重み付けされ、2 つの直近ウィンドウのエントロピー項は加算的に入ります(Hassan、arXiv 2504.18511)。完全な導出は src/vcs/score.rs にあります。
The size term ln(1 + sloc)² / 100 is a real contributor, not the tie-breaker its position at the end of the sum might suggest: it reaches about 0.85 at 10k SLOC and exceeds 1.0 past roughly 50k SLOC, comparable in magnitude to the churn terms. Large files are only weakly correlated with defects, but the squared-log scaling keeps size a first-class additive signal rather than letting it dominate.
パーセンタイル式
--risk-formula percentile is the alternative: each signal is re-ranked to its percentile within the analysed set, and the per-file mean of those percentiles becomes the score. This formula replaces fixed weights with relative ranks within the analysed file set. Prediction research recommends relative triggers over fixed absolute thresholds, but this score is meaningful only within one run’s file set.
読み方
The score is ordinal. Sort a repository’s files by it and look at the top of the list; that is the ranking the score exists to produce. Do not compare a raw risk_score between two repositories, and do not read its magnitude as a defect probability. To watch a single file move over time, use bca vcs trend, which re-anchors the walk at each historical point so the series reflects what the file looked like then.
ホットスポットスコア
The hotspot score is the product of a file’s complexity and its recent churn: hotspot_score = cyclomatic_sum × churn_recent. It is an Option, present only when an AST complexity figure is computed alongside the history (for example bca metrics --metrics cyclomatic --vcs), because it needs both halves. A per-function block uses the space’s own cyclomatic instead of the subtree sum, so a nested function’s complexity is not counted again in every enclosing space.
The metric is the central idea of Adam Tornhill’s 2015 book Your Code as a Crime Scene and the CodeScene tooling built on it. The argument is that complexity on its own is cheap to ignore (a complex file nobody touches costs nothing) and churn on its own is cheap too. The danger is their intersection: code that is both complicated and changing often is where defects concentrate and where developer effort is repeatedly spent. Tornhill observes that a small fraction of a codebase typically accounts for a large majority of its change activity, and the hotspot score is built to find that fraction.
読み方
リスクスコアと同様、ホットスポットの積は順序尺度です。ファイルをこれでランク付けし、大きさそのものは読まないでください。CLI は慣例として複雑度の軸にファイルレベルの cyclomatic 合計を使いますが、どの AST 複雑度の数値でも役割を果たします。このスコアの価値は 優先順位付け にあります。複雑なファイルすべての中から、現に編集されているものを浮かび上がらせます。それらは最も壊れやすく、かつ誰かの画面ですでに開かれている今こそ最も安上がりにリファクタリングできるファイルです。
バスファクター
ownership_top_share が単一ファイル 「内」 の知識集中を測るのに対し、バスファクター(トラックファクター とも呼ばれます)はそれを ファイル集合をまたいで 測ります。その離脱によってディレクトリのファイルの半分超が知識ある保守者を失うことになる、最小の開発者数です。この概念全般には Wikipedia の概説があります。big-code-analysis はこれを、リポジトリ全体、各トップレベルディレクトリ、およびその直下のサブディレクトリを対象とする vcs_aggregate オブジェクトとして出力します。
推定手法は、Guilherme Avelino、Leonardo Passos、Andre Hora、Marco Tulio Valente による 2016 年の ICPC 論文 A Novel Approach for Estimating Truck Factors のものです。各開発者の各ファイルに対する作者性は、彼らの Degree-of-Authorship ヒューリスティックでスコア付けされます。
DoA(d, f) = 3.293 + 1.098 · FA + 0.164 · DL − 0.321 · ln(1 + AC)
ここで FA は最初の作者性(開発者 d がファイル f を作成していれば 1)、DL は d の f への提供(変更)回数、AC は 「他の」 開発者による変更数です。開発者は、ファイルの最大値で正規化した DoA が 0.75(論文のしきい値)を超えるとき、そのファイルの作者とみなされます。
アルゴリズム
トラックファクターは貪欲な除去法で計算されます(src/vcs/bus_factor.rs を参照)。まだカバーされているファイルを最も多く作者として持つ開発者を繰り返し取り除き、--bus-factor-threshold(デフォルト 0.5、Avelino に準拠)を超える割合のファイルが孤児化した時点で停止し、取り除いた開発者数を報告します。集約は 1 回のウォークでスコープ内の全ファイルをカバーするため、by_directory の各エントリは各ディレクトリ配下の全ファイルを再帰的に対象として計算されます。
読み方
A bus factor of 1 means losing one person orphans the set, which is common, and correct, for a repository of mostly single-author files. Treat the number as a planning signal, not a guarantee: it is a heuristic over observed authorship within the long window, so “first authorship” means the earliest commit seen in that window, not necessarily a file’s true creation. Use it to find the directories where knowledge is dangerously concentrated and spread review accordingly.
ジャストインタイムコミットスコア
Everything above ranks files at a point in time. The just-in-time (JIT) score estimates the defect-induction risk of a single commit. A continuous-integration gate reviews that commit at check-in. bca vcs commit <commit> reports an ordinal risk_score and a per-group contributions breakdown.
特徴量グループとその符号は、Yasutaka Kamei らによる 2013 年の IEEE TSE 論文 A Large-Scale Empirical Study of Just-in-Time Quality Assurance に始まり、公開追試の Commit Guru(FSE 2015)および Shane McIntosh と Yasutaka Kamei の Are Fix-Inducing Changes a Moving Target?(IEEE TSE 2018)で確認された、ジャストインタイム欠陥予測の文献から採られています。big-code-analysis は学習済みモデルではなく静的なルールベースのスコアラーを実装しているため、プロジェクトが古びても何もドリフトしません。
アルゴリズム
5 つの特徴量グループがスコアを動かします。各グループはコミットの第一親に対して評価されます(src/vcs/jit.rs を参照)。
| グループ | 特徴量 | 方向 |
|---|---|---|
| サイズ | 追加 / 削除行数、変更ファイル数、diff ハンク数 | 大きいほど ⇒ 高リスク |
| 拡散度 | 個別のサブシステム数とディレクトリ数、コミット内変更エントロピー | 分散しているほど ⇒ 高リスク |
| 履歴 | the touched files’ priors (prior changes, distinct authors, fix counts, and their composite risk), measured before the commit | 波乱の履歴 ⇒ 高リスク |
| 経験 | 作者のそれまでのコミット数(長期・直近) | 経験が多いほど ⇒ リスクは低下(このグループは減算) |
| 目的 | メッセージの修正 / セキュリティ修正 / リバート分類 | 修正は加算、リバートは減衰 |
contributions ブロックは各グループの符号付き寄与を報告するため、消費者はコミットが 「なぜ」 その位置にランクされたかを確認できます。マージコミットはフラグ付けされ、第一親に対してスコア付けされます。ルートコミットと新規ファイルは構造上、事前値がゼロになるため、スコアはサイズと作者の経験に依拠します。これはファイル履歴のない変更に対して文献が定める通りの挙動です。素の git diff もスコア付けできます(bca vcs commit --diff)が、diff から計算できるのはサイズと拡散度のグループだけなので、その経路は意図的に部分的な partial_risk_score を出力します。
読み方
Like the file-level score, the JIT score is ordinal: rank commits by it, or compare a commit against the repository’s own commit-score distribution, but do not read the magnitude as a probability. Its intended use is a check-in gate: bca vcs commit HEAD --fail-above <N> exits non-zero when a commit scores at or above a threshold, with the threshold calibrated against your own history rather than treated as an absolute. Any change to the formula bumps a jit_score_version that is independent of the file-level risk_score_version.
次のステップ
- コマンド → 変更履歴(VCS)メトリクスのページでは、
bca vcsの呼び出し方、ウィンドウの設定、出力形式の選択、永続的な履歴キャッシュの使い方を説明しています。 - The Supported Code Metrics chapter covers the AST-derived metrics these change-history signals complement; the hotspot score in particular combines the two families.
- Python バインディング → 変更履歴(VCS)メトリクスのページでは、同じファミリーを
big_code_analysis.vcsモジュールから利用する方法を示します。