先日GitHub Universeをダラダラと聞いてたら、Git LFSの1.0がリリースされてGitHub上で使えるようになったらしいので試してみました。
- 追記
- 2016/8/20: まだベータでしたがBitbucketでも使えるようになってました。試したら詳しく追記します。
- 2017/5/20:
git lfs init
がgit lfs install
にrenameされていたのでその旨追記しました。
概要
Git LFSはGitHubが中心となって開発しているラージファイル(画像・音声・映像等)を扱うための拡張機能です。gitレポジトリにはテキストファイルのポインタを保存しておいて別の場所にラージファイルの実態を保存しておくことができます。これによって不要なファイルのpullやfetchをすることなくgitレポジトリの最新化ができるようになったりします。
先日のGitHub UniverseでLFS1.0のリリースとGitHub上でのLFS対応が発表されたので試してみました。
今回試した環境
- 前提条件 - Git v1.8.2以上が必要
- 試した環境 - Fedora22(x64)
インストール
-
公式サイトからインストーラを入手。
- 公式サイトにはインストーラを使う方法の他にrpmやdebによるインストールも記載されていましたが、自分の環境ではできませんでした。
- インストーラを実行
tar xfz git-lfs-linux-amd64-1.0.0.tar.gz
cd git-lfs-1.0.0
sudo bash install.sh
独自のインストーラは使いたくなかったんですが、中身を見たら/usr/local/binにgit-lfsのバイナリを一つコピーしてgit lfs initするだけだったので気にせずインストーラを使いました。
ただ、少しだけ罠がありました。
git lfs initすると~/.gitconfgに以下のエントリを追加するんですが、sudo付けて実行するとrootユーザの.gitconfigに追加するので、インストール後に手動でgit lfs initを実行する必要があります。
(sudo付けないと/usr/local/binに書き込めない)
[filter "lfs"]
required = true
clean = git-lfs clean %f
smudge = git-lfs smudge %f
また、git lfs initするとカレントディレクトリに.git/hooks/pre-pushを作りますが、gitレポジトリ以外で打った場合は削除してしまってOKです。gitレポジトリではgit lfs initを毎回手動で打つ必要はなく、あとで出てくるgit lfs track等のコマンド実行時にpre-pushは自動で追加されます。
追記(2017/5/20)
久しぶりに使ったらfedoraでもdnf install git-lfs
で入りました。またgit lfs init
コマンドはgit lfs install
にrenameされてました。
使ってみる
pushする側
- まず、ネットで拾ってきたパブリックドメインの画像ファイルを以下のように配置します。
images/1以下はpng、images/2、images/3以下はjpgがいくつか入ってます。
$ ls -lh images/1/ images/2/ images/3/
images/1/:
total 34M
-rw-rw-r-- 1 dk dk 1.8M Oct 3 07:17 abstract-20650.png
(以下略)
images/2/:
total 34M
-rw-rw-r-- 1 dk dk 2.3M Oct 2 21:21 garda-202068.jpg
(以下略)
images/3/:
total 35M
-rw-rw-r-- 1 dk dk 110K Oct 2 21:25 sun-49143_1280.jpg
(以下略)
- 現在lfsの対象になっているファイルはtrackサブコマンドで確認します。
$ git lfs track
Listing tracked paths
- jpgをtrackするようにします。
$ git lfs track "*.jpg"
Tracking *.jpg
- track対象になったか確認します。
$ git lfs track
Listing tracked paths
*.jpg (.gitattributes)
- ここでカレントディレクトリに以下の内容の.gitattributesが出来上がっていました。
$ cat .gitattributes
*.jpg filter=lfs diff=lfs merge=lfs -text
- また、track後に.git内にlfsフォルダが配置されました。
$ ls .git/
branches config description FETCH_HEAD HEAD hooks index info logs objects refs
$ ls .git
branches COMMIT_EDITMSG config description HEAD hooks index info lfs logs objects refs
- さらにpre-pushフックも自動で追加されました。
$ cat .git/hooks/pre-push
#!/bin/sh
command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/pre-push.\n"; exit 2; }
git lfs pre-push "$@"
- add、commit、pushは通常通りに行います。
commitまでするとls-filesサブコマンドで対象のファイルを確認できます。
$ git lfs ls-files
72efd47286 * images/2/garda-202068.jpg
f9a9d2f678 * images/2/golden-sunset-173594.jpg
(省略)
ecbaed3ab4 * images/3/sun-49143.jpg
699ef8586d * images/3/sun-49143_1280.jpg
(省略)
途中省略してますが、track対象をjpgのみにしたので、pngの画像ファイルは含まれていないことが分かります。
- ここでpushしたらエラーになってしまいました。
$ git push origin master
(21 of 21 files) 33.09 MB / 33.09 MB
Post https://api.github.com/lfs/daikikohara/lfs-test/objects/5e17ac7d1353e297e821eb4b49a54eb9db53b95b19ddccf6b324fdb4aea30453/verify: EOF
error: failed to push some refs to 'git@github.com:daikikohara/lfs-test.git'
- が、再実行したら問題なく終わりました。
$ git push origin master
(1 of 21 files, 20 skipped) 1.10 MB / 33.09 MB, 31.99 MB skipped
Counting objects: 25, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (23/23), done.
Writing objects: 100% (25/25), 3.45 KiB | 0 bytes/s, done.
Total 25 (delta 0), reused 0 (delta 0)
To git@github.com:daikikohara/lfs-test.git
* [new branch] master -> master
- 念の為再度キレイな状態にしてやり直したら、今度は一発で大丈夫でした。ネットワークが不安定だったとかAPIがまだ不安定とかかもしれません。
$ git push origin master
(19 of 16 files) 40.43 MB / 34.85 MB
Counting objects: 20, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (19/19), done.
Writing objects: 100% (20/20), 2.71 KiB | 0 bytes/s, done.
Total 20 (delta 0), reused 0 (delta 0)
To git@github.com:daikikohara/lfs-test.git
09eb0ff..ece1774 master -> master
pullする側
- pullは普通に行なえます。
$ git pull origin master
remote: Counting objects: 25, done.
remote: Compressing objects: 100% (23/23), done.
remote: Total 25 (delta 0), reused 25 (delta 0), pack-reused 0
Unpacking objects: 100% (25/25), done.
From github.com:daikikohara/lfs-test
* branch master -> FETCH_HEAD
* [new branch] master -> origin/master
- この状態だとファイルの中身はテキストファイルのポインタになっているためpullは一瞬で終わります。
$ ls -lh images/2
total 84K
-rw-rw-r--. 1 dk dk 132 Oct 3 14:42 garda-202068.jpg
(以下略)
- ファイルの中身を見てみるとテキストなのが分かります。
$ cat images/2/garda-202068.jpg
version https://git-lfs.github.com/spec/v1
oid sha256:72efd472864c7faccdbbf832a4b63e7c2faff150eab3ad5ffc8c1df091084575
size 2402319
- ファイルの実態をpullするにはgit lfs pullを使います。
lfs pullするとファイルの中身が画像ファイルとして見れるようになります。
$ git lfs pull origin master
(21 of 21 files) 32.97 MB / 33.09 MB
- ちなみに、includeやexcludeをすることもできるので、git pullは普通にしてラージファイルは必要なファイルのみlfs pullすればローカルは軽いままにしておけるし、pullやfetchで長時間待つこともないですね。
また、git pullすればgitレポジトリ自体は最新にできるので、チーム内等でlfs使ってない人がいても問題ないです。
$ git lfs pull origin master --include=images --exclude=images/3
- なお、GitHubのUI上ではファイルはテキストファイルのポインタじゃなくて普通に画像ファイルとして見れます。
以上。
簡単ですが使い方でした。
機能はもっと色々あるようなので詳細は公式サイトを見てもらえればと思います。