Git LFSを使ってみた: ZIPファイルで挙動を確認
はじめに
AnsibleリポジトリなどでインストーラやZIPを直接配置していると、
時間が経つにつれてリポジトリが肥大化してしまうことがある。
Git LFS(Large File Storage) を使用することでこの問題を回避できる。
Git LFS の挙動についてGitLab SaaS を使用して以下の5項目を確認した。
検証項目
| No | 確認内容 |
|---|---|
| ① | LFSでZIPファイルを管理する方法 |
| ② | LFS導入前後で同一ファイルの見え方 |
| ③ | LFSをすべての履歴に適用する |
| ④ | 既存リポジトリにLFS導入した際の履歴の見え方・書き換え |
| ⑤ | LFS対象のファイルを更新したときの挙動 |
Git LFSとは
Git LFSは、大容量ファイルの実体をリポジトリ内に直接保存せず、
代わりに**参照情報(ポインタファイル)**だけをGitで管理する仕組み。
ポインタファイルの例:
version https://git-lfs.github.com/spec/v1
oid sha256:fa46b4decb0fd468fdb29e29e35a3f35aafc3c9cf35f10cdd382aa106fed52e8
size 11162
- version:LFS仕様のバージョン
- oid:ハッシュ方式とオブジェクトID
- size:実ファイルのサイズ
(参考)
以下の図のように、Git LFSでは「Gitリポジトリ」と「LFSストレージ」が分離され、
リポジトリにはポインタ情報だけが保存される
[Developer PC]
|
| git push
v
[Git Repository] --- stores ---> pointer file
|
| references
v
[LFS Storage] --- stores ---> real ZIP / binary
検証環境
- GitLab.com(SaaS)
① LFSでZIPファイルを管理する方法
参考: 作業前のリポジトリ

LFSを初期化
$ git lfs install
Updated Git hooks.
Git LFS initialized.
ZIPを対象として登録する。
$ git lfs track "*.zip"
Tracking "*.zip"
すると .gitattributes が自動生成される。
*.zip filter=lfs diff=lfs merge=lfs -text
この状態でZIPファイルを追加・コミット・push。
$ git add after_LFS.zip
$ git commit -m "add after_LFS.zip"
$ git push
Uploading LFS objects: 100% (1/1), 11 KB | 0 B/s, done.
→ ZIPファイルの実体はLFSサーバ側にアップロードされ、Gitにはポインタだけが保存される。
.gitattributeが追加され、「after_LFS.zip」にはLFSのマークが表示

② LFS導入前後で同一ファイルの見え方
同じZIPをLFS化の前後で比較してみた。
LFS導入前の状態
$ git show HEAD:before_LFS.zip
PK^C^D^T^@^H^@^H^@+<#[^・・・
→ Git内部にバイナリの実体が保存されている。
LFS導入後の状態
$ git show HEAD:after_LFS.zip
version https://git-lfs.github.com/spec/v1
oid sha256:fa46b4decb0fd468fdb29e29e35a3f35aafc3c9cf35f10cdd382aa106fed52e8
size 11162
→ LFS化後はGit内部に実体がなく、参照情報のみが残ることを確認
③ LFSをすべての履歴に適用する
既存のコミット履歴にもLFSを適用したい場合、
git lfs migrate import を使用する。
$ git lfs migrate import --include="*.zip" --include-ref=refs/heads/main
Sorting commits: ..., done.
Rewriting commits: 100% (5/5), done.
このコマンドにより、過去の全コミットに含まれるZIPファイルがLFS管理に変換される。
完了後に --force オプションを付けてpushする必要がある。
$ git push origin main --force
④ 既存リポジトリにLFS導入した際の履歴の見え方・書き換え
git lfs migrate import実行前:
コミットID「f86af412...」

git lfs migrate import実行後:
コミットID「79b87c4b...」に更新

→LFS移行によって履歴が再構築され、コミットIDが書き換えられることを確認。
注意点:
履歴が変わるため、すでにリポジトリをクローンしているメンバーは再度クローンし直す必要があり
⑤ LFS対象のファイルを更新したときの挙動
ZIPファイルを上書きして再コミット・pushする。
$ git add after_LFS.zip
$ git commit -m "modify after_LFS.zip"
$ git push
更新前後でポインタファイルの中身を確認。
更新前
$ git show HEAD~1:after_LFS.zip
version https://git-lfs.github.com/spec/v1
oid sha256:fa46b4decb0fd468fdb29e29e35a3f35aafc3c9cf35f10cdd382aa106fed52e8
size 11162
更新後
$ git show HEAD:after_LFS.zip
version https://git-lfs.github.com/spec/v1
oid sha256:7c23e25a77507a83a08f981e359c33d36716a796eea78ce469acd8d144082b39
size 12401
→ OID(ハッシュ値)とサイズが更新され、ポインタファイルが差し替えられている。
Gitの履歴にはポインタの差分のみが保存されるため、
履歴サイズは軽いまま維持される。
LFSで管理する場合にもafter_LFS.zipの履歴はLFSの導入前のように確認できる

追加確認(ドキュメントベース)
① LFS設定はどのブランチに有効?
.gitattributes が作成されたブランチでのみ有効。
git lfs track だけでは他ブランチや過去コミットには反映されない。
② MRでLFS管理ファイルを扱うと?
マージ自体は通常どおり可能。
ただし、差分ビューはポインタ情報のみが表示される。
--
参考ドキュメント
おわりに
実際に動かすことでLFSの挙動や「リポジトリが軽く保たれる理由」が理解できたと思う。
LFS無効化の動きについても確認したい。
Discussion