git lfs migrate で Git-LFS 移行したときのメモ

Mercurial(Hg)からGit移行移行したついでに、ほぼ1GBとかあるリポジトリ*1をGit-LFSに移行した際のメモです。

Git-LFSを扱えるサービスとしてはBitbucket CloudよりもGitlab.comの方が制限が緩かったので、そちらへの移行も同時に行いました。

ja.confluence.atlassian.com

gitlab.com

作業環境: Windows 10 + Git for Windows(+Git Bash,Git LFS)

0. BFGを使わなかった理由

Git-LFSへの移行(変換)を調べているとBFGを使った移行方法の説明が多く見つかります。

AttlasianGitlab.comBFGを使用した移行ドキュメントを公開しています。

ところが、ドキュメント通りにBFGによるGit-LFSを実行したところ、一見問題なく移行できたように見えて、実はうまくいってないのでは? という状態になり、色々調べ直したところ、現在は git lfs migrate で問題なく移行できるというところに行きつきました。*2

BFGでのGit LFS移行について、自分の環境で問題になったのは以下の点です。

  1. BFGが生成する .gitattributes ファイルはオプションで指定した文字列がそのまま入ってしまう関係上、Git-LFS的に無効なフォーマットで生成される場合がある。(これにより、問題なくgit lfs pullできるが、git lfs管理のファイルがModifiedな状態として認識される事態が発生した)*3
  2. .gitattributes ファイルが、ルートになるディレクトリだけでなく、対象となるファイルがあるフォルダ毎に生成されてしまう。*4(1.の問題に引っかかると認識しにくいが、リポジトリ内を一括で変換してるのにディレクトリ毎に .gitattributes ファイルを管理することになるのはうれしくなかった)

1. Bitbucket Cloud から --mirrorでクローン

git clone --mirror git@bitbucket.org:[ユーザー名]/[リポジトリ名].git

※クローンした [リポジトリ名].git を別にコピーしておくなり圧縮して置いておくなりすると、繰り返しテストする時など大変便利がいい。

2. git lfs migrate info による事前調査

クローンした[リポジトリ名].gitフォルダに移動したのち、現在の状態を調査

git lfs migrate info --everything

上記を実行すると、リポジトリに含まれるファイルのサイズを拡張子毎に集計して、容量降順に並べて表示してくれる。 デフォルトだとトップ5の拡張子まで表示してくれる。

--everything は全ブランチを対象にするオプション。

git lfs migrate info --top=20 --everything

だと、トップ20まで表示してくれる。

あくまでも拡張子毎に集計しているだけなので、.csなども普通に入ってくる。

参考にしつつ、対象となる拡張子(またはファイル)を選定する。

なお、このgit lfs migrate infoでは拡張子の大文字小文字も厳密に分けて集計される。 これはのちに実行する変換コマンドでの指定でも同様なので留意する。

バイナリだからとにかくGit-LFSに移行すればよいってものでもないと思うので、そこの判断は慎重に行う。(あとマイナー?な拡張子はバイナリかどうかの判断に困ったりもする)

3. git lfs migrate import 実行

[リポジトリ名].gitフォルダ内で、Git LFSに移行するファイルを指定してgit lfs migrate importコマンドを実行する。

git lfs migrate import --include="[Git LFSに移行するファイルの指定]" --everything

--include でのファイル指定はワイルドカード(*)が使えるので、拡張子を指定する場合は *.[拡張子] で指定する。複数指定がある場合はカンマ(,) でつなげていく。

例として、以下の指定だと、拡張子wav,png,bmp,zipのファイルが移行対象になる。

git lfs migrate import --include="*.wav,*.png,*.bmp,*.zip" --everything

※細かい指定方法などは git-lfs/git-lfs-migrate.1.ronn at master · git-lfs/git-lfs · GitHub を参照のこと。

あまり指定が長くなるようなら、(Git Bashなので) \ でつないで複数行にする。

git lfs migrate import の実行が完了したら、以下のコマンドで、ローカルのファイル・キャッシュを整理する。*5

git reflog expire --expire-unreachable=now --all && git gc --prune=now

リポジトリのルートディレクトリに .gitattributes が追加されているので、--inlude で指定したファイル名、パターンが問題なく記述されていることを確認する。(履歴も改変されて.gitattributesが最初期にコミットされたことになっているはず)

また、git lfs migrate import 実行後に git lfs migrate info を実行すると再度集計できる。この時Git-LFSに移行したファイルはポインタファイルでの集計になっている。これは移行の確認や効果の見直しなどに使う。

4. Gitlab.com へ --mirror でプッシュ

Gitlab.comで新しく作ったGitリポジトリへプッシュ

git push --mirror https://gitlab.com/[ユーザー名]/[リポジトリ名].git

既になにかしらあるリポジトリへも --mirror だとforce扱いでpushできるが、それは結構な荒療治なので諸々確認が必要になる。 (なので新しいリポジトリにpushして移行する形にしている)

リポジトリURI形式がBitbucket CloudとGitlab.comで異なるのはたまたま作業していてそうなっただけで特に意味はありません。

5. 参考資料ほか

github.com

tech.griphone.co.jp

qiita.com