Git Blameが「嘘つき」になるとき
深夜2時、本番サーバーの決済モジュールでロジックエラーが発生しました。私は画面に釘付けになりながら、値引き計算ロジックを最後に修正したのが誰かを探しようとしていました。お決まりのコマンドを打ち込みます:git blame src/services/payment.js。
しかし、表示された結果に強い苛立ちを覚えました。ファイルの200行すべてに、…私自身の名前が表示されていたのです。コミットメッセージにはただ一言:“chore: run prettier for the whole project”(Gitの履歴を「ゴミの山」にしないためにプロジェクト全体にPrettierを適用)。
先週、プロジェクトを整理するためにPrettierを実行したのですが、図らずもその操作がすべての行の作成者名を私の名前に「上書き」してしまっていたのです。2年前の重要なロジックの真の作成者が隠されてしまいました。結局、元のコミットを見つけ出すために、さらに30分かけてgit log -pを遡る羽目になりました。数千ものファイルがあるプロジェクトなら、これは生産性における大惨事です。
幸いなことに、Gitにはこのノイズを処理するための非常に優れた機能があります:--ignore-revです。
Git Blameの履歴を整理する3つの方法
PrettierやBlack (Python)、またはLinterなどのツールが自動的にフォーマットを変更すると、コードの履歴が乱れます。以下は、git blameの清浄さを取り戻すために私が試した方法です。
1. キャレット記号(^)を使って手動で追跡する
最も簡単な方法は、フォーマット変更コミットが行われる直前の時点でGit blameを実行することです:
bash
git blame <commit-hash>^ -- <file-path>
メリット: 設定不要ですぐに使える。
デメリット: そのファイルが一度しかフォーマットされていない場合にのみ有効。5〜6回のコードクリーンアップを経ている場合、手動で何度も遡るのは非常に面倒です。
2. コマンドライン引数で特定のコミットを除外する
Gitに無視させたいハッシュ値を直接指定できます:
bash
git blame --ignore-rev <commit-hash> <file-path>
メリット: 特定のコード箇所を素早く確認したいときに便利。
デメリット: 長いハッシュ値を覚えるのは不可能です。さらに重要なのは、同僚がこの恩恵を受けられないことです。
3. .git-blame-ignore-revsファイルを使用する(推奨)
これが最もプロフェッショナルな方法です。フォーマット変更のみを含むコミットの「ブラックリスト」を作成し、Gitにそれらを永続的に無視するよう設定します。
なぜチーム全体で設定ファイルを使うべきなのか?
長年メンテナンスされているレガシープロジェクトに携わる中で、無視リストをリポジトリに保存することには大きなメリットがあると感じています:
- データの整合性: チームの全員が追跡時に同じ「真の作成者」を見ることができます。
- プラットフォームのサポート: GitHubやGitLabはこのファイルを読み取って、ブラウザ上でも正確なblameを表示することをサポートしています。
- メンテナンスの容易さ: 大規模なリファクタリングがあった際、ハッシュ値をファイルに1行追加するだけで済みます。
これはプロジェクト履歴にインテリジェントなフィルターを作成するようなものです。コードの「歴史的事実」を保護し、責任の所在を確認したりコンテキストを知る担当者を探したりする際の不要な誤解を防ぎます。
詳細な導入手順
ステップ1:フォーマット変更コミットのハッシュ値を見つける
logコマンドを使ってコードクリーンアップのコミットを抽出します。例:
bash
git log --oneline --grep="prettier"
例えば、a1b2c3d4 と e5f6g7h8 という2つのハッシュ値が見つかったとします。
ステップ2:.git-blame-ignore-revsファイルを作成する
プロジェクトのルートディレクトリにこのファイルを作成します。内容は以下のようになります:
# Prettier v2.0によるプロジェクト全体の再フォーマット
a1b2c3d4e5f6g7h8i9j10k11l12m13n14o15p16q
# インデントの修正(リンター)
e5f6g7h8i9j10k11l12m13n14o15p16q17r18s19t
ヒント:絶対的な正確性を期すために、完全なハッシュ値(40文字)を使用してください。
ステップ3:Git設定を有効にする
以下のコマンドを使用して、git configにこのファイルの存在を知らせる必要があります:
bash
git config blame.ignoreRevsFile .git-blame-ignore-revs
個人のPC上のすべてのプロジェクトに適用するには、--globalフラグを追加します。ただし、プロジェクトごとにコミットリストは異なるため、ローカル設定(プロジェクト単位)が最適です。
ステップ4:同僚と共有する
.git-blame-ignore-revsファイルをリポジトリにコミットします。他のメンバーが自分で設定コマンドを打たなくて済むように、package.jsonのpost-installスクリプトに追加するか、Husky hookを使用することをお勧めします。これにより、プロジェクトをクローンした全員が標準のblameフィルターを利用できるようになります。
実際の効果
最初のpayment.jsファイルに対して、もう一度blameコマンドを実行してみましょう:
bash
git blame src/services/payment.js
今度は、Gitが自動的にPrettierコミットを「透過」して表示します。2022年にロジックを書いた同僚の名前が再び現れるはずです。GitHubのインターフェース上でも、“Ignoring revisions listed in .git-blame-ignore-revs”(.git-blame-ignore-revsにリストされたリビジョンを無視しています)という通知が表示されます。
重要な注意点:いつ無視すべきではないか?
大きな力には大きな責任が伴います。無視リストに入れるのは、純粋にフォーマット変更のみのコミットに限定してください。
もし、あるコミットがフォーマットを修正すると同時に、ついでに小さなバグも修正している場合、絶対にそれを無視してはいけません。そのコミットを無視してしまうと、バグ修正の痕跡が消えてしまいます。その結果、最新の変更について全く知らない、より古い作成者にたどり着いてしまうことになります。
私の経験則はこうです:フォーマット変更のコミットとロジック変更のコミットは常に分けること。決して混ぜてはいけません。もし混ぜてしまった場合は、ignore-revで隠そうとするのではなく、そのコミットを履歴に残しておくことを受け入れてください。
手順のまとめ
- 履歴のノイズとなっているコミットのハッシュ値を取得する。
- それらを
.git-blame-ignore-revsファイルに保存する。 git configコマンドを実行してフィルターを有効にする。- チーム全体で同期するために、ファイルをコミットしてプッシュする。
このテクニックを使えば、深夜のデバッグ作業のストレスが少し軽減されるはずです。Git をすばやく直感的に管理できるツールなどと組み合わせることで、リンターツールによる無機質なコード行にイライラする代わりに、本当に質問すべき相手をすぐに見つけることができます。

