Git LFS について(オブジェクトとロック)

以前に 「Git LFS を使ってみる」という記事を書いたのですが、現在のものと少し合わなくなってきている感じがしたので書き直しました。
Git LFS が出始めの頃と比較すると利用できる環境は格段に増えています。

Git LFS について

出始めの頃は別パッケージとしてインストールが必要でしたが、現在は Git for Windows の中に含まれています。
Git LFS は、指定されたファイルタイプ(拡張子による設定など)によって、特別な処理を行いバージョン管理させる仕組みとなっています。
具体的には、比較的ファイルサイズが大きくなるバイナリファイルを対象に指定して、バイナリファイルへのリンク情報をテキストの形にして git によるバージョン管理に載せる動きとなります。
リポジトリ上では、バイナリファイルは git の標準のデータ構造とは別の場所に格納されていたりします。

現在においては、各種 git リポジトリサービスが、この Git LFS に対応しています。

  • GitHub
  • GitLab
  • GitBucket
  • GitBlit
  • Bitbucket
  • Azure DevOps

ただ Git LFS にもバージョンがあり、現時点においては git-lfs のバージョンは 2.7.2 となっています。この過程で Git LFS の通信プロトコルにも拡張が入ることがあり、機能が増えたり、作業の改善があったりとします。
例えば初期では LFS 対象のバイナリファイルが1つずつしかダウンロード出来ていなかったのが、複数を並列でダウンロード出来るようになったりしました。
こういった点より、リポジトリサービスを提供するアプリケーションもバージョン更新が定期的であることが理想的です。GitBlit はかなりの間、バージョン更新が無いようなので利用はあまりオススメできないかと思います。

使い方

Git LFS は、 “.gitattributes” ファイルに設定を記載することで動き出します。
直接このファイルを編集しても良いのですが、コマンドでファイルタイプを追加するには次のようにします。

ファイルの拡張子ごとに LFS に管理させる設定ですが、git は大文字小文字を区別するので注意してください。
あとは普段通りに対象のファイルを add / commit すると、LFS の管理下に置かれます。
また、 push を実行すると、git の管理しているファイルだけでなく LFS 部分で管理されているものも送信されます。

基本的に LFS のファイルは、必要になるまで手元のリポジトリに取得されません。
共同作業している人が、その人専用のブランチで大きなファイルを上げていても、そのブランチが自分と全く無関係であればデータ本体は手元にきません。ブランチの切り替え(checkout)や、プル、マージを実行した際には、そのタイミングで必要となる LFS ファイルがダウンロードされることがあります。
このときにネットワークが不通状態だと処理に失敗するので、注意が必要です。なお、自分はこの挙動が嫌いです。本来の git の良さが死んでいると思っています。

tortoiseGitについて

現在の tortoiseGit では LFS に関する設定が GUI からは出来ないです。また、 Git for windows のインストールの際に、 git をパスに追加するインストールオプションを選択している場合は LFS の対象ファイルを追加・コミットが可能です。しかし、 git bash only な設定でインストールしている自分のような環境では、 tortoiseGit からの操作はエラーが発生してしまいます。

Git lfs のコマンド

いくつか git lfs に関するコマンドの紹介をしておきます。

“git lfs checkout”
競合発生時にこのコマンドを使用して、 base, ours, theirs のファイルを取得できます。例えば次のようにすると自身のファイルを別名で取り出すことが出来ます。
これは、 Git LFS のバージョン 2.6 から使用可能です。

単独で git lfs checkout の実行では、見つからないファイルや LFS ファイルとして置き換わっていないものを取得してきます。

“git lfs fetch”
このコマンドでも LFS ファイルをダウンロードしてきます。このときにオプション指定出来るもので、自分が有用と考えているものが次のオプションです。

  • –recent
  • –all
  • –prune

recent は、最近のブランチとコミットによって参照される LFS ファイルを取得します。
all では、到達可能なコミットによって参照されている全てのオブジェクトを取得します。これは、基本的にリポジトリのバックアップ・移行を目的としています。
prune では、古いオブジェクトおよび参照されていないオブジェクトを破棄します。

prune のオプションの存在を知るまでは LFS 管理するとずっと容量が肥大化していくと思っていました。なお、オプション未指定で git lfs fetch を実行すると、現在チェックアウトされている参照が使われます。

先にブランチのマージでも LFS ファイルを取得すると説明しましたが、マージの実行のまえに次のコマンドを実行しておくとマージコマンドの処理中には LFS ファイルの取得に行かないで済むようになります。

オフラインの環境でのマージ処理が待ち構えている場合には、事前にこれを実行しておくと良さそうです。長距離の移動列車だとか飛行機乗車中とか、そういう状況でもコードを確認しなければならない人にはお勧めです。

使い方 その2

Git LFS にはファイルのロック機能と呼ばれるものが追加されました。正式には “Git LFS File Locking” という機能で、これは Git LFS バージョン 2.0 にて追加されました。
これを使うには、”.gitattributes” に lockable のオプションを追記します。もしくはコマンドラインから操作するのであれば、次のようになります。

このオプションを与えると、該当するファイルは読み取り専用の属性が付きます。

サーバーからロックを得るには次のコマンドです。

ロックを解放するには次のコマンドです。

ロックを解放するタイミングは少し難しいです。多くの場合では、リポジトリサーバーへ push したタイミングでロック解放となるのではないでしょうか。しかしブランチ運用&マージ処理のことを考慮すると、意図しない書き換えをこれだけで防止というわけにはいかないと考えられます。

ロックの一覧を得るには、次のコマンドです。

このコマンドで現在誰がロックを取得しているのかを確認出来ます。当然ながらリポジトリサーバーに通信に行きます。

思うこと

単なる読み取り専用属性が付くだけのロックです。属性を編集してしまえばロックを得ていない人も編集できます。この状態でローカルのリポジトリにはコミットまで出来てしまいます。単にプッシュ時にサーバーから怒られるだけの動きとなります。こういった状況が発生したときに手間が掛かるので自分はこの機能は嬉しくないと思っています。また、git におけるブランチのことを考慮していないので、この点でも使いにくいなと思っています。

Git LFS File Locking の仕様は今後拡張されそうな気配なので、そのときにブランチを考慮したものが出てくるのではと考えています。

対応ツールについて

現在のところ、 Git LFS File Locking を考慮したツールはまだ無さそうです。
使うにはコマンドをたたくしか方法がなさげです。先に述べたように課題が色々とあるので気軽に使うわけにはいかないなぁという状況なので、これでよいかなと思っています。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする