git gc --aggressive vs git repack


88

gitリポジトリのサイズを小さくする方法を探しています。検索すると、git gc --aggressiveほとんどの場合につながります。また、これは好ましいアプローチではないことも読みました。

どうして?実行している場合は何に注意する必要がありgc --aggressiveますか?

git repack -a -d --depth=250 --window=250以上をお勧めしgc --aggressiveます。どうして?repackリポジトリのサイズをどのように削減しますか?また、フラグ--depthとについてはよくわかりません--window

との間で何を選択する必要がgcありrepackますか?ときに私が使用する必要がありますgcrepack

回答:


76

今日では違いはありませんgit gc --aggressive。2007年にLinusが行った提案に従って動作します。下記参照。バージョン2.11(2016年第4四半期)の時点で、gitのデフォルトの深さは50です。サイズ250のウィンドウは、各オブジェクトのより大きなセクションをスキャンするため適切ですが、250の深さは、すべてのチェーンが非常に古いものを参照するため、不適切です。オブジェクト。これにより、今後のすべてのgit操作が遅くなり、ディスク使用量がわずかに少なくなります。


歴史的背景

Linusは、次のようなgit gc --aggressive場合にのみ使用することを提案しました(完全なメーリングリストの投稿については、以下を参照してください)悪いパック」または「本当にひどく悪いデルタ」がある「ほとんどの場合、他の場合では、実際には本当に悪いですやるべき事。" その結果、リポジトリを開始したときよりも悪い状態のままになる可能性があります。

「長くて複雑な歴史」をインポートした後、これを適切に行うために彼が提案するコマンドは

git repack -a -d -f --depth=250 --window=250

ただし、これは、リポジトリ履歴から不要なガンクをすでに削除しており、git filter-branchドキュメントにあるリポジトリを縮小するためのチェックリストに従っていることを前提としています

git-filter-branchは、ファイルのサブセットを取り除くために使用できます。通常、--index-filter--subdirectory-filterます。人々は結果のリポジトリが元のリポジトリよりも小さいことを期待していますが、Gitは指示があるまでオブジェクトを失わないように努力するため、実際にリポジトリを小さくするにはさらにいくつかの手順が必要です。まず、次のことを確認してください。

  • ブロブがその存続期間にわたって移動された場合、ファイル名のすべてのバリアントを実際に削除しました。git log --name-only --follow --all -- filename名前の変更を見つけるのに役立ちます。

  • あなたは本当にすべての参照をフィルタリングしました:--tag-name-filter cat -- --allを呼び出すときに使用しgit filter-branchます。

次に、より小さなリポジトリを取得する2つの方法があります。より安全な方法は、元の状態を維持するクローンを作成することです。

  • でクローンしgit clone file:///path/to/repoます。クローンには削除されたオブジェクトはありません。git-cloneを参照してください。(プレーンパスでクローンを作成すると、すべてがハードリンクされることに注意してください!)

なんらかの理由で本当にクローンを作成したくない場合は、代わりに次の点を(この順序で)確認してください。これは非常に破壊的なアプローチなので、バックアップを作成するか、クローン作成に戻ります。あなたは警告されました。

  • git-filter-branchによってバックアップされた元の参照を削除します:say

    git for-each-ref --format="%(refname)" refs/original/ |
      xargs -n 1 git update-ref -d
    
  • すべてのreflogをgit reflog expire --expire=now --all。で期限切れにします。

  • ガベージは、で参照されていないすべてのオブジェクトを収集しますgit gc --prune=now(または、git gc引数をサポートするのに十分なほど新しくない場合は--prunegit repack -ad; git prune代わりに使用します)。


Date: Wed, 5 Dec 2007 22:09:12 -0800 (PST)
From: Linus Torvalds <torvalds at linux-foundation dot org>
To: Daniel Berlin <dberlin at dberlin dot org>
cc: David Miller <davem at davemloft dot net>,
    ismail at pardus dot org dot tr,
    gcc at gcc dot gnu dot org,
    git at vger dot kernel dot org
