部分クローン

Git リポジトリのサイズが大きくなると、作業が煩雑になることがあります:

  • ダウンロードしなければならない大量の履歴。
  • 必要なディスク容量が大きい

パーシャルクローンは、「リポジトリの完全なコピーを持たずにGitを機能させる」パフォーマンスの最適化です。この作業の目的は、Gitが非常に大きなリポジトリをよりうまく扱えるようにすることです。”

Git 2.22.0以降が必要です。

ファイルサイズによる絞り込み

GitLab 12.10で導入されました

Gitに大きなバイナリファイルを保存することは、通常は推奨されません。なぜなら、大きなファイルを追加するたびに、その後に変更をクローンしたりフェッチしたりするすべての人がダウンロードされるからです。これらのダウンロードには時間がかかり、特にインターネット接続が遅かったり信頼できなかったりする場合には問題があります。

ファイルサイズフィルター付きの部分クローンを使うと、厄介な大きなファイルをクローンやフェッチから除外することで、この問題を解決できます。Gitが見つからないファイルを見つけたら、オンデマンドでダウンロードします。

リポジトリをクローンする際には、--filter=blob:limit=<size> 引数を使います。たとえば、1メガバイト以上のファイルを除外してリポジトリをクローンするには、次のようにします:

git clone --filter=blob:limit=1m git@gitlab.com:gitlab-com/www-gitlab-com.git

この場合、次のように出力されます:

Cloning into 'www-gitlab-com'...
remote: Enumerating objects: 832467, done.
remote: Counting objects: 100% (832467/832467), done.
remote: Compressing objects: 100% (207226/207226), done.
remote: Total 832467 (delta 585563), reused 826624 (delta 580099), pack-reused 0
Receiving objects: 100% (832467/832467), 2.34 GiB | 5.05 MiB/s, done.
Resolving deltas: 100% (585563/585563), done.
remote: Enumerating objects: 146, done.
remote: Counting objects: 100% (146/146), done.
remote: Compressing objects: 100% (138/138), done.
remote: Total 146 (delta 8), reused 144 (delta 8), pack-reused 0
Receiving objects: 100% (146/146), 471.45 MiB | 4.60 MiB/s, done.
Resolving deltas: 100% (8/8), done.
Updating files: 100% (13008/13008), done.
Filtering content: 100% (3/3), 131.24 MiB | 4.65 MiB/s, done.

出力が長くなっているのは、Git:

  1. リポジトリをクローンする際に、1メガバイトを超えるファイルを除外するからです。
  2. デフォルトブランチをチェックアウトするために必要な、見つからない大きなファイルをダウンロードします。

ブランチを変更すると、Git はさらに足りないファイルをダウンロードするかもしれません。

オブジェクトの種類による絞り込み

GitLab 12.10で導入されました

何百万ものファイルと長い履歴を持つリポジトリでは、すべてのファイルを除外し、git sparse-checkout 、作業コピーのサイズを小さくすることができます。

# Clone the repo excluding all files
$ git clone --filter=blob:none --sparse git@gitlab.com:gitlab-com/www-gitlab-com.git
Cloning into 'www-gitlab-com'...
remote: Enumerating objects: 678296, done.
remote: Counting objects: 100% (678296/678296), done.
remote: Compressing objects: 100% (165915/165915), done.
remote: Total 678296 (delta 472342), reused 673292 (delta 467476), pack-reused 0
Receiving objects: 100% (678296/678296), 81.06 MiB | 5.74 MiB/s, done.
Resolving deltas: 100% (472342/472342), done.
remote: Enumerating objects: 28, done.
remote: Counting objects: 100% (28/28), done.
remote: Compressing objects: 100% (25/25), done.
remote: Total 28 (delta 0), reused 12 (delta 0), pack-reused 0
Receiving objects: 100% (28/28), 140.29 KiB | 341.00 KiB/s, done.
Updating files: 100% (28/28), done.

$ cd www-gitlab-com

$ git sparse-checkout set data --cone
remote: Enumerating objects: 301, done.
remote: Counting objects: 100% (301/301), done.
remote: Compressing objects: 100% (292/292), done.
remote: Total 301 (delta 16), reused 102 (delta 9), pack-reused 0
Receiving objects: 100% (301/301), 1.15 MiB | 608.00 KiB/s, done.
Resolving deltas: 100% (16/16), done.
Updating files: 100% (302/302), done.

