2
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Github謹製Gitリポジトリサイズ問題解析ツール「git-sizer」

こちらは、Gitリポジトリのさまざまなサイズメトリックを集計し、問題を引き起こす可能性のある箇所を解析する Github製のツールgit-sizerのREADME.mdの翻訳(ほとんどGoogle翻訳)です。

このREADME.mdは解析ツールの利用方法だけではなく、巨大Gitリポジトリを避けるための手法やベストプラクティスが詰まっているので、ついつい大きいリポジトリを作ってしまいがちな人は必見です。


幸せなGitリポジトリはすべて似ています。 不幸なGitリポジトリはすべて、それ自体が不幸です。 —Linus Tolstoy

git-sizer

あなたのGitリポジトリは溢れんばかりのサイズでしょうか?

git-sizer は、ローカルGitリポジトリのさまざまなサイズメトリックを計算し、問題や不便を引き起こす可能性があるものにフラグを立てます。 例えば:

  • リポジトリが全体的に大きすぎませんか? 理想的には、Gitリポジトリは1 GiB未満である必要があり、(特別な処理なしで)5 GiBを超えると扱いにくくなります。 大きなリポジトリでは、クローン作成とリパックに時間がかかり、多くのディスク容量が必要になります。 提案:

    • 生成されたファイル(コンパイラ出力、JARファイルなど)をGitに保存しないでください。 必要に応じてそれらを再生成するか、パッケージレジストリまたはファイルサーバーに保存することをお勧めします。
    • 大きなメディア資産をGitに保存しないでください。 Git-LFS または git-annex を調べてください。 実際にリポジトリの外部に保存しながら、Gitでメディアアセットをバージョン管理します。
    • 特に圧縮されている場合は、Gitにファイルアーカイブ(ZIPファイル、tarballなど)を保存しないでください。 そのようなファイルの異なるバージョンは、互いに十分に差分をとらないため、Gitはそれらを効率的に保存できません。 個々のファイルをリポジトリに保存するか、アーカイブを他の場所に保存することをお勧めします。
  • リポジトリの参照(ブランチやタグ)が多すぎませんか? たとえクローンが最新であっても、フェッチするたびにすべてクライアントに転送する必要があります。 せいぜい数万に制限してください。 提案:

    • 不要なタグとブランチを削除します。
    • 「リモートトラッキング」ブランチを共有リポジトリにプッシュしないでください。
    • タグではなく "git notes" を使用して、コミットに補助情報(たとえば、CIビルド結果)を添付することを検討してください。
    • まれに必要なタグとブランチの一部を、通常の開発者から取得されないリポジトリの別のフォークに保存することもできます。
  • リポジトリに含まれるオブジェクトが多すぎませんか? オブジェクトが多いほど、Gitがリポジトリの履歴をたどるのにかかる時間は長くなります(ガベージコレクションなど)。 提案:

    • いくつかの大きなファイルに簡単に収集できる非常に多くの小さなファイルを保存しているかどうかを考えてください。
    • プロジェクトを複数のサブプロジェクトに分割することを検討してください。
  • リポジトリには巨大なblob(ファイル)が含まれていますか? Gitは、中小規模のファイルで最適に機能します。 メガバイトの範囲でいくつかのファイルを作成しても問題ありませんが、通常は例外です。 提案:

    • Git-LFS を使用して、大きなファイル、特に便利に差分やマージを行わないファイル(メディアアセットなど)を保存することを検討してください。
    • 「リポジトリが全体的に大きすぎませんか?」のセクションも参照してください。
  • リポジトリには、大きなテキストファイルの多くの多くのバージョンが含まれており、それぞれが以前のものからわずかに変更されていますか? このようなファイルの差分は非常に良好であるため、リポジトリが驚くほど大きくなることはありません。 しかし、Gitが完全なファイルを再構築し、それらを差分化するのは高価です。これは多くの操作のために内部で行う必要があります。 提案:

    • ログファイルとデータベースダンプをGitに保存しないでください。
    • 特に頻繁に変更される場合は、Gitに巨大なデータファイル(巨大なXMLファイルなど)を保存しないでください。 代わりにデータベースの使用を検討してください。
  • リポジトリには巨大なツリー(ディレクトリ)が含まれていますか? ファイルが変更されるたびに、Gitはファイルに至るすべてのツリー(パス内のすべてのディレクトリ)の新しいコピーを作成する必要があります。 巨大な木はこれを高価にします。 さらに、たとえば「git blame」のように、巨大なツリーを含む履歴を走査するのは非常に高価です。 提案:

    • それぞれ数千エントリ以上のディレクトリを作成しないでください。
    • 非常に多くのファイルを保存する必要がある場合は、複数の小さなディレクトリの階層に分割することをお勧めします。
  • リポジトリーには、同じ(または非常に類似した)ファイルが1回のコミットで異なるパスで繰り返し繰り返されますか? その場合、リポジトリの全体的なサイズは妥当かもしれませんが、チェックアウトすると、膨大な作業コピーになります。 (極端に言えば、これは「git bomb」と呼ばれます。以下を参照してください。)提案:

    • おそらく、タグとブランチまたはビルド時の構成システムを使用することで、目標をより効果的に達成できます。
  • リポジトリにとてつもなく長いパス名が含まれていますか? それはおそらく他のツールではうまく機能しないでしょう。 Javaを作成している場合でも、100文字または200文字で十分です。

  • リポジトリには他にも奇妙で疑わしいものがありますか?

    • 長いチェーンで互いに指し示す注釈付きタグ?
    • Octopus mergesで数十の親を持つ?
    • 巨大なログメッセージでコミットする?