Subject: Re: Git and GCC
In-Reply-To: <4aca3dc20712052111o730f6fb6h7a329ee811a70f28@mail.gmail.com>
Message-ID: <alpine.LFD.0.9999.0712052132450.13796@woody.linux-foundation.org>
References: <4aca3dc20712051947t5fbbb383ua1727c652eb25d7e@mail.gmail.com>
            <20071205.202047.58135920.davem@davemloft.net>
            <4aca3dc20712052032n521c344cla07a5df1f2c26cb8@mail.gmail.com>
            <20071205.204848.227521641.davem@davemloft.net>
            <4aca3dc20712052111o730f6fb6h7a329ee811a70f28@mail.gmail.com>

2007年12月6日木曜日、ダニエルベルリンは次のように書いています。

実際、git-gc --aggressiveSVNリポジトリから変換したかどうかに関係なく、ファイルをパックするためにこのばかげたことが行われることがあります。

絶対に。git --aggressiveほとんど馬鹿です。これは、「本当に持っていることがわかっている」場合にのみ役立ちます。悪いパック自分が行った悪いパッキングの決定をすべて破棄したいます。

これを説明するために、git delta-chainsがどのように機能し、他のほとんどのシステムとどのように異なるかを説明する価値があります(おそらくご存知でしょうが、とにかく基本を説明します)。

他のSCMでは、デルタチェーンは一般的に固定されています。これは「順方向」または「逆方向」であり、リポジトリを操作するにつれて少し進化する可能性がありますが、通常は、ある種の単一のSCMエンティティとして表される単一のファイルへの一連の変更です。CVSでは、それは明らかに*,vファイルであり、他の多くのシステムはかなり似たようなことをします。

Gitはデルタチェーンも実行しますが、より「緩く」実行します。固定エンティティはありません。デルタは、gitが(さまざまなかなり成功したヒューリスティックを使用して)優れたデルタ候補であると見なすランダムな他のバージョンに対して生成され、厳密なグループ化ルールはまったくありません。

これは一般的に非常に良いことです。これはさまざまな概念上の理由で優れています(つまり、内部的にgitがリビジョンチェーン全体を気にする必要はありません。デルタに関してはまったく考えていません)が、柔軟性のないデルタルールを取り除くことは意味があるので素晴らしいことでもあります。たとえば、そのgitは、2つのファイルをマージすることにまったく問題はありません*,v。つまり、隠された意味を持つ任意の「リビジョンファイル」はありません。

また、デルタの選択がはるかに自由形式の質問であることも意味します。デルタチェーンを1つのファイルだけに制限すると、デルタをどうするかについての選択肢は実際には多くありませんが、gitでは、まったく別の問題になる可能性があります。

そして、これが本当にひどい名前の--aggressive出番です。gitは一般的にデルタ情報を再利用しようとしますが(それは良い考えであり、以前に見つけたすべての良いデルタを再検索するためにCPU時間を無駄にしないため)、時々あなたは「白紙の状態で最初からやり直し、以前のデルタ情報をすべて無視して、新しいデルタのセットを生成してみましょう」と言いたい。

つまり--aggressive、実際には積極的ではなく、CPU時間を無駄にして、以前に行った決定をやり直すことです。

時にはそれは良いことです。特に一部のインポートツールは、本当にひどく悪いデルタを生成する可能性があります。を使用するものgit fast-importたとえば、、デルタレイアウトがあまり優れていない可能性が高いため、「白紙の状態から始めたい」と言う価値があるかもしれません。

しかし、ほとんどの場合、他の場合では、それは実際には本当に悪いことです。CPU時間を浪費することになります。特に、以前にデルタ化で実際に優れた仕事をした場合、最終結果では、すでに見つけた優れたデルタをすべて再利用することはできないため、実際には多くの結果になります。悪い結果も!

git gc --aggressive ドキュメントを削除するためのパッチをJunioに送信します。これは便利な場合がありますが、通常は、それが何をしているのかを非常に深いレベルで本当に理解している場合にのみ役立ちます。そのドキュメントはそれを行うのに役立ちません。