詳しくは、sparse-checkout の Git ドキュメントをご覧ください。

ファイルパスによるフィルタリング

部分クローンとスパースチェックアウトのより深いインテグレーションは、--filter=sparse:oid=<blob-ish> フィルタ仕様によって可能です。このフィルタリングモードでは、.gitignore ファイルに似たフォーマットを使用して、クローンやフェッチ時に含めるファイルを指定します。

caution
sparse フィルタを使った部分クローンはまだ実験的です。クローンやフェッチ時に遅くなり、Gitalyリソースの使用率が大幅に増加する可能性があります。すべてのblobをフィルタリングし、代わりにsparse-checkoutを使用してください。 git-sparse-checkoutは、このタイプの部分クローンの使用を単純化し、その制限を克服するからです。

詳しくは、rev-list-options の Git ドキュメントをご覧ください。

  1. フィルター仕様の作成たとえば、モノリシックリポジトリにたくさんのアプリケーションがあり、それぞれがルートの別のサブディレクトリにあるとします。ファイルshiny-app/.filterspec を作成します:

    # Only the paths listed in the file will be downloaded when performing a
    # partial clone using `--filter=sparse:oid=shiny-app/.gitfilterspec`
       
    # Explicitly include filterspec needed to configure sparse checkout with
    # git config --local core.sparsecheckout true
    # git show master:snazzy-app/.gitfilterspec >> .git/info/sparse-checkout
    shiny-app/.gitfilterspec
       
    # Shiny App
    shiny-app/
       
    # Dependencies
    shimmery-app/
    shared-component-a/
    shared-component-b/
    
  2. ファイルを作成します。clone コマンドを使った--filter=sparse:oid のサポートは、スパースチェックアウトと完全にはインテグレーションされていません。

       
    # Clone the filtered set of objects using the filterspec stored on the
    # server. WARNING: this step may be very slow!
    git clone --sparse --filter=sparse:oid=master:shiny-app/.gitfilterspec <url>
       
    # Optional: observe there are missing objects that we have not fetched
    git rev-list --all --quiet --objects --missing=print | wc -l
    
    caution
    bash や Zsh などとの Git インテグレーションや、Git ステータス情報を自動的に表示するエディターでは、リポジトリ全体を取得するgit fetch がよく実行されます。これらのインテグレーションを無効にするか再設定する必要があるかもしれません。

部分クローンのフィルタリングの削除

部分クローンフィルタリングを設定している Git リポジトリは、フィルタリングを解除することができます。フィルタリングを削除するには

  1. フィルターによって除外されたものをすべて取得し、リポジトリが完全であることを確認します。git sparse-checkout を使用していた場合は、git sparse-checkout disable を使用して無効にします。詳しくはdisable ドキュメント を参照してください。

    その後、定期的にfetch を実行し、リポジトリが完全であることを確認してください。特にgit sparse-checkout を使用していない場合に、フェッチするオブジェクトが不足していないかチェックし、フェッチするには、以下のコマンドを使用できます:

    # Show missing objects
    git rev-list --objects --all --missing=print | grep -e '^\?'
       
    # Show missing objects without a '?' character before them (needs GNU grep)
    git rev-list --objects --all --missing=print | grep -oP '^\?\K\w+'
       
    # Fetch missing objects
    git fetch origin $(git rev-list --objects --all --missing=print | grep -oP '^\?\K\w+')
       
    # Show number of missing objects
    git rev-list --objects --all --missing=print | grep -e '^\?' | wc -l
    
  2. すべてをリパックします。これは例えばgit repack -a -d を使って行います。これにより、.git/objects/pack/ に3つのファイルだけが残るはずです:
    • pack-<SHA1>.pack ファイル。
    • 対応するpack-<SHA1>.idx ファイル。
    • pack-<SHA1>.promisor ファイル。
  3. .promisor ファイルを削除します。上記の手順で、pack-<SHA1>.promisor ファイルが1つだけ残っているはずです。このファイルは空のはずなので、削除してください。

  4. 部分クローン設定を削除します。部分的なクローン関連の設定変数をGit設定ファイルから削除します。通常は、以下の設定のみを削除します:
    • remote.origin.promisor.
    • remote.origin.partialclonefilter.