日本語 ▾ トピック ▾ 最新バージョン ▾ partial-clone は 2.49.0 で最終更新されました

"部分クローン (Partial Clone)" 機能は、Git がリポジトリの完全なコピーを持たずに動作できるようにする Git のパフォーマンス最適化です。この作業の目標は、Git が非常に大規模なリポジトリをより適切に処理できるようにすることです。

クローンおよびフェッチ操作中、Git はリポジトリの完全なコンテンツと履歴をダウンロードします。これには、リポジトリの全ライフサイクルにおけるすべてのコミット、ツリー、およびブロブが含まれます。非常に大規模なリポジトリの場合、クローンに数時間 (または数日) かかり、100GiB 以上のディスク領域を消費することがあります。

多くの場合、これらのリポジトリにはユーザーが不要な多くのブロブとツリーが含まれています。例えば、

  1. ツリー内のユーザーの作業領域外のファイル。たとえば、すべてのコミットに 50 万個のディレクトリと 350 万個のファイルが含まれるリポジトリで、ユーザーがソースツリーの狭い「コーン」しか必要としない場合、多くのオブジェクトのダウンロードを避けることができます。

  2. 大きなバイナリアセット。たとえば、大きなビルド成果物がツリーにチェックインされているリポジトリで、これらのマージできないバイナリアセットの以前のバージョンをすべてダウンロードするのを避け、実際に参照されているバージョンのみをダウンロードできます。

部分クローンを使用すると、クローンおよびフェッチ操作中に、このような不要なオブジェクトを事前にダウンロードするのを避け、ダウンロード時間とディスク使用量を削減できます。不足しているオブジェクトは、必要に応じて後で「オンデマンドでフェッチ」できます。

後で不足しているオブジェクトを提供できるリモートは、要求されたときにオブジェクトを送信することを約束するため、プロミサーリモートと呼ばれます。当初、Git は 1 つのプロミサーリモート、つまりユーザーがクローンした元のリモートのみをサポートしており、それは "extensions.partialClone" 設定オプションで設定されていました。その後、複数のプロミサーリモートのサポートが実装されました。

部分クローンを使用するには、ユーザーがオンラインであること、および元のリモートまたは他のプロミサーリモートが不足しているオブジェクトのオンデマンドフェッチに利用可能である必要があります。これはユーザーにとって問題になる場合とならない場合があります。たとえば、ユーザーがソースツリーの事前に選択されたサブセット内に留まることができる場合、不足しているオブジェクトに遭遇しないかもしれません。あるいは、ユーザーはオフラインになることを知っている場合、さまざまなオブジェクトを事前にフェッチしようとすることができます。

非目標

部分クローンは、特定のコミット範囲でダウンロードされるブロブとツリーの数を制限するメカニズムであり、したがって、要求されたコミットセットを制限する既存のDAGレベルのメカニズム(つまり、シャロークローン、シングルブランチ、またはフェッチ <refspec>)とは独立しており、競合することを意図していません。

設計概要

部分クローンは論理的に以下の部分で構成されます。

  • クライアントが不要なオブジェクトをサーバーに記述するメカニズム。

  • サーバーがそのような不要なオブジェクトをクライアントに送信されるパックファイルから除外するメカニズム。

  • クライアントが不足しているオブジェクト(以前にサーバーによって除外されたもの)を適切に処理するメカニズム。

  • クライアントが必要に応じて不足しているオブジェクトを補充するメカニズム。

設計詳細

  • 新しいパックプロトコル機能「filter」がフェッチパックとアップロードパックのネゴシエーションに追加されました。

    これは既存の機能検出メカニズムを使用します。 gitprotocol-pack[5] の「filter」を参照してください。

  • クライアントは「filter-spec」をクローンとフェッチに渡し、それがサーバーに渡されてパックファイル構築中のフィルタリングを要求します。

    さまざまな状況に対応するために、さまざまなフィルターが利用可能です。 Documentation/rev-list-options.adoc の "--filter=<filter-spec>" を参照してください。

  • サーバー側では、pack-objects は、クライアント用の「フィルタリングされた」パックファイルを作成する際に、要求された filter-spec を適用します。

    これらのフィルタリングされたパックファイルは、従来の意味では不完全です。なぜなら、それらはパックファイルに含まれていないオブジェクト、またはクライアントがまだ持っていないオブジェクトを参照するオブジェクトを含む可能性があるからです。たとえば、フィルタリングされたパックファイルは、不足しているブロブを参照するツリーやタグ、または不足しているツリーを参照するコミットを含む可能性があります。

  • クライアントでは、これらの不完全なパックファイルは「プロミサーパックファイル」としてマークされ、さまざまなコマンドによって異なる方法で扱われます。

  • クライアントでは、古いバージョンの Git が、処理できないオブジェクトの不足によって操作中に失敗するのを防ぐために、リポジトリ拡張がローカル設定に追加されます。 git-config[1]extensions.partialClone を参照してください。