一般に、インクリメンタルgit gcを実行することは正しいアプローチであり、実行するよりも優れていgit gc --aggressiveます。古いデルタを再利用し、それらの古いデルタが見つからない場合(そもそもインクリメンタルGCを実行する理由!)、新しいデルタを作成します。

一方、「長くて複雑な歴史の最初のインポート」は、本当に良いデルタを見つけるために多くの時間を費やす価値があるポイントであることは間違いありませ。そうすれば、その後のすべてのユーザーは(git gc --aggressive元に戻すために使用しない限り!)、その1回限りのイベントを利用できます。したがって、特に長い歴史を持つ大規模なプロジェクトの場合は、デルタ検索コードをワイルドにするように指示して、追加の作業を行う価値があります。

したがって、適切にgit gc --aggressive実行れるのと同等のことは、次のようなことを(一晩で)行うことです

git repack -a -d --depth=250 --window=250

ここで、その深さはデルタチェーンの深さ(古い履歴では長くする-スペースオーバーヘッドの価値があります)であり、ウィンドウは各デルタ候補でスキャンするオブジェクトウィンドウの大きさです。

そして、ここで、-fフラグを追加することをお勧めします(これは、「古いデルタをすべて削除する」ことです。これは、これが実際に適切な候補を見つけることを実際に確認しようとしているためです。

そして、それは永遠に1日かかるでしょう(つまり、「一晩でやる」こと)。しかし、最終的には、そのリポジトリの下流にいるすべての人が、自分で労力を費やすことなく、はるかに優れたパックを入手できるようになります。

          Linus

2
深さについてのあなたのコメントは少し紛らわしいです。最初、私はあなたが完全に間違っていると不平を言うつもりでした、その攻撃はgitリポジトリを大幅にスピードアップすることができます。積極的なガベージコレクションを実行した後、gitステータスを実行するのに5分かかった巨大なリポジトリが数秒に短縮されました。しかし、その後、攻撃的なgcがリポジトリの速度を低下させるのではなく、非常に大きな深度サイズであることに気付きました。
user6856 2018

57

gc&repackはいつ使用する必要がありますか?

Gitガベージコレクションは完全には機能していないようです」で述べたように、aだけでgit gc --aggressiveは十分でも十分でもありません。
そして、以下説明するように、多くの場合、必要ありません。

最も効果的な組み合わせは、を追加することgit repackですが、git prune

git gc
git repack -Ad      # kills in-pack garbage
git prune           # kills loose garbage

注:Git 2.11(2016年第4四半期)では、デフォルトのgc aggressive深度が50に設定されます

Jeff King()によるcommit 07e7dbf(2016年8月11日)を参照してください。(合併によりJunio C浜野- -0952ca8コミットし、2016年9月21日)をpeff
gitster

gc:デフォルトの攻撃深度は50

" git gc --aggressive"は、デルタチェーンの長さを250に制限するために使用されていました。これは、スペースをさらに節約するには深すぎ、実行時のパフォーマンスに悪影響を及ぼします。
制限が50に減りました。

要約すると、現在のデフォルトの250はスペースをあまり節約せず、CPUのコストがかかります。それは良いトレードオフではありません。

--aggressive」フラグgit-gcは3つのことを行います。

  1. -f」を使用して、既存のデルタを破棄し、最初から再計算します
  2. 「--window = 250」を使用して、デルタを探しにくくします
  3. 「--depth = 250」を使用して、より長いデルタチェーンを作成します

アイテム(1)と(2)は、「アグレッシブ」な再パックに適しています。
彼らは、より良いパックを手に入れることを期待して、より多くの計算作業を行うように再パックに依頼します。再梱包中に費用を支払い、他の操作ではメリットのみが表示されます。

項目(3)はそれほど明確ではありません。
より長いチェーンを許可すると、デルタに対する制限が少なくなります。つまり、より適切なチェーンを見つけて、スペースを節約できる可能性があります。
ただし、デルタにアクセスする操作はより長いチェーンに従う必要があることも意味し、パフォーマンスに影響します。
したがって、これはトレードオフであり、トレードオフが適切なものであるかどうかは明らかではありません。

研究のためのコミットを参照してください)

