「デルタを解決する」と書かれているとき、gitは実際に何をしていますか?


187

リポジトリの最初のクローン中に、gitは最初にオブジェクト(十分に明らかです)を受け取り、次に「デルタの解決」とほぼ同じ時間を費やします。クローンのこの段階で実際に何が起こっていますか?



1
Git 2.20(2018年第4四半期)およびその他のデルタアイランドについても参照してください:stackoverflow.com/a/52458712/6309
VonC

回答:


54

Gitは差分エンコーディングを使用して、一部のオブジェクトをパックファイルに格納します。しかし、あなたはすべての単一の変更を再生するにはしたくない、これまでのGitもうまくとして格納されたファイルの内容の臨時のスナップショットを持っているので、現在のバージョンを取得するために、与えられたファイルに。「デルタの解決」は、それらすべての一貫性を維持するためのステップです。

ここの章です。この程度の協議こと、オンラインで利用可能であるプロGitの著書の「Gitの内部構造」セクションからは。


80
この答えは間違っています。それはGitではなく、Mercurialがどのように機能するかを説明しているようです。この問題のGoogle検索で表示される予定なので、返信する必要があると感じています。Gitはコミット間の違いをデルタとして保存しませ。Gitは「オブジェクト全体」のストアです。そのため、ファイル履歴をデルタから再構築する必要がないため、Gitは特定のファイルを表示するための「スナップショット」を必要としません。それがMercurialの仕組みです。
ネクサスによると

12
デルタエンコーディングが機能する唯一の場所は、厳密に圧縮と転送を目的とするパックファイル内です。これにより、Gitが世界を「見る」方法は変わりません。(kernel.org/pub/software/scm/git/docs/v1.6.2.3/technical/…)正確な応答については、以下のaraqnidの回答を参照してください。
ネクサスによると

4
すべての「スナップショット」とは、このコンテキストでは、差分エンコードされたバージョンではなく、ファイルの状態の完全なコピーであることを意味します。あなたが述べたように、Git packfilesで差分エンコーディングを使用ます。「Gitが世界を見る方法を変える」とは誰も言っていません。自分の仮定を投影するのをやめてください。
アンバー

2
あなたの答えはまだ不正確です。「Gitには、ファイルの内容のスナップショットも保存されています。」-不正解です。「「デルタの解決」は、それらすべての一貫性を保つことを確実にすることを扱うステップです。」-これも正しくありません。以下のaraqnidの応答は正しいです。
ネクサスは

1
上記の章で説明したように、Gitは常に最新バージョンの完全なファイルコンテンツを保存します。以前のバージョンは、「緩い」ファイルの場合、デルタコードファイルとして保存されます。定期的に(呼び出しによって、git gcまたはGitが必要と判断するたびに)、Gitはすべての「緩い」ファイルをパックファイルに圧縮してスペースを節約し、そのパックファイルへのインデックスファイルが作成されます。そのため、zlibは独自のデルタアルゴリズムで圧縮しますが、Gitはデルタエンコーディングを使用して以前のバージョンを格納します。最も一般的で頻繁なアクセスは最新バージョンであるため、スナップショットとして保存されます。
BrionS 2013

118

の段階は次のgit cloneとおりです。

  1. リポジトリデータベース内のすべてのオブジェクトの「パック」ファイルを受け取る
  2. 受け取ったパックのインデックスファイルを作成する
  3. ヘッドリビジョンを確認してください(ベアリポジトリ以外の場合)

"Resolving deltas"は、パックファイル( "git index-pack")のインデックスを作成する第2段階で表示されるメッセージです。

パックのファイルがないではない、彼らにのみオブジェクトの内容を実際のオブジェクトIDを持っています。そのため、オブジェクトIDを特定するために、gitはパック内の各オブジェクトの解凍+ SHA1を実行してオブジェクトIDを生成し、それをインデックスファイルに書き込む必要があります。

パックファイル内のオブジェクトは、デルタ、つまり他のオブジェクトに対して行われる一連の変更として保存できます。この場合、gitはベースオブジェクトを取得し、コマンドを適用して結果をSHA1する必要があります。基本オブジェクト自体は、一連のデルタコマンドを適用することによって派生する必要がある場合があります。(クローンの場合でも、ベースオブジェクトは既に検出されていますが、メモリにキャッシュされる製造済みオブジェクトの数には制限があります)。

要約すると、「デルタの解決」段階では、repoデータベース全体の圧縮解除とチェックサム計算が行われますが、驚くほど長い時間はかかりません。おそらく、SHA1の解凍と計算には、deltaコマンドを適用するよりも時間がかかります。

後続のフェッチの場合、受信したパックファイルには、受信gitがすでに持っていると予想される他のオブジェクトへの参照(デルタオブジェクトベースとして)が含まれている可能性があります。この場合、受け取り側のgitは実際に、受け取ったパックファイルを書き換えて、そのような参照オブジェクトを含めます。これにより、保存されているパックファイルはすべて自給自足になります。これは、メッセージ「デルタを解決しています」が発生した場所である可能性があります。


7
これは並列化できますか?
brooksbp 2013

このデルタ圧縮は、1つのzlibデータストリームに複数のオブジェクトを格納する以上のものですか?
fuz

1
@FUZxxlはい、diffやxdeltaなどのアルゴリズムを使用して2つのblobを比較し、編集スクリプトを生成しています
araqnid

@brooksbp:制限付きのみ。ID 103fa49のオブジェクトはdf85b51をデコードする必要があるかもしれませんが、103fa49を受け取ったとき、df85b51はまだそこにありません(パックファイルはsha1ハッシュによって厳密に順序付けられています)。したがって、すでに存在するもののみを参照するものはすべて簡単ですが、それ以外の場合は、それが受信されるまで待つ必要があります。そして、このデルタ圧縮は入れ子にすることができるので、103fa49には4e9ba42が必要で、次に29ad945が必要で、c9e645aが必要です。[はい、4年以上経過していることに気づきました;)]
Bodo Thiesen 2017年

2
@brooksbp:結局、私は間違っていました。パックファイルは、sha1ハッシュでソートする必要はありません。また、書き込み時には、オブジェクトが必要とする前にgitが必要なオブジェクトを書き込みます。したがって、実際にはそれを並列化できるはずです。残っている唯一の欠点:後で必要になるオブジェクトがわからないため、何度も何度も作成し直す必要があります。ここを参照してください:kernel.org/pub/software/scm/git/docs/technical/...
ボードーThiesen

4

アンバーは、Mercurialなどが使用するオブジェクトモデルを説明しているようです。Gitは、オブジェクトの後続のバージョン間の差分を保存するのではなく、毎回オブジェクトの完全なスナップショットを保存します。次に、これらのスナップショットをデルタ圧縮を使用して圧縮し、履歴のどこに存在するかに関係なく、使用する適切なデルタを見つけようとします。


5
実際、Gitはルーズオブジェクトを格納できますが、必ずしもそのように格納されるとは限りません。ルースオブジェクトは削除してパックされたコンテンツで置き換えることができるためです。アンバーの答えがその後のバージョンについて何かを言ったとは思いません。
AlBlue
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.