不足しているオブジェクトの処理

  • オブジェクトは、部分クローンまたはフェッチによって不足している場合、あるいはリポジトリの破損によって不足している場合があります。これらのケースを区別するために、ローカルリポジトリは、プロミサーリモートから取得したそのようなフィルタリングされたパックファイルを「プロミサーパックファイル」として特別に示します。

    これらのプロミサーパックファイルは、"<name>.pack" および "<name>.idx" ファイルに加えて、任意のコンテンツを持つ "<name>.promisor" ファイル("<name>.keep" ファイルのように)で構成されます。

  • ローカルリポジトリは、「プロミサーオブジェクト」を、プロミサーリモートが持っていると約束した(能力の限り)オブジェクトであると見なします。これは、ローカルリポジトリがそのオブジェクトをプロミサーパックファイルのいずれかに持っているか、または別のプロミサーオブジェクトがそれを参照しているためです。

    Gitが不足しているオブジェクトに遭遇した場合、それがプロミサーオブジェクトであるかどうかを確認し、適切に処理できます。そうでない場合、Gitは破損を報告できます。

    これは、クライアントが、修正にコストがかかる欠落オブジェクトのリストを明示的に維持する必要がないことを意味します。[a]

  • 現在のほとんどの Git コードは、参照されるすべてのオブジェクトがローカルに存在することを期待しており、すべてのコマンドに最初にドライランを実行させることを強制したくないため、Git がプロミサーリモートから不足しているオブジェクトを動的にフェッチしようとすることを可能にするフォールバックメカニズムが追加されました。

    通常のオブジェクト検索がオブジェクトを見つけられない場合、Git は promisor_remote_get_direct() を呼び出してプロミサーリモートからオブジェクトを取得しようとし、その後オブジェクト検索を再試行します。これにより、複雑な予測アルゴリズムなしでオブジェクトを「障害発生時に読み込む」ことができます。

    効率上の理由から、欠落しているオブジェクトが実際にプロミサーオブジェクトであるかどうかのチェックは行われません。

    オブジェクトは一度に1つずつフェッチされるため、動的なオブジェクトのフェッチは遅くなる傾向があります。

  • checkout (および unpack-trees を使用する他のすべてのコマンド) は、必要な欠落ブロブをすべて単一のバッチで一括プリフェッチするように教えられました。

  • rev-list は、欠落しているオブジェクトを出力するように教えられました。

    これは、他のコマンドがオブジェクトを一括でプリフェッチするために使用できます。たとえば、「git log -p A..B」は内部的に最初に「git rev-list --objects --quiet --missing=print A..B」のようなことを実行し、それらのオブジェクトを一括でプリフェッチしたい場合があります。

  • fsck は、プロミサーオブジェクトを完全に認識するように更新されました。

  • GC の repack は、プロミサーパックファイルには一切触れず、他のオブジェクトのみをリパックするように更新されました。

  • グローバル変数 "fetch_if_missing" は、オブジェクト検索が欠落オブジェクトを動的にフェッチしようとするか、エラーを報告するかを制御するために使用されます。

    このグローバル変数には満足しておらず、削除したいと考えていますが、そのためにはオブジェクトコードを大幅にリファクタリングして追加のフラグを渡す必要があります。