深さを減らすと、通常の操作でのCPUの節約が向上することがわかります。
しかし、深さが増すにつれて、スペースの節約はそれほど大きくないこともわかります。10から50の間で5-10%節約することは、おそらくCPUのトレードオフの価値があります。50から100に移行するために1%節約すること、または100から250に移行するためにさらに0.5%節約することはおそらくそうではありません。


CPUの節約と言えば、「git repack」は--threads=<n>オプションを受け入れてパックオブジェクトに渡すことを学びました。

Junio C Hamano()によるcommit 40bcf31(2017年4月26日)を参照してください。(による合併Junio C浜野- -31fb6f4コミット、2017年5月29日)をgitster
gitster

再梱包:受け入れ--threads=<n>て、pack-objects

私たちはすでにとのためにそうし--window=<n>てい--depth=<n>ます; これは、ユーザーが--threads=1複数のスレッドのレースに影響されることなく、再現性のあるテストを強制したい場合に役立ちます。


3
「Gitガベージコレクションが完全に機能していないようです」リンクでLinusスレッドについて言及しました
VonC 2015

1
この最新のアップデートをありがとう!ここでの他のすべての答えは古いです。これがgit gc --aggressive2回修正されたことがわかります。1つは、2007年にLinusが「より良い梱包方法」として提案したことを行うことです。そして、Git 2.11では、Linusが提案したが有害であることが判明した過度のオブジェクトの深さを回避するために(将来のすべてのGit操作が遅くなり、話す価値のあるスペースを節約できませんでした)。
gw0 2017年

git gc、続いてgit repack-Adとgitpruneを使用すると、リポジトリのサイズが大きくなります...なぜですか?
devops 2017

@devopsわからない:どのバージョンのGitを使用していますか?そのための新しい質問をすることができます(OS、リポジトリの一般的なサイズなどの詳細を含む)
VonC 2017

man git-repack以下のために言う-d: `も実行Gitの冗長緩いオブジェクトfiles.`を削除するかんプルーン詰めgit pruneもそれを行いますか?man git-pruneと言うIn most cases, users should run git gc, which calls git prune.ので、その後の使用は何git gcですか?ただ使うほうがいいのではないgit repack -Ad && git gcでしょうか?
ヤコブ

14

の問題git gc --aggressiveは、オプション名とドキュメントが誤解を招くことです。

Linus自身はこのメールでは説明して、どのようなgit gc --aggressivebasicly行うことはこれです:

gitは通常、デルタ情報を再利用しようとしますが(これは良い考えであり、以前に見つけたすべての適切なデルタを再検索するためにCPU時間を無駄にしないため)、「最初からやり直しましょう。白紙の状態で、以前のデルタ情報をすべて無視し、新しいデルタのセットを生成してみてください。」

通常、gitはこれらのデルタを非常に柔軟に決定するため、gitでデルタを再計算する必要はありません。本当に、本当に悪いデルタがあることを知っている場合にのみ意味があります。Linusが説明しているように、主に使用するツールはgit fast-importこのカテゴリに分類されます。

ほとんどの場合、gitは有用なデルタを決定するのに非常に優れた仕事をしており、使用git gc --aggressiveすると、多くのCPU時間を浪費しながら、さらに悪化する可能性のあるデルタが残ります。


Linusはgit repack、大規模--depth--window、ほとんどの場合、より良い選択であるという結論でメールを終了します。特に大規模なプロジェクトをインポートし、gitが適切なデルタを見つけられるようにしたい場合は特にそうです。

したがって、git gc --aggressive-しかし適切に行われる-と同等のことは、(一晩)次のようなことを行うことです。

git repack -a -d --depth=250 --window=250

ここで、その深さはデルタチェーンの深さ(古い履歴では長くする-スペースオーバーヘッドの価値があります)であり、ウィンドウは各デルタ候補でスキャンするオブジェクトウィンドウの大きさです。

