git-sizer の使い方:肥大化して重くなった Git リポジトリを救出する

Git tutorial - IT technology blog
Git tutorial - IT technology blog

なぜあなたのGitリポジトリは「鉛のように」重いのか?

小さなプロジェクトを git clone するのに15分もかかったり、git fetch のたびにコーヒーを淹れに行く時間があるような状況に陥ったことはありませんか?私は以前、実際のソースコードはわずか120MBしかないのに、.git ディレクトリ が8GBまで膨れ上がったリポジトリを扱ったことがあります。

実のところ、原因が書いたコード自体にあることは稀です。犯人は、意図せず履歴(history)に放り込んでしまったものたちです。1GBの dump.sql ファイル、誤ってコミットされた node_modules フォルダ、あるいは二度と使われない何千もの古いタグなどです。Gitは非常に記憶力が良いため、対策を講じない限り、それらのミスを永遠に保持し続けます。

フォルダを一つずつ手動で調べる代わりに、私はよく git-sizer を使います。これは、リポジトリの負荷となっている要素を特定 し、診断してくれる「強力な武器」です。

Git-sizerとは何か、なぜ特別なのか?

通常、容量を確認するには du -sh .git コマンドを使いますが、この大まかな数字だけでは、なぜリポジトリが重いのかは分かりません。

git-sizerの利点は、Git内部の構造(objects、trees、blobs、commits)を分解して分析できる点にあります。以下の重要な指標を算出します:

  • コミットの総数と単一コミットの最大サイズ。
  • 容量を占有している上位のblob(ファイル)リスト。
  • ディレクトリツリーの深さ(tree depth)。
  • 存在するリファレンス(ブランチやタグなど)の数。

このツールは、リポジトリを0から30個以上の星(★)で評価します。星が多いほど、GitHubなどのサーバーから拒否されたり、同僚のPCでの動作が極端に遅くなったりするリスクが高まります。

git-sizerのインストール

Goで書かれた単一の実行ファイルなので、インストールは非常に迅速です。Homebrewを使っているmacOSユーザーなら、以下のコマンドを実行するだけです:

brew install git-sizer

WindowsまたはLinuxをお使いの場合は、GitHubのReleasesページからビルド済みバイナリをダウンロードしてPATHを通してください。また、すでにGoがインストールされている環境なら、以下のコマンドで直接インストールすることも可能です:

go install github.com/github/git-sizer@latest

実践: 「問題あり」なリポジトリを分析する

まずは、肥大化したリポジトリのディレクトリに移動し、以下のコマンドを実行します:

git-sizer --verbose

--verbose パラメータを付けると、具体的なファイルの詳細が表示されます。以下は、私が以前最適化したレガシープロジェクトの実際の結果です:


| Name                         | Value     | Level of concern               |
| ---------------------------- | --------- | ------------------------------ |
| Overall repository size      |           |                                |
| * Total size of blobs        |  1.52 GiB | *                              |
| * Total size of trees        |  85.2 MiB |                                |
| * Total size of commits      |  12.4 MiB |                                |
|                              |           |                                |
| Biggest objects              |           |                                |
| * Maximum blob size          |   450 MiB | ******************** (20 stars)|
| * Maximum tree size          |   1.2 MiB | **                             |
|                              |           |                                |
| History structure            |           |                                |
| * Maximum commit depth       |    15,402 | ****                           |

Maximum blob size に20個の星が付いているのは、危険信号です。これは、履歴の中に少なくとも450MBの巨大なファイルが隠れていることを示しています。現在のコミットでそのファイルを削除したとしても、Gitは過去へのチェックアウトを可能にするために、.git 内にそれを保持し続けます。

犯人を突き止める

巨大なファイルがあることが分かったら、次のコマンドを使ってそのファイル名を特定します:

git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -10 | awk '{print $1}')"

このコマンドは、git-sizerからのIDを実際のファイル名と照合します。あるプロジェクトでは、開発者が誤って600MBの video_demo.mp4 をコミットしていたのを見つけました。ファイル名が特定できれば、クリーンアップ作業は非常にスムーズに進みます。

分析後の最適化方法

単に rm file をして git commit するだけでは、この問題は解決しません。Gitの履歴全体を「手術」する必要があります。

1. git-filter-repo を使用する(推奨)

これは、古くなった git filter-branch よりもモダンで安全、かつ高速なツールです。履歴から巨大なファイルを完全に削除するには、以下を使用します:

git filter-repo --path path/to/large/file --invert-paths

重要な注意点: この操作は過去のコミットのハッシュ値を変更します。クリーンアップ後は、チーム全員が新しいリポジトリを再度クローンし直すように周知する必要があります。

2. 不要なリファレンスを掃除する

もしgit-sizerが Total number of references セクションで警告を出しているなら、リポジトリに不要なブランチやタグが多すぎます。メインブランチにマージ済みのブランチを削除するには、以下のコマンドを実行します:

git branch --merged | grep -v "\*" | xargs -n 1 git branch -d

リポジトリを常に「クリーン」に保つための秘訣

数GBのリポジトリを掃除するのは苦行です。同じ過ちを繰り返さないよう、私はチームに以下の3つの鉄則を課しています

  • 適切な .gitignore の設定: プロジェクト開始初日から、ログ、ビルド成果物、node_modules などの依存関係フォルダを徹底的に除外します。
  • Git LFS の活用: AIモデルや4K画像などの大きなファイルを扱う必要がある場合は、直接コミットせずに Git LFS を使用します。
  • 定期的なチェック: 3ヶ月に一度はメインブランチで git-sizer を実行し、「迷い込んだ」ファイルがないか早期発見に努めます。

このプロセスを導入した後、チームのCI/CD速度は明らかに向上しました。ビルドサーバーへのコード取得(fetch)時間は5分から30秒未満に短縮されました。

Lời kết

git-sizer は直接問題を修正するものではありませんが、潜在的な問題をすべて見透かすための「顕微鏡」です。リポジトリが重すぎてクローンできなくなるまで待つ必要はありません。ぜひ今日、git-sizer を試してみてください。驚くような結果が出るかもしれませんよ!

Share: