スキップしてメイン コンテンツに移動

【Day 35】巨大バイナリ・DLL・画像管理の決定版(Git LFS)

Day 35 アイキャッチ
▲ 【Day 35】巨大バイナリ・DLL・画像管理の決定版(Git LFS)
👨‍🏫
皆さん、こんにちは! 本講座の専任講師です。
前回のDay 34では、WindowsとLinuxの差異に起因する「大文字・小文字ファイル名変更トラブル」のメカニズムと、安全な git mv の作法を学びました。
続く本日のDay 35は、第7部「Windows & C# (.NET) 固有の落とし穴完全制覇」の第3弾――
リポジトリの巨大化・クローン激重問題を解決する【巨大バイナリ・DLL・画像管理の決定版(Git LFS)】を徹底攻略します!
「数GBのインストーラーや画像アセット、ONNX機械学習モデル、古い社内DLLをGitにコミットしたら、git clone に30分以上かかるようになって全員のPCが悲鳴をあげている…!」
「VSSやSVNを使っていた30年前は、100MBのバイナリを普通にコミットしても平気だったのに、なぜGitだとこんなに重くなるのか…!?」
そんな疑問や絶叫を抱えたことはありませんか?
Gitはテキストの差分管理には最強ですが、巨大バイナリに対しては構造的な弱点を持っています。
しかし、公式の拡張機能 Git LFS(Large File Storage) を導入すれば、リポジトリを羽のように軽く保ったまま、大容量ファイルを安全・快適に運用できます。
本講義で、LFSの内部メカニズム(ポインタファイル参照)から実践的な導入・運用手順まで完全マスターしていきましょう!

① なぜGitはバイナリに弱いのか?(Git vs SVN)

「以前使っていたSVN(Subversion)では、大容量の画像やコンパイル済みDLLをコミットしてもリポジトリが爆発することはなかった。なぜGitに移行した途端、こんなにリポジトリが重くなるのか?」
これは、長年集中型バージョン管理システムに慣れ親しんだエンジニアが最も直面しやすい疑問の一つです。

なぜGitはバイナリに弱いのか?(Git vs SVN)
▲ 【図解①】なぜGitはバイナリに弱いのか?(全履歴まるごと保持の落とし穴)

決定的な違い:「中央サーバーのみ保持」 vs 「全員が全歴史を保持」

その理由は、集中型(SVN)と分散型(Git)の根本的なアーキテクチャの違いにあります。

  • 集中型(SVN / VSS): 過去の全履歴はすべて中央サーバーにのみ保管されます。開発者がチェックアウトするのは「最新リビジョン(または指定したリビジョン)の作業コピー」だけです。過去にどれほど巨大なファイルが何十回更新されていようと、ローカルPCには最新の1ファイル分しか落ちてきません。
  • 分散型(Git): git clone を実行した瞬間、リポジトリの「創世記から現在に至るすべてのコミット履歴・全ファイル」がローカルの .git フォルダに丸ごとダウンロードされます。
🚨 バイナリファイルは「差分圧縮」が効かない!

