Edited at

アホみたいにでかいgit repositoryを上手く扱う方法

More than 1 year has passed since last update.

gitが大きくなると時間かかってしゃーないと思っていたら、ちょうどatlassianのブログにこんな記事があった。

How to handle big repositories with git - Atlassian Blogs

巨大なリポジトリ を Git で上手く扱う方法

直訳ではなく、読んだことを参考に自分用にメモを記す。これは本当にメモ代わりなので原文を参照した方がいいと思う。

gitが重くなる原因は、「長い歴史」と「デカいファイル」の2つがある。その2つの対処法。


長い歴史に対処する


shallow cloneを使う

gitのhistoryが積み重なると、git cloneに時間がかかる。そのときはshallow cloneを使って、深さを限定してcloneする。

git clone --depth depth remote-url

手元の環境だと23sくらいかかっていたのでも6sくらいに短縮されたから、大きいのだともっと短縮されそう。


filter-branchを使う。

誰かアホなやつが(主に俺が)git add .とかで不要なバイナリファイルとかを一度入れてしまうと、gitの歴史はずっとそのファイルを持ち続けるので、重くなる。そういう時はfilter-branchを使って、歴史の書き換えをする。

git filter-branch --tree-filter 'rm -rf /path/to/spurious/asset/folder' HEAD

Git - 歴史の書き換え

これによって、指定したコマンドをすべてのcommitに対して実行する。俺も何回か使っとことあるけど、gitの歴史の書き換えはすげえ注意が必要。


single-branchを使う

shallow cloneの代わりに、single-branchオプションを使うこともできる。これで、ひとつのbranchのみcloneすれば、重いbranchを無視してcloneできる。

git clone URL --branch branch_name --single-branch [folder]


デカいファイルに対処する

gitってそもそもbinaryファイルを上げることを嫌っていると思っていた(デフォルトではignoreされた気がする)。でも違って、特にバイナリを扱うことに劣っているわけではないらしい(優れてもいない)。

デカいファイルには、状況に応じた対処が必要


  • バイナリファイルの変更が大きい時は、差分圧縮は使いものにならない。不必要な差分圧縮を避けるためにも、これらのファイルをdelta offにしておく必要がある。

  • 上記の状況だとzlib圧縮は上手く機能しないだろうから、core.compression 0もしくはcore.loosecompression 0に設定をして、圧縮をしないようにしておく必要がある。バイナリファイル以外には悪い影響が出るので、バイナリを別のrepositoryに分けるのをおすすめする。

  • git gcによって不必要なオブジェクトを削除したり、ゆるいオブジェクトを一つのパックファイルに整理したりする。これも有効


  • core.bigFileThresholdをチューニングすることも有効。512MiBより大きいファイルは差分圧縮されるべきではない。(.gitattributes)を設定することを除いて。


sparse checkout

sparse checkoutというものを使えば、明示的に特定のfileやdirectoryのみをgit上で扱えるようになる。

まずは普通にgit cloneする。

git clone

configを設定。

git config core.sparsecheckout true

扱いたいdirectoryを.git/info/sparse-checkoutに記述

echo src/ > .git/info/sparse-checkout

反映させる

git read-tree -m -u HEAD

これを使うと、指定したdirectoryやfileのみを操作できるようになる。(他のファイルは見えなくなる。)


submodule

大きいbinaryなどは別のrepositoryにいれて、そのrepositoryをsubmoduleとする。

Git submodule の基礎 - Qiita

submoduleを使えば、binaryの入っているrepositoryは参照するだけで、一緒に更新したりしないので、重いものを有効に除外できる。


git annexもしくはgit-bigfiles

git-annexを使う。これを使えば、ファイルの中身を取り込まずに管理できる。

git-annex

また、git-bigfilesは、大きいファイルを扱うことを目的としたgitのforkである。

git-bigfiles – Caca Labs