そして、ここで、-fフラグを追加することをお勧めします(これは、「古いデルタをすべて削除する」ことです。これは、これが実際に適切な候補を見つけることを実際に確認しようとしているためです。


8

注意。git gc --agressiveバックアップがない場合は、リモートと同期されていないリポジトリで実行しないでください。

この操作はデルタを最初から再作成し、適切に中断された場合、データ損失につながる可能性があります。

私の8GBコンピュータの場合、アグレッシブなgcは、1Gbリポジトリのメモリを10kの小さなコミットで使い果たしました。OOMキラーがgitプロセスを終了したとき-それは私にほとんど空のリポジトリを残し、作業ツリーといくつかのデルタだけが生き残った。

もちろん、それはリポジトリの唯一のコピーではなかったので、私はそれを再作成してリモートからプルしました(フェッチは壊れたリポジトリで機能せず、「デルタの解決」ステップでデッドロックを数回試みました)が、リポジトリがリモートをまったく使用しない単一開発者のローカルリポジトリ-最初にバックアップします。


5

注:git gc --aggressiveGit 2.22(2019年第2四半期)で明らかにされているように、の使用には注意してください。

参照0044f77をコミットしdaecbf2コミット7384504をコミットし22d4e3bコミット080a448をコミットし54d56f5をコミットしd257e0fをコミットしb6a8d09コミット(2019年4月7日)、およびfc559fbコミットcf9cd77をコミットしb11e856コミットにより(2019年3月22日)を(ÆvarアインホルトBjarmason avar
(合併によりJunio C浜野- gitster-ac70c53コミット、2019年4月25日)を

gc ドキュメント:の有用性を軽視する --aggressive

既存の " gc --aggressive"ドキュメントは、定期的に実行することをユーザーに推奨するには不十分です。
私は、このオプションを使用するためのアドバイスとしてこれらのドキュメントを利用している多くのユーザーと個人的に話をしましたが、通常は(ほとんど)時間の無駄です

それでは、それが実際に何をするのかを明確にし、ユーザーに独自の結論を導き出させましょう。

また、ジェフ・キングの説明の簡単なバージョンを言い換えるために、「効果[...]は永続的である」を明確にしましょう。

つまり、git-gcのドキュメントには次のものが含まれています

アグレッシブ

ときに--aggressiveオプションが供給されている、git-repackと呼び出される-f順番に渡しますフラグ、--no-reuse-deltaのgit-パック-オブジェクト
これにより、既存のデルタが破棄されて再計算されますが、再パッキングにより多くの時間が費やされます。

この影響はほとんど持続します。たとえば、パックとルーズオブジェクトが互いに合体した場合、そのパック内の既存のデルタが再利用される可能性がありますが、新しいものから次善のデルタを選択する場合もあります。代わりにパックしてください。

さらに、提供--aggressiveすると、に渡されるオプション--depth--windowオプションが微調整されgit-repackます。以下
gc.aggressiveDepthおよびgc.aggressiveWindow設定を参照してください。
より大きなウィンドウサイズを使用することで、より最適なデルタを見つける可能性が高くなります。

カスタマイズされたパフォーマンスベンチマークを実行せずに、特定のリポジトリでこのオプションを使用することはおそらく価値がありません
それにはもっと時間がかかり、結果として得られるスペース/デルタの最適化はそれだけの価値があるかもしれませんし、そうでないかもしれません。これをまったく使用しないことは、ほとんどのユーザーとそのリポジトリにとって正しいトレードオフです。

そして(コミット080a448):

gcドキュメント:ノートどのように--aggressive影響を与えます--window--depth

07e7dbfgc:デフォルトのアグレッシブ深度50、2016-08-11、Git v2.10.1)以降、デフォルトと同じ深度をやや紛らわしく使用--aggressiveしています。

理にかなっているそのコミットで述べたように、「アグレッシブ」のデフォルトをより深くして、ランタイムパフォーマンスを犠牲にしてディスクスペースを節約するのは間違っていました。これは通常、「アグレッシブgc」を望む人の反対です。欲求。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.