Gitはテキストファイル(C#コード等)であれば、変更行だけを効率よく差分圧縮(Packfile)して保持します。
しかし、ZIPファイル、画像(PNG/JPG)、動画、コンパイル済みDLLなどのバイナリファイルは、1バイトでも変更されると中身全体が別データとみなされ、差分圧縮がほとんど効きません。
つまり、「100MBのバイナリを10回更新してコミットすると、リポジトリの容量は単純に1GB増加」し、チーム全員が新規クローンするたびにその1GBを毎回強制ダウンロードさせられる羽目になります!

② Git LFSの画期的な仕組み(ポインタファイルと外部退避)

この「全歴史を全員が丸ごと抱え込む」というGitの宿命的な弱点を克服するために開発されたのが、オープンソースの拡張機能 Git LFS(Large File Storage) です。
Git LFSの設計思想は極めてシンプルかつエレガントです。

Git LFSの仕組み(ポインタ参照と外部退避)
▲ 【図解②】Git LFSの画期的な仕組み(ポインタ参照と外部ストレージ分離)

Git本体には「わずか百数十バイトのポインタ」だけを記録

Git LFSを有効にすると、巨大なバイナリファイルの実体はGitリポジトリ(.git)には保存されず、専用の外部LFSストレージ(GitHub LFSサーバー等)へ直接アップロードされます。
そして、Gitリポジトリ本体の中には、その実体を指し示す「ポインタファイル(わずか百数十バイトの極小テキスト)」だけがコミットされます。

# Gitリポジトリ内に実際に記録されるポインタファイルの中身(例: model_weights.onnx)
version https://git-lfs.github.com/spec/v1
oid sha256:4d7a282a51f1273ab929b818ec7548d9ac10ba5cb14202b803bae110c659d7b3
size 524288000 # 実体は500MBだが、Gitが持つのはこの3行(約130バイト)のテキストだけ!

開発者がブランチを切り替えたりチェックアウトしたりすると、Git内部のフィルタフック(Smudgeフィルタ)がポインタファイルを検知し、LFSキャッシュから作業フォルダへ必要な実体ファイルだけを瞬時に展開します。
過去の履歴にある何十世代もの巨大実体はローカルに落ちてこないため、リポジトリ本体は常に数MB〜数十MBという超軽量な状態を維持できるのです!

③ 実践!Git LFSの導入・追跡・コミット(基本3ステップ)

それでは、Windows / C#環境でGit LFSを導入し、実際にファイルを追跡・コミットする手順を実践していきましょう。
Git for Windowsを通常インストールしていれば、Git LFSのコマンドは既に同梱されています。

Git LFSの導入・追跡・コミット手順
▲ 【図解③】Git LFSの導入・追跡設定・コミットの3ステップ

ステップ1: 環境全体でGit LFSを有効化する(初回1回のみ)

まずPC環境全体に対して、GitがLFSのフック処理を自動実行できるように初期設定を行います。

# PC全体(グローバル)でGit LFSフックを有効化
$ git lfs install
Git LFS initialized.

ステップ2: LFSで追跡したいファイル形式(拡張子・パス)を指定する

次に、リポジトリ内でLFS管理下に置きたいファイル形式を git lfs track コマンドで指定します。

# 大容量ZIPファイルや動画、機械学習モデルを指定
$ git lfs track "*.zip"
$ git lfs track "*.onnx"
$ git lfs track "Assets/LargeVideos/**"

# .gitattributes が自動生成・更新されていることを確認
$ git status
Untracked files:
  .gitattributes
💡 .gitattributes に何が書かれているのか?

git lfs track "*.zip" を実行すると、リポジトリ直下の .gitattributes に以下の行が自動追加されます:
*.zip filter=lfs diff=lfs merge=lfs -text
前回の改行コード講座でも登場した .gitattributes が、ここでも大活躍しています! このファイルこそが「どの拡張子をLFSとして処理するか」をチーム全員で共有するための命綱です。

ステップ3: .gitattributes と対象ファイルをコミット&プッシュ

設定ファイルである .gitattributes と、追跡対象の巨大バイナリを通常通りコミット&プッシュします。

# .gitattributes とバイナリファイルをステージング
$ git add .gitattributes model_weights.onnx

# コミット実行
$ git commit -m "feat: 機械学習モデルをGit LFS管理として追加"

# リモートへプッシュ(実体はLFSサーバーへ、ポインタはGitリポジトリへ自動アップロードされる)
$ git push origin main
Uploading LFS objects: 100% (1/1), 500 MB | 25 MB/s, done.
Writing objects: 100% (3/3), 420 bytes | 420.00 KiB/s, done.
🔍 便利な確認コマンド: git lfs ls-files

現在どのファイルがGit LFSによってポインタ管理されているかを確認したいときは、git lfs ls-files を実行します。OIDハッシュとファイル名が一覧表示されれば、正常にLFS管理下に入っています。

④ C# (.NET) 開発現場におけるGit LFS運用の3大鉄則

Git LFSは非常に強力ですが、運用ルールを定めずに安易に導入すると、思わぬ落とし穴や追加課金のトラブルに見舞われます。
特にC# / Windows開発現場で必ず徹底すべき「3大鉄則」を押さえておきましょう。

C#開発現場におけるGit LFS運用の3大鉄則
▲ 【図解④】C#開発現場におけるGit LFS運用の3大鉄則と注意点

鉄則①: 再配布可能なDLLはLFSではなく「NuGet」で管理せよ!

C#開発現場で最も多い失敗が、「外部ベンダーから提供された巨大DLL」や「社内共通ライブラリのDLL」をすべてGit LFSに突っ込んでしまうことです。
ライブラリの依存関係管理は、Git LFSの役割ではなくパッケージマネージャー(NuGet / Azure Artifacts / GitHub Packages)の役割です!

  • 外部DLLや社内共通ライブラリは .nupkg パッケージ化してプライベートNuGetフィードへ公開する。
  • プロジェクト側では PackageReference として参照し、コンパイル成果物(bin/ や obj/)は .gitignore で徹底的に除外する。
  • Git LFSで管理すべきもの: インストーラー用リソース、大型画像・3Dモデル・音声アセット、機械学習モデルなど「NuGet化に適さない固定の大容量アセット」に限定する。

鉄則②: ファイルを追加する「前」に必ず git lfs track せよ!

「先にファイルをコミットしてしまってから、後で慌てて git lfs track を実行した」というケースが頻発します。
しかし、過去に一度でもGit本体へコミットされたバイナリファイルは、リポジトリの全履歴(.git)に永久に残り続けます!
後から git lfs track を設定しても、今後の変更がLFSになるだけで、過去の肥大化した履歴は消えません。

💡 すでにコミットしてしまった場合の救済コマンド

もし過去のコミット履歴に巨大ファイルが混入してしまった場合は、Git LFS公式のマイグレーションコマンド git lfs migrate import --include="*.zip" を使用して、過去の全履歴をポインタファイルへ一括書き換える作業が必要になります(※コミットハッシュがすべて再計算されるため、チーム全体での周知が必須です)。

鉄則③: GitHub LFSの「容量枠・帯域制限」を常に監視せよ!

GitHubでは、無料プランおよび有料プラン(Pro/Team)にかかわらず、リポジトリあたりのLFS無料枠は「ストレージ1GB、月間データ転送帯域1GB」に制限されています。
もしCI/CD(GitHub Actions)で毎回クローン時に500MBのLFSファイルをダウンロードしていると、わずか2回のビルドで月間1GBの帯域上限に達し、LFSのダウンロードが停止してCIが突然全滅する事故が起きます!

  • GitHub Actionsでの対策: actions/checkout で lfs: false(デフォルト)のままにし、ビルドにバイナリが必要なワークフローでのみ git lfs pull を実行する。
  • CIキャッシュの活用: 頻繁にダウンロードしないよう、ダウンロード済みLFSオブジェクトを Actions Cache で永続化する。
  • 必要に応じたデータパック購入: 業務で日常的にGB単位のファイルを扱う場合は、Organizationの設定で「LFS Data Pack(月額$5/50GB)」をあらかじめ購入しておく。

📌 本日のまとめと最重要ポイント

  • Gitは「全員が全歴史を丸ごと保持する」ため、バイナリの肥大化に極めて弱い!
  • Git LFSは「ポインタ参照(百バイト)」と「外部専用ストレージ」を分離してリポジトリの爆速化を実現する!
  • 導入は簡単3ステップ: git lfs install → git lfs track → .gitattributes と一緒にコミット!
  • C#ライブラリDLLはLFSではなく「NuGet」で配る! bin/objは .gitignore を徹底せよ!
  • 巨大ファイルを追加する「前」に track せよ! GitHub LFSの帯域枠(月1GB)に注意せよ!
次回予告

【Day 36】Windowsの最大パス長制限(260文字問題 / core.longpaths)

「ディープなフォルダ階層や長大なファイル名で Filename too long エラーが発生してクローンできない…!」
Windowsの伝統的な260文字制限の壁を打ち破る core.longpaths 設定とOSレジストリ設定を徹底解説します! 次回もお楽しみに!

コメント

このブログの人気の投稿

【Perfume】Perfume 3rd Tour 「JPN」さいたまスーパーアリーナに行って参りました~

Perfume 3rd Tour 「JPN」1月28日、29日の2daysで参戦して参りました。 ファンクラブ会員の選考抽選会に28日、29日の両日で申し込んでいたんですが、両方とも当選していたという嬉しい誤算。 仕事だぁ、なんだかんだと紆余曲折ありまして28日の参戦は危ぶまれていたのですが、なんとかかんとか28日は40分遅刻しながらも参戦、29日はフル参戦する事が出来ました(∩´∀`)∩

Perfume、2025年末で“コールドスリープ(活動休止)”へ──東京ドーム2daysの記録と、公式・各界・ファンの声

  1) 公式発表・基本情報 活動休止(コールドスリープ)を正式発表 2025年9月21日、公式サイト「 Perfumeより 」で、2026年から一度コールドスリープに入ると発表。再始動の意思(“新しいPerfume”として戻る)も明記。 Perfume Official Site 今後の運用告知(配信・上映など) 同21日付の「 今後のPerfumeに関して 」で、9/23(火・祝)東京ドーム公演の LIVESHIP全世界生配信 および 全国ディレイビューイング 決定を案内。特設サイトも併記。 Perfume Official Site +1 公式グッズ **「Perfume Calendar 2026」**発売決定(B2壁掛け/表紙+2カ月1枚×6枚+ポスター)。テーマは“フルーツ”。 Perfume Official Site 2) 東京ドーム2days(9/22・23)要点 公演タイトル: ZO/Z5 Anniversary “ネビュラロマンス” Episode TOKYO DOME 。日程・開場/開演・会場・物販等の実務情報は特設で公開。 Perfume Official Site 9/23公演を世界配信(LIVESHIP) /ディレイビューイング実施。 Perfume Official Site 海外向け報道(英語)も「 indefinite hiatus 」として広く配信。 The Times of India 国内英字メディアも速報。 朝日新聞 3) 現地レポ( メリ爺 )から見える空気 あなたの現地記録(9/24公開)を、ファクトと現場情景の両面で反映: 両日参戦 。22日は アリーナ 、23日は 1階席から俯瞰 。前日の発表を受け、開演前のザワつき→MC後に“いつもの一体感”へ。開演は22日 18:45 頃。オープニングは**P³ツアー東京ドーム(2020/2)**と同趣向で“回収”の演出。 メリ爺のゲーム万歳 MC所感 :解散ではなく前向きな休止で不安を和らげる内容。 かしゆか の涙、 のっち の気丈さ、 あ〜ちゃん の思い出語り──3人の結束と「 また戻る 」約束が強く刻まれた。 メリ爺のゲーム万歳 体感時間 : “3時間弱”級のボリューム ながら“過去一...

ニンテンドースイッチでオンラインゲームを遊ぶには?

モンスターハンターライズが発売になって、家族でモンハン楽しみたい人が増えたみたいですね。 某ブログの検索キーワードを調べると、モンハンを家族でやるにはどうしたらいいのか?を調べている人が沢山いるのがわかります。 ※これでも一部  家族で協力するにはSwitch2台、ソフトも2つ購入する必要があります。 1台のスイッチでは遊べませんし、ソフト1つでも遊べません。 でも、1台のスイッチで別々アカウントがあれば交代で遊ぶこともできますよ。セーブデータもしっかり分かれます。 Switchのオンラインゲームを家族で遊ぶ方法については以下の記事にまとめてますのでよろしければ参考にしてみてくださいね。 家族でモンスターハンターライズDL版のオンラインプレーを楽しむ方法