欠落オブジェクトのフェッチ

  • オブジェクトのフェッチは、「git fetch」サブプロセスを呼び出すことによって行われます。

  • ローカルリポジトリは、要求されたすべてのオブジェクトのハッシュを含む要求を送信し、パックファイルのネゴシエーションは実行しません。その後、パックファイルを受信します。

  • 既存のフェッチメカニズムを再利用しているため、現在、フェッチは、要求されたオブジェクトによって参照されるすべてのオブジェクトをフェッチします。これらは必ずしも必要ではありません。

  • --refetch を使用したフェッチは、リモートから完全な新しいフィルタリングされたパックファイルを要求します。これは、不足しているオブジェクトを動的にフェッチすることなくフィルターを変更するために使用できます。

複数のプロミサーリモートの使用

多くのプロミサーリモートを設定して使用することができます。

これにより、たとえば、ユーザーは、欠落しているブロブをフェッチするために複数の地理的に近いキャッシュサーバーを持ちながら、中央サーバーからフィルタリングされた git-fetch コマンドを実行し続けることができます。

オブジェクトのフェッチ時、プロミサーリモートは、すべてのオブジェクトがフェッチされるまで、順次試行されます。

「プロミサー」リモートと見なされるリモートは、次の構成変数で指定されたものです。

  • extensions.partialClone = <name>

  • remote.<name>.promisor = true

  • remote.<name>.partialCloneFilter = ...

extensions.partialClone 設定変数を使用して構成できるプロミサーリモートは1つだけです。このプロミサーリモートは、オブジェクトをフェッチする際に最後に試行されます。

多くの場合、多くのプロミサーリモートを使用している人は、他のプロミサーリモートが何らかの理由(特定の種類のオブジェクトに対してより近い、またはより高速など)でオリジンよりも優れているため、そのようにしている可能性があり、オリジンは extensions.partialClone で指定されたリモートである可能性が高いと判断したため、最後に試行することにしました。

この正当化はそれほど強力ではありませんが、選択する必要があり、いずれにせよ長期的な計画は、順序を何らかの形で完全に設定可能にすることです。

しかし、今のところ、他のプロミサーリモートは、設定ファイルに表示される順序で試行されます。

現在の制限

  • プロミサーリモートが試行される順序を、設定ファイルに現れる順序以外の方法で指定することはできません。

    また、あるリモートからフェッチするときに使用する順序と、別のリモートからフェッチするときに使用する別の順序を指定することもできません。

  • 特定のオブジェクトのみをプロミサーリモートにプッシュすることはできません。

    特定の順序で複数のプロミサーリモートに同時にプッシュすることはできません。

  • 動的なオブジェクトのフェッチは、不足しているオブジェクトに対してのみプロミサーリモートに問い合わせます。プロミサーリモートはリポジトリの完全なビューを持ち、そのようなすべての要求を満たすことができると仮定しています。

  • Repack は基本的にプロミサーと非プロミサーのパックファイルを 2 つの異なるパーティションとして扱い、それらを混合しません。

  • ほとんどのアルゴリズムは、欠落しているオブジェクトに遭遇し、作業を続行する前にそれを解決する必要があるため、動的なオブジェクトのフェッチは各アイテムに対して一度 fetch-pack を呼び出します。多くのオブジェクトが必要な場合、これはかなりのオーバーヘッド(および複数の認証要求)を引き起こす可能性があります。

  • 動的なオブジェクトのフェッチは現在、既存のパックプロトコル V0 を使用しているため、各オブジェクトは fetch-pack を介して要求されます。接続が確立されると、サーバーは完全な info/refs セットを送信します。参照の数が多い場合、これはかなりのオーバーヘッドを引き起こす可能性があります。

