メインコンテンツまでスキップ

なぜ Git LFS を使うのか

Git のオブジェクトストレージについて

Git は変更があった場合、変更前と変更後のオブジェクトを完全な状態で保持します。差分は変更前と変更後のオブジェクトを都度比較することにより生成します。 実際にファイルの完全な状態での保持をします。そのままのデータではとても巨大なオブジェクトストレージのサイズとなってしまうため、可逆データ圧縮アルゴリズムである Deflate を利用してすべてのデータに対してサイズの縮小をします。

Deflate アルゴリズム(RFC1951)は LZ77 とハフマン符号化を組み合わせたよく知られているアルゴリズムです。圧縮は比較的高速、展開は非常に高速なため Git や Web の圧縮によく利用されます。

LZ 法では前方からデータを読み込み、一致があればその一致した前方のインデックスと長さを保持して圧縮を試みます。ハフマン符号化では現れるデータパターンに対して数え上げを行い頻出するパターンに対して短い別のデータ構造を割り当てることで圧縮を試みます。このアルゴリズムはソースコードなどの文字ベースのデータには強い規則性を見出すことができるため比較的良い圧縮をできます。しかしPNG 圧縮されている画像や mp4 圧縮されている音楽などに対してはすでに規則性に対する圧縮をしているため圧縮をしても縮小できる余白が残されていません。

PNG はRFC2083として文書化されていて、圧縮アルゴリズムに Deflate を利用し、フォーマットを zlib 形式(RFC1950)とすることが定められています。そのため単純に 2 回目の Deflate アルゴリズムの圧縮を適用することになり圧縮率は極めて悪いです。

Git LFS を求める理由

ここまでで Git LFS を使いたくなる理由がある程度わかりました。文字ベースのソースコードはどれだけ大きくてもある程度圧縮率が高いため Git のオブジェクトストレージには対して優しいデータと言えます。対照的にそれ以外のデータを Git のオブジェクトストレージで管理することは非効率であることもわかります。Git のオブジェクトストレージに存在するということは通常の clone 操作などをする場合にはこれら全てを取得する必要があるためです。

しかし現代の開発などでは 3D モデルやフォトショップのデータなども管理したくなる場面は当たり前に存在します。そこで、当然考えつく方法として Git とは外部のオブジェクトストレージを利用してそれのリンクだけ Git のオブジェクトストレージに保持する方法です。Git ではバージョン管理できる利点とバージョン間の差分データを得られるツールであり、バイナリの差分は基本的に Git の管理する範疇を超えてしまいます。画像の差分などはまた別のツールや GitHub の機能としても良いでしょう。そこで Git LFS としてバイナリを保持する別のオブジェクトストレージを作成します。

ここまでの課題を素直に解決する Git LFS の仕様

前回のページで Git LFS のサーバ側が提供すべき仕様について記述していました。基本的に外部へデータを保存・取得する URI を提供する機能だけあれば Git のオブジェクトストレージの代わりを担うことができそうです。クライアント側では Git にデータを読み込む前の pre-commit, pre-push などの段階でバイナリデータを URI のみに書き換えた文字コードに変換して Git へ読み込ませます。これで外部機能としての Git LFS がうまく成り立ちそうです。ここまでの解説を実際の Git LFS の実装で表現しています。