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

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

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

これらのリポジトリには、ユーザーが不要な多くのブロブやツリーがしばしば存在します。例えば、

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

  2. 大規模なバイナリ資産。例えば、大規模なビルド成果物がツリーにチェックインされているリポジトリでは、これらのマージ不可能なバイナリ資産の以前の全バージョンをダウンロードすることなく、実際に参照されているバージョンのみをダウンロードできます。

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

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

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

非目標

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

設計概要

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

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

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

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

  • クライアントが必要に応じて不足しているオブジェクトをバックフィルするためのメカニズム。

設計詳細

  • fetch-pack および upload-pack のネゴシエーションに、新しいパックプロトコル機能「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>.keep」ファイルのような)任意のコンテンツを含む「<name>.promisor」ファイルで構成されます。

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

    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 を1回呼び出します。多くのオブジェクトが必要な場合、これにより大きなオーバーヘッドと複数の認証要求が発生する可能性があります。

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

今後の作業

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

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

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

    ユーザーは、それぞれがリポジトリの不完全なビューを持つ複数のプロミサーリモートと三角的なワークフローで作業したいと考えるかもしれません。

  • パス名に基づかないフィルターが(存在する場合)パックファイルビットマップを利用できるようにします。これは、最初の実装時の単なる見落としでした。

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

    パックプロトコル V2 が、その長時間実行プロセスが単一の長時間接続を介して一連の要求を行えるようにできれば、より良いでしょう。

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

  • ルーズなプロミサーオブジェクトを処理する必要性を調査します。

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

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

非タスク

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

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

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

脚注

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

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

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

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

[0] https://crbug.com/git/2 バグ#2: 部分クローン

[1] https://lore.kernel.org/git/20170113155253.1644-1-benpeart@microsoft.com/
Subject: [RFC] オンデマンドでのブロブダウンロードのサポートを追加
Date: Fri, 13 Jan 2017 10:52:53 -0500

[2] https://lore.kernel.org/git/cover.1506714999.git.jonathantanmy@google.com/
Subject: [PATCH 00/18] 部分クローン (クローンからレイジーフェッチまで18個のパッチ)
Date: Fri, 29 Sep 2017 13:11:36 -0700

[3] https://lore.kernel.org/git/20170426221346.25337-1-jonathantanmy@google.com/
Subject: Git リポジトリにおける不足ブロブサポートの提案
Date: Wed, 26 Apr 2017 15:13:46 -0700

[4] https://lore.kernel.org/git/1488999039-37631-1-git-send-email-git@jeffhostetler.com/
Subject: [PATCH 00/10] RFC 部分クローンとフェッチ
Date: Wed, 8 Mar 2017 18:50:29 +0000

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

[6] https://lore.kernel.org/git/20170714132651.170708-1-benpeart@microsoft.com/
Subject: [RFC/PATCH v2 0/1] オンデマンドでのブロブダウンロードのサポートを追加
Date: Fri, 14 Jul 2017 09:26:50 -0400

scroll-to-top