Edited at

Git LFSが1.0になってGitHubで使えるようになったので試してみた

More than 1 year has passed since last update.

先日GitHub Universeをダラダラと聞いてたら、Git LFSの1.0がリリースされてGitHub上で使えるようになったらしいので試してみました。


  • 追記


    • 2016/8/20: まだベータでしたがBitbucketでも使えるようになってました。試したら詳しく追記します。

    • 2017/5/20: git lfs initgit lfs installrenameされていたのでその旨追記しました。




概要

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に書き込めない)


~/.gitconfigに追記される内容

[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 installrenameされてました。


使ってみる


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サブコマンドで確認します。


trackでlfsの対象を確認

$ git lfs track

Listing tracked paths


  • jpgをtrackするようにします。


jpgをtrackする

$ git lfs track "*.jpg"

Tracking *.jpg


  • track対象になったか確認します。


再度trackを実行

$ git lfs track

Listing tracked paths
*.jpg (.gitattributes)


  • ここでカレントディレクトリに以下の内容の.gitattributesが出来上がっていました。

$ cat .gitattributes

*.jpg filter=lfs diff=lfs merge=lfs -text


  • また、track後に.git内にlfsフォルダが配置されました。


track前

$ ls .git/

branches config description FETCH_HEAD HEAD hooks index info logs objects refs


track後

$ ls .git

branches COMMIT_EDITMSG config description HEAD hooks index info lfs logs objects refs


  • さらにpre-pushフックも自動で追加されました。


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サブコマンドで対象のファイルを確認できます。


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したらエラーになってしまいました。


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'


  • が、再実行したら問題なく終わりました。


push再実行したら無事完了

$ 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がまだ不安定とかかもしれません。


キレイにして再実行したら一発でOKだった

$ 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は普通に行なえます。


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
(以下略)


  • ファイルの中身を見てみるとテキストなのが分かります。


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するとファイルの中身が画像ファイルとして見れるようになります。


ファイルの実態の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使ってない人がいても問題ないです。


includeとexclude

$ git lfs pull origin master --include=images --exclude=images/3



  • なお、GitHubのUI上ではファイルはテキストファイルのポインタじゃなくて普通に画像ファイルとして見れます。

以上。

簡単ですが使い方でした。

機能はもっと色々あるようなので詳細は公式サイトを見てもらえればと思います。