26

Git リポジトリを実行git gcまたはgit repack上書きすると、完了すると「合計」行が出力されます。これらの数字は何を意味するのでしょうか?

かなり小さなリポジトリからのいくつかの例:

$ git gc
...
Total 576 (delta 315), reused 576 (delta 315)

$ git repack -afd --depth=250 --window=250
...
Total 576 (delta 334), reused 242 (delta 0)

そして、はるかに大きなリポジトリからの 1 つ:

$ git gc
...
Total 347629 (delta 289610), reused 342219 (delta 285060)
...

最初の「合計」数は、リポジトリ内の Git オブジェクト (つまり、コミット、ツリー、およびファイル) の数であると推測できます。他のすべては実際にはどういう意味ですか?

私はすでにgit-gc(1)およびgit-repack(1)man ページを見て、それらの「関連項目」も熟読しましたが、Google で検索しようとしても、無関係な結果しか得られませんでした。

4

1 に答える 1

27

私は、Git の純粋な Python 実装であるdulwichを使用していくつかの作業を行いました。ここで私が言おうとしていることは、正規の git ソースではなく、dulwich の git 実装での私の経験を反映しているため、違いがあるかもしれません。

Git は驚くほどシンプルです。名前は、その愚かさのために非常に賢いデザインに本当に適しています。

何かをコミットすると、git はインデックス (ステージング領域) にあるものを取得して SHA ダイジェスト アイテムを作成します。そのため、各ファイルは SHA 処理され、各ディレクトリ内のファイルは BLOB オブジェクトとして SHA 処理され、もちろんディレクトリ構造はツリー オブジェクトとして SHA 処理されます。 SHAも持つコミットオブジェクトにバインドされるすべてのもの。Git は、コミットを処理するときに、これらを .git/objects のファイリング システムに直接送信します。そこにあるそれらすべての起動に成功した場合、最新のコミット オブジェクトの SHA を .git/refs/heads/ に書き込むだけです。

時々、コミットが途中で失敗することがあります。.git/objects への書き込みに失敗した場合、git はその時点でクリーンアップを行いません。これは、通常、問題を修正してコミットをやり直すためです。この場合、git は以前に停止した場所、つまりコミットの途中から正確に再起動します。

ここで git gc の出番です。.git/objects 内のすべてのオブジェクトを単純に解析し、何らかの方法で HEAD または BRANCH によって参照されるすべてのオブジェクトをマークします。明らかに残っているものは孤立しており、「重要」なものとは何の関係もないため、削除できます。これが、ブランチを作成し、そのブランチで何らかの作業を行った後、そのブランチを破棄して git リポジトリからそのブランチへの参照を削除すると、実行される定期的な git gc によってブランチが完全に削除される理由です。これは一部の古い VCS ユーザーを驚かせる可能性があります。たとえば、CVS はクラッシュしたり破損したりしたとき以外は何も忘れませんでした (よくあることです)。

git repack (実際には git-pack-objects) は git gc とはまったく異なります (例: git gc は git repack を呼び出すかもしれませんが、別のコマンドと操作です)。先に述べたように、git はすべてを独自の SHAed ファイルに入れるだけです。ディスクストレージに移動する前にそれらをgzipしますが、明らかにこれは長期的にはスペース効率が良くありません. つまり、git-pack-objects が行うことは、一連の SHA オブジェクトを調べて、リビジョン間でデータが複製される場所を探すことです。それがどの種類の SHA オブジェクトであるかは気にしません。すべてがパッキングに対して等しいと見なされます。次に、意味のあるバイナリ デルタを生成し、ロット全体を .pack ファイルとして .git/objects/pack に保存し、パックされたオブジェクトを通常のディレクトリ構造から削除します。

最新のパック ファイルのサイズが 1Mb 未満の場合、通常、git-pack-objects は既存の .pack ファイルを置き換えるのではなく、新しい .pack ファイルを作成することに注意してください。したがって、時間が経つにつれて、複数の .pack ファイルが .git/objects/pack に表示されるようになります。実際、git fetch を実行するときは、リモート リポジトリに、アンパックされたすべてのアイテムをパックし、フェッチ リポジトリにない .pack ファイルをフェッチ リポジトリに送信するように依頼するだけです。git repack は単に git-pack-objects を呼び出しますが、適切と思われる .pack ファイルをマージするように指示します。これは、変更されたものを解凍し、バイナリ デルタを再生成して再圧縮することを意味します。

したがって、質問に答えるために、合計行は git リポジトリ内のオブジェクトの合計数を指します。最初のデルタ数は、バイナリ デルタ オブジェクトであるオブジェクトの総数です。つまり、他のオブジェクトと強い類似性があり、バイナリ デルタとして格納できると git が判断したオブジェクトの数です。再利用された数は、圧縮されたソース (パックファイルなど) からのオブジェクトのうち、最近の変更を含めるために再圧縮されていないものがいくつ使用されているかを示します。これは、複数のパックファイルがあり、最新の SHA オブジェクトが古いパックファイル内のアイテムをベースとして参照し、それにデルタを適用してモダンにする場合に発生します。これにより、以前に圧縮されたデータの古いリビジョンを git が利用できるようになり、再圧縮して最近の追加を含める必要がなくなります。

一般的に言えば、再利用回数が多いということは、完全な再パック (つまり git repack -a) を使用して一部のスペースを再利用できることを示しています。ただし、通常、git はこれらすべてを黙って処理します。また、完全なリパックを行うと、パックが異なるため、いくつかの git fetch が強制的に最初からやり直される場合があります。これはサーバーの設定によって異なります (クライアントごとのカスタム パックの生成を許可すると、サーバーの CPU に負荷がかかるため、一部の主要な GIT サイトでは無効になっています)。

うまくいけば、これはあなたの質問に答えます。本当に git を使用すると、最初はとても簡単に機能することに驚きます。真の天才プログラマーだけが、これほど単純でありながらうまく機能するものを書くことができます。

ニール

于 2012-02-27T14:42:45.213 に答える