git-sizer は、リポジトリに関する多くのサイズ関連の統計を計算します。これは、上記のすべての問題を明らかにするのに役立ちます。 これらのプラクティス自体は間違っていませんが、Gitをそのスイートスポットを超えて伸ばすほど、Gitの伝説的なスピードとパフォーマンスを楽しむことができなくなります。 特に、Gitリポジトリの統計がプロジェクトのサイズに比例していないように思われる場合は、Gitの使用方法を調整することで、作業を楽にすることができる場合があります。

Getting started

  1. Gitコマンドラインクライアントがインストールされていることを確認してください、 version >= 2.6。 Note: git-sizerは、リポジトリの内容を調べるためにgitコマンドを呼び出します。そのため、git-sizerを実行するときは、gitコマンドが$PATH` に存在する必要があります。

  2. git-sizerのインストール. いずれか:

    a. git-sizerのリリースバージョンをインストールします(推奨):

    1. releases page に移動し、プラットフォームに対応するZIPファイルをダウンロードします。
    2. ファイルをunzipします。
    3. 実行可能ファイル(git-sizerまたはgit-sizer.exe)を $PATHに移動します。

    b. ソースからビルドしてインストールします。 docs/BUILDING.mdの手順を参照してください。

  3. 分析するGitリポジトリの完全なclone(non-shallow)を含むディレクトリに移動して次を実行する:

    git-sizer [<option>...]
    

    オプションは不要です。利用可能なオプションについては、git-sizer -hで学ぶ、もしくは読んでください。

Pro tip: $PATHgit-sizerを追加した場合、git-sizerまたはgit sizerと入力して実行できます。後者の場合、Gitによって検出されて実行され、2つの単語の間にgit -C /path/to/my/repo sizerのような追加のGitオプションを追加できます。 PATHgit-sizerを追加しない場合、もちろん実行するためにフルパスとファイル名を入力する必要があります。例: /path/to/bin/git-sizer。どちらの場合も、git実行可能ファイルは$PATHある必要があります

Usage

デフォルトでは、 git-sizerは結果を表形式で出力します。たとえば、すべての統計が出力されるように --verboseオプションを使用して、the Linux repository を分析するためにそれを使用してみましょう:

$ git-sizer --verbose
Processing blobs: 1652370
Processing trees: 3396199
Processing commits: 722647
Matching commits to trees: 722647
Processing annotated tags: 534
Processing references: 539
| Name                         | Value     | Level of concern               |
| ---------------------------- | --------- | ------------------------------ |
| Overall repository size      |           |                                |
| * Commits                    |           |                                |
|   * Count                    |   723 k   | *                              |
|   * Total size               |   525 MiB | **                             |
| * Trees                      |           |                                |
|   * Count                    |  3.40 M   | **                             |
|   * Total size               |  9.00 GiB | ****                           |
|   * Total tree entries       |   264 M   | *****                          |
| * Blobs                      |           |                                |
|   * Count                    |  1.65 M   | *                              |
|   * Total size               |  55.8 GiB | *****                          |
| * Annotated tags             |           |                                |
|   * Count                    |   534     |                                |
| * References                 |           |                                |
|   * Count                    |   539     |                                |
|                              |           |                                |
| Biggest objects              |           |                                |
| * Commits                    |           |                                |
|   * Maximum size         [1] |  72.7 KiB | *                              |
|   * Maximum parents      [2] |    66     | ******                         |
| * Trees                      |           |                                |
|   * Maximum entries      [3] |  1.68 k   | *                              |
| * Blobs                      |           |                                |
|   * Maximum size         [4] |  13.5 MiB | *                              |
|                              |           |                                |
| History structure            |           |                                |
| * Maximum history depth      |   136 k   |                                |
| * Maximum tag depth      [5] |     1     |                                |
|                              |           |                                |
| Biggest checkouts            |           |                                |
| * Number of directories  [6] |  4.38 k   | **                             |
| * Maximum path depth     [7] |    13     | *                              |
| * Maximum path length    [8] |   134 B   | *                              |
| * Number of files        [9] |  62.3 k   | *                              |
| * Total size of files    [9] |   747 MiB |                                |
| * Number of symlinks    [10] |    40     |                                |
| * Number of submodules       |     0     |                                |

[1]  91cc53b0c78596a73fa708cceb7313e7168bb146
[2]  2cde51fbd0f310c8a2c5f977e665c0ac3945b46d
[3]  4f86eed5893207aca2c2da86b35b38f2e1ec1fc8 (refs/heads/master:arch/arm/boot/dts)
[4]  a02b6794337286bc12c907c33d5d75537c240bd0 (refs/heads/master:drivers/gpu/drm/amd/include/asic_reg/vega10/NBIO/nbio_6_1_sh_mask.h)
[5]  5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c (refs/tags/v2.6.11)
[6]  1459754b9d9acc2ffac8525bed6691e15913c6e2 (589b754df3f37ca0a1f96fccde7f91c59266f38a^{tree})
[7]  78a269635e76ed927e17d7883f2d90313570fdbc (dae09011115133666e47c35673c0564b0a702db7^{tree})
[8]  ce5f2e31d3bdc1186041fdfd27a5ac96e728f2c5 (refs/heads/master^{tree})
[9]  532bdadc08402b7a72a4b45a2e02e5c710b7d626 (e9ef1fe312b533592e39cddc1327463c30b0ed8d^{tree})
[10] f29a5ea76884ac37e1197bef1941f62fda3f7b99 (f5308d1b83eba20e69df5e0926ba7257c8dd9074^{tree})

出力は、測定されたもの、その数値、および懸念の原因となる可能性のある値の大まかな指示を示す表です。すべての場合において、参照から到達可能なオブジェクトのみが含まれます(つまり、到達不能なオブジェクトや、reflogからのみ到達可能なオブジェクトではありません)。。

"Overall repository size"セクションには、繰り返しを含まない、個別のオブジェクトに関するリポジトリ全体の統計が含まれます。 "Total size"は、非圧縮形式の対応するオブジェクトのサイズの合計で、バイト単位で測定されます。
すべてのオブジェクトの全体的な非圧縮サイズは、 git gc --aggressive(およびgit repack [-f|-F]git pack-objects --no-reuse-deltaなどのコマンドがどれだけ高価かを示しています。 )、 git fsck、およびgit log [-G|-S]になります。圧縮されていないツリーとコミットのサイズは、クローンとフェッチ、git gcを含む、到達可能性のトラバースがどれほど高価になるかを示しています。

"Biggest objects" セクションでは、履歴のどこにいても、各タイプの最大の単一オブジェクトに関する情報を提供します。
"History structure"セクションでは、"maximum history depth"は履歴内のコミットの最長チェーンであり、"maximum tag depth"は他の注釈付きタグを指す注釈付きタグの最長チェーンを報告します。

"Biggest checkouts"セクションは、作業コピーにチェックアウトされたコミットのサイズに関するものです。 "Maximum path depth"は作業コピー内のファイルのパスコンポーネントの最大数であり、"maximum path length"はバイト単位の最長パスです。 "Total size of files"は、同じファイルが複数回出現する場合の多重度を含む、単一の最大コミットのすべてのファイルサイズの合計です。

"Value"列には、単位「k」(キロ)、「M」(メガ)、「G」(ギガ)などを使用してカウントが表示され、単位「B」(バイト)、「KiB」(1024バイト)、 "MiB"(1024 KiB)など。値がカウンターをオーバーフローする場合(これは悪意のあるリポジトリでのみ発生します)、対応する値は表形式で として表示されるか、2³²-1に切り捨てられます。またはJSONモードの2⁶⁴-1(カウンターのサイズに応じて)。

"Level of concern"列では、アスタリスク(*)を使用して、"典型的な"Gitリポジトリと比較して高いと思われる値を示しています。アスタリスクが多いほど、リポジトリのこの側面が引き起こすと予想される不便さが大きくなります。感嘆符(!)は、非常に高い値(つまり、30を超えるアスタリスク(*)に相当)を示します。

脚注には、テーブルで参照される"biggest"オブジェクトのSHA-1と、そのオブジェクトがリポジトリの履歴のどこにあるかについてのより人間が読める <commit>:<path>の説明がリストされています。ラージオブジェクトの名前を指定すると、たとえば次のように入力できます

git cat-file -p <commit>:<path>

コマンドラインで、オブジェクトの内容を表示します。 (これらの脚注を省略したい場合は、--names=noneを使用してください。)

デフォルトでは、懸念の最小レベルを超える統計のみが報告されます。 (上記のように)--verboseを使用して、すべての統計の出力を要求します。--threshold=<value>を使用して、指定された懸念レベルを下回る統計のレポートを抑制します。 (<value>はアスタリスク(*)の数に対応する数値として解釈されます。)--criticalを使用して、重大な懸念レベルの統計のみをレポートします(--threshold=30に相当)。

正確な数値を含む機械可読形式の出力が必要な場合は、 --jsonオプションを使用します。 --json-version=1または--json-version=2を使用して、古いスタイルと新しいスタイルのJSON出力を選択できます。

他のオプションのリストを取得するには以下を実行します

git-sizer -h

Linuxリポジトリは大きいリポジトリの標準です。ご覧のとおり、Gitの制限の一部を押し上げています。実際、LinuxリポジトリでのGitの操作(たとえば、git fsck, git gc)には時間がかかります。しかし、その健全な構造のために、その次元のいずれもコードベースのサイズに大きく比例していないため、カーネルプロジェクトはGitを使用して正常に管理されます。

以下は、有名な"git bomb"リポジトリの非冗長出力です:

$ git-sizer
[...]
| Name                         | Value     | Level of concern               |
| ---------------------------- | --------- | ------------------------------ |
| Biggest checkouts            |           |                                |
| * Number of directories  [1] |  1.11 G   | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
| * Maximum path depth     [1] |    11     | *                              |
| * Number of files        [1] |     ∞     | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
| * Total size of files    [2] |  83.8 GiB | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |

[1]  c1971b07ce6888558e2178a121804774c4201b17 (refs/heads/master^{tree})
[2]  d9513477b01825130c48c4bebed114c4b2d50401 (18ed56cbc5012117e24a603e7c072cf65d36d469^{tree})

このリポジトリは、同じディレクトリが繰り返し繰り返される病理学的なツリー構造を持つように、いたずらに構築されています。その結果、リポジトリ全体のサイズは20 kb未満ですが、チェックアウトすると、100億を超えるファイルを含む10億を超えるディレクトリに爆発します。 (git-sizerはblobカウントにを出力します。これは、そのフィールドに使用される32ビットカウンターが真の数でオーバーフローしたためです。)

Contributing

git-sizerは常用されており、現在も活発に開発されています。手伝いたい場合は、CONTRIBUTING.mdをご覧ください。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
2
Help us understand the problem. What are the problem?