Gitに大容量ファイルをプッシュするときには”Git LFS”を利用しよう

Git

はじめに

Git の利用目的として、「ソースコード」の配置だけでなく、「テストデータ」や画像や音声、動画といった「メディアファイル」の配置にも使われるようになってきている。

ところが、
Git は大容量のファイルをうまく処理できず、リポジトリがすぐに肥大化してしまう。

そこで登場したのが Git LFS という機能です。

今回は Git LFS のメリットや、

検証環境

$ uname -moi
x86_64 MacBookPro16,1 Darwin

$ bash -version | head -n 1
GNU bash, バージョン 5.1.16(1)-release (x86_64-apple-darwin21.1.0)

"Git LFS" がない時

もともとソースコード用に最適化されていた。
テキストファイルですので、マージしたり、圧縮することで容量を劇的に小さくできます。

ところが、
大きなバイナリファイルを履歴管理したり、圧縮したりするととたんに非効率となり、速度も劣化しました。
特にバイナリファイルは圧縮率が低く(画像や動画はもともと圧縮済みということもあり)ほぼそのままのサイズで履歴保存されてしまいます。

10MB のファイルを 10 回コミットすれば履歴はあっという間に 100MB、100 回コミットすれば 1GB となってしまいます。

"Git LFS" がある時

この問題に対して、 "Git LFS" では大容量のファイル(主にバイナリファイルとなる)を Git の外部にあるストレージ ( LFS = Large File Storage )に保存するという方法を取ります。

バイナリファイルの実体(実ファイル)は外部ストレージに保存し、これに対する「参照(リンク)」だけを Git で履歴として保存、操作します。

Github では"Git LFS"を無料で利用できる

Github では巨大なファイルの取り扱いに制限を設けています。

プッシュしたファイルサイズにより以下のようなレスポンスを返却します。

  • 50M 以上の場合、警告
  • 100MB 以上の場合、ブロック

「Github には大容量のファイルをプッシュできない?」と思うかもしれませんが、これに対して回避策を用意してくれています。
それが "Git LFS" の利用です。

"Git LFS" が使えるように、Github では LFS 用の領域を提供しています。
無料アカウントの場合は 1GB まで利用できます。

不足した場合は有料購入する必要があります。(100MB のファイルで制限がかかることから、これを 10 ファイルもプッシュすると無料上限を突破してしまいます。)

Git LFS のインストール

お使いの環境ごとにインストール方法が異なります。

詳細は Installing を参照ください。

ここでは Mac のインストール方法だけを取り上げておきます。

Mac はインストールが楽ですね。

$ brew install git-lfs

Debian では apt でインストールする方法も提供されています。

検証用に Github リポジトリを作成

動作確認用に Github 上にパブリックなリポジトリを作成しました。

操作は長いですが、やっていることは genzouw/git-lfs-training というパブリックリポジトリを作成し、README.md をプッシュしているだけです。

$ mkdir git-lfs-training

$ cd git-lfs-training

$ git init

このタイミングで LFS を利用できるようにインストール作業を実施します。

$ git lfs install

あとは通常通り、 README.md を作成しコミット、プッシュします。

$ echo git-lfs-training >> README.md

$ git add .

$ git commit -m "first commit."

# 手動でGithub上にリポジトリを作成しても構いませんが、
# 今回は自分の作業用PCにインストールされていた Github-CLI を使いました。
$ gh repo create --public genzouw/git-lfs-training
✓ Created repository genzouw/git-lfs-training on GitHub

$ git remote add origin ssh://git@github.com/genzouw/git-lfs-training.git

$ git push -u origin main

使い方

1. Git LFS を利用したいローカルリポジトリに移動

既に先程移動していると思いますが、移動していない場合には移動しておきます。

$ cd git-lfs-training/

2. Git LFS で管理したいファイルを決め、設定する

Git LFS の管理対象とするファイルを指定します。

拡張子で指定するのがよいでしょう。

$ git lfs track "*.jpg"

上記コマンドを実行した結果は、 .gitattributes という設定ファイルに保存されます。
(直接エディタで編集しても構いません。)

$ ls -la
drwxr-xr-x  - genzouw  8 2 21:07 .git/
.rw-r----- 42 genzouw  8 2 21:07 .gitattributes
.rw-r--r-- 17 genzouw  8 2 20:58 README.md

$ cat .gitattributes
*.jpg filter=lfs diff=lfs merge=lfs -text

.gitattributes は Git の管理対象に含めておきましょう。

$ git status -s
?? .gitattributes

$ git add .gitattributes

$ git commit -m "second commit."

$ git push origin main

(注意)

今回はリポジトリを新規に作成していますが、 既にコミット+プッシュ済みの *.jpg ファイルは LFS 上で管理されません。

この場合、 git lfs migrate を使って LFS を利用する形に切り替える必要があります。

3. あとは *.jpg ファイルをプッシュするだけ

設定はここまでになります。

あとは *.jpg ファイルを何でも良いので配置し、プッシュしてみましょう。

Github 上で利用可能な LFS 領域にファイルが配置されるはずです。

$ dd if=/dev/zero of=./large.jpg bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.036411 s, 2.9 GB/s

$ du -hs large.jpg
100M    large.jpg

$ git status -s
?? large.jpg

$ git add large.jpg

$ git commit -m "add big file."

$ git push origin main
Uploading LFS objects: 100% (1/1), 105 MB | 1.6 MB/s, done.
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 422 bytes | 422.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To ssh://github.com/genzouw/git-lfs-training.git
   99afa36..839286a  main -> main

ポイントは 100MB もの巨大なファイルをプッシュしたにもかかわらず、警告が表示されないという点です。
また、メッセージにも Uploading LFS objects と表示されています。

ちなみに LFS を使っていない場合には以下のような警告が表示されます。

remote: warning: See http://git.io/iEPt8g for more information.
remote: warning: File large.jpg is 100.00 MB; this is larger than GitHub's recommended maximum file size of 50.00 MB
remote: warning: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com.

「LFS 使ったほうが良いね!」と言われました。

"Git LFS" が使われているかどうやったら確認できる?

git lfs ls-files というコマンドを実行することで、 "Git LFS" 領域を使ってファイルが管理されているかどうか確認することができます。

$ git lfs ls-files
20492a4d0d - large.jpg

large.jpg は LFS に配置されていることがわかります。

Github の LFS の利用状況は、 Billing ページから確認することができます。

ひとこと

Git LFS は「Github」で提供されている領域だけではなく、「AWS S3」や「Google Cloud Storage」といったクラウドのオブジェクトストレージサービスを利用する事もできます。

参考

Git