📖

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 だけでは他ブランチや過去コミットには反映されない。

Git LFS 公式ドキュメント


② MRでLFS管理ファイルを扱うと?

マージ自体は通常どおり可能。
ただし、差分ビューはポインタ情報のみが表示される。

GitLab Issue #26063


--

参考ドキュメント


おわりに

実際に動かすことでLFSの挙動や「リポジトリが軽く保たれる理由」が理解できたと思う。
LFS無効化の動きについても確認したい。

Discussion