今後の作業

  • プロミサーリモートが試行される順序を指定する方法を改善する。

    たとえば、これにより、「このリモートからフェッチするときは、これらのプロミサーリモートをこの順序で使用したい。ただし、あのリモートにプッシュまたはフェッチするときは、あのプロミサーリモートをあの順序で使用したい。」といったように明示的に指定できるようになる可能性があります。

  • プロミサーリモートへのプッシュを許可する。

    ユーザーは、それぞれがリポジトリの不完全なビューを持つ複数のプロミサーリモートを使用して、三角ワークフローで作業したい場合があります。

  • パックファイルビットマップ(存在する場合)を利用するために、パス名ベースではないフィルターを許可する。これは初期実装時の単なる見落としでした。

  • [5,6] で提案されているように、プロセス起動とオーバーヘッドコストを削減するために、一連のオブジェクトを動的にフェッチする長時間実行プロセスを使用することを調査します。

    パックプロトコル V2 が、単一の長時間接続で長時間実行プロセスが一連のリクエストを行うことを許可できれば素晴らしいでしょう。

  • 不足しているオブジェクトを動的にフェッチするためにサーバーとの接続ごとに info/refs のブロードキャストを回避するために、パックプロトコル V2 の必要性を調査します。

  • ゆるいプロミサーオブジェクトを処理する必要性を調査する。

    プロミサーパックファイル内のオブジェクトは、サーバーから動的にフェッチできる不足オブジェクトを参照することを許可されています。ゆるいオブジェクトはローカルでのみ作成され、したがって不足オブジェクトを参照すべきではないという仮定が立てられました。たとえば、不足しているツリーを動的にフェッチし、単一オブジェクトパックファイルではなくゆるいオブジェクトとして格納する場合、その仮定を再検討する必要があるかもしれません。

    これは必ずしもゆるいオブジェクトをプロミサーとしてマークする必要があるという意味ではありません。オブジェクト検索または is-promisor 関数を緩和するだけで十分かもしれません。

非タスク

  • 「ブロブのオンデマンド読み込み」という話題が出るたびに、誰かがサーバーが「推測」して、要求されたオブジェクトに関連する可能性のある追加のオブジェクトを送信することを許可すべきだと提案するようです。

    実際にそれを行う作業は行われていません。それはよくある提案であることを文書化しているだけです。それがどのように機能するかは不明であり、それに取り組む計画もありません。

    サーバーが要求されたよりも多くのオブジェクトを送信することは有効ですが(動的なオブジェクトフェッチの場合でも)、我々はその上には構築していません。

脚注

[a] 修正にコストがかかる欠落オブジェクトのリスト: 部分クローンの設計の初期段階で、欠落オブジェクトの単一リストの必要性について議論しました。これは、本質的に、クローンまたはその後のフェッチ中にサーバーによって省略された OID のソートされた線形リストとなるでしょう。

このファイルは、すべてのオブジェクト検索でメモリにロードされる必要があります。すべての明示的な「git fetch」コマンドおよびすべての動的オブジェクトフェッチで、読み取り、更新、および再書き込み(.git/index のように)が必要になります。

欠落オブジェクトが多数ある場合、このファイルの読み取り、更新、書き込みのコストは、すべてのコマンドにかなりのオーバーヘッドを追加する可能性があります。たとえば、1億個の欠落ブロブがある場合、このファイルはディスク上で少なくとも2GiBになります。

「プロミサー」の概念により、参照しているパックファイルの種類に基づいて、不足しているオブジェクトを推測します。

[0] https://crbug.com/git/2 Bug#2: Partial Clone

[1] https://lore.kernel.org/git/20170113155253.1644-1-benpeart@microsoft.com/
件名: [RFC] ブロブのオンデマンドダウンロードのサポートを追加
日付: 2017年1月13日金曜日 10:52:53 -0500

[2] https://lore.kernel.org/git/cover.1506714999.git.jonathantanmy@google.com/
件名: [PATCH 00/18] 部分クローン (クローンから遅延フェッチまで18パッチ)
日付: 2017年9月29日金曜日 13:11:36 -0700

[3] https://lore.kernel.org/git/20170426221346.25337-1-jonathantanmy@google.com/
件名: Gitリポジトリにおける欠落ブロブサポートの提案
日付: 2017年4月26日水曜日 15:13:46 -0700

[4] https://lore.kernel.org/git/1488999039-37631-1-git-send-email-git@jeffhostetler.com/
件名: [PATCH 00/10] RFC 部分クローンとフェッチ
日付: 2017年3月8日水曜日 18:50:29 +0000

[5] https://lore.kernel.org/git/20170505152802.6724-1-benpeart@microsoft.com/
件名: [PATCH v7 00/10] フィルター処理コードを再利用可能なモジュールにリファクタリング
日付: 2017年5月5日金曜日 11:27:52 -0400

[6] https://lore.kernel.org/git/20170714132651.170708-1-benpeart@microsoft.com/
件名: [RFC/PATCH v2 0/1] ブロブのオンデマンドダウンロードサポートを追加
日付: 2017年7月14日金曜日 09:26:50 -0400

scroll-to-top