SYNOPSIS

$GIT_DIR/objects/pack/pack-*.{pack,idx}
$GIT_DIR/objects/pack/pack-*.rev
$GIT_DIR/objects/pack/pack-*.mtimes
$GIT_DIR/objects/pack/multi-pack-index

DESCRIPTION

The Git pack format is how Git stores most of its primary repository data. Over the lifetime of a repository, loose objects (if any) and smaller packs are consolidated into larger pack(s). See git-gc(1) and git-pack-objects(1).

パック形式は通信(over-the-wire)でも使用されます。 たとえば gitprotocol-v2(5) を参照して下さい。 そして、 gitformat-bundle(5) では他のコンテナ形式の一部です。

Checksums and object IDs

従来のSHA-1を使用するリポジトリでは、以下で説明するパックチェックサム、インデックスチェックサム、およびオブジェクトID(オブジェクト名)はすべてSHA-1を使用して計算されます。 同様に、SHA-256リポジトリでは、これらの値はSHA-256を使用して計算されます。

pack-*.pack files have the following format:

  • ヘッダーは最初にあらわれ、以下のもので構成されます

    4-byte シグネチャ

    The signature is: {P, A, C, K}

    4-byte version number (network byte order)

    Gitは現在バージョン番号2または3を受け入れますが、バージョン2のみを生成します。

    4-byte パックに含まれるオブジェクトの数(network byte order)

    所見: このバージョンでは、パック内のオブジェクトは4Gを超えることはできず、パックも4Gを超えることはできません。

4-byte signature: The signature is: {P, A, C, K}

4-byte version number (network byte order): Git currently accepts version number 2 or 3 but generates version 2 only.

4-byte パックに含まれるオブジェクトの数(network byte order)
所見: このバージョンでは、パック内のオブジェクトは4Gを超えることはできず、パックも4Gを超えることはできません。
  • The header is followed by a number of object entries, each of which looks like this:

    (undeltified representation)
    n-byte type and length (3-bit type, (n-1)*7+4-bit length)
    compressed data

(deltified representation) n-byte type and length (3-bit type, (n-1)*7+4-bit length) base object name if OBJ_REF_DELTA or a negative relative offset from the delta object’s position in the pack if this is an OBJ_OFS_DELTA object compressed delta data

Observation: the length of each object is encoded in a variable length format and is not constrained to 32-bit or anything.
  • トレーラー(trailer)は、上記のすべてのパックチェックサムを記録します。

Object types

有効なオブジェクトタイプは以下のとおりです:

  • OBJ_COMMIT (1)

  • OBJ_TREE (2)

  • OBJ_BLOB (3)

  • OBJ_TAG (4)

  • OBJ_OFS_DELTA (6)

  • OBJ_REF_DELTA (7)

タイプ5は、将来の拡張用に予約されています。 タイプ0は無効です。

Size encoding

このドキュメントでは、負でない整数で、「サイズエンコーディング」(size encoding)を使用します。つまりそれは、 各バイトから、下位7ビットを使用して結果の整数を形成します。 最上位ビットが1である限り、この処理は続行されます。 MSB 0 のバイトは、最後の7ビットを提供します。これら7ビットのチャンクは連結されます。 後の値の方が上位です。

このサイズエンコーディング(size encoding)を、このドキュメントでも使用されている「オフセットエンコーディング」(offset encoding)と混同しないでください。

Deltified representation(デルタ化表現)

概念的には、commit、tree、tag、blobの4つのオブジェクトタイプしかありません。 ただし、スペースを節約するために、オブジェクトを別の「ベース」(base)オブジェクトの「デルタ」(delta)として格納できます。 これらの表現には、パックファイルでのみ有効な新しいタイプの ref-delta および ofs-delta が割り当てられます。

ofs-deltaとref-deltaはどちらも、オブジェクトを再構築するために別のオブジェクト(「ベースオブジェクト」と呼ばれる)に適用される「デルタ」を格納します。 それらの違いは、ref-deltaがベースオブジェクト名を直接エンコードすることです。 ベースオブジェクトが同じパックにある場合、ofs-deltaは代わりにパック内のベースオブジェクトのオフセットをエンコードします。

同一パックに含まれている場合は、ベースオブジェクトを削除することもできます。 ref-deltaは、パック外のオブジェクト(つまり、いわゆる「薄いパック」(thin pack))を参照することもできます。 ただし、ディスクに保存する場合は、循環依存を回避するためにパックを自己完結型にする必要があります。

The delta data starts with the size of the base object and the size of the object to be reconstructed. These sizes are encoded using the size encoding from above. The remainder of the delta data is a sequence of instructions to reconstruct the object from the base object. If the base object is deltified, it must be converted to canonical form first. Each instruction appends more and more data to the target object until it’s complete. There are two supported instructions so far: one for copying a byte range from the source object and one for inserting new data embedded in the instruction itself.

各命令の長さは可変です。 命令タイプは、最初のオクテット(訳注:1バイト(8ビット))のビット7(訳注:つまりこのバイトの最上位ビット)によって決定されます。 以下の図は、RFC 1951(Deflate compressed data format;圧縮データ形式の解凍)の規則に従います。

ベースオブジェクトからのコピー命令

+----------+---------+---------+---------+---------+-------+-------+-------+
| 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 |
+----------+---------+---------+---------+---------+-------+-------+-------+

これは、ソースオブジェクトからバイト範囲をコピーするための命令です。 コピー元のオフセットとコピーするバイト数をエンコードします。 オフセットとサイズはリトルエンディアンです。

All offset and size bytes are optional. This is to reduce the instruction size when encoding small offsets or sizes. The first seven bits in the first octet determine which of the next seven octets is present. If bit zero is set, offset1 is present. If bit one is set offset2 is present and so on.

注意: よりコンパクトな形式は、オフセットとサイズのエンコーディングを変更しないことに注意してください。 たとえば、以下のようにoffset2のみが省略されている場合でも、offset3にはビット16〜23が含まれています。 それはoffset1の隣に続くからoffset2という訳ではなくて、(offset3の)ビット8〜15が含まれています。

+----------+---------+---------+
| 10000101 | offset1 | offset3 |
+----------+---------+---------+

最もコンパクトな形式では、この命令はオフセットとサイズの両方が省略された1バイト(0x80)のみを使用し、デフォルト値はゼロになります。 もうひとつ例外があります。サイズゼロは自動的に 0x10000 に変換されます。

新データ追加命令

+----------+============+
| 0xxxxxxx |    data    |
+----------+============+

This is the instruction to construct the target object without the base object. The following data is appended to the target object. The first seven bits of the first octet determine the size of data in bytes. The size must be non-zero.

Reserved instruction

+----------+============
| 00000000 |
+----------+============

これは、将来の拡張のために予約されている命令です。

Original (version 1) pack-*.idx files have the following format:

  • ヘッダーは、256個の4バイトのネットワークバイトオーダー整数で構成されます。このテーブルのN番目のエントリは、対応するパック内のオブジェクトの数を記録します。オブジェクト名の最初のバイトはN以下です。これは、「first-level fan-out」テーブルと呼ばれます。

  • ヘッダーの後には、ソートされた24バイトのエントリが続きます(パック内のオブジェクトごとに1つのエントリ)。 各エントリは以下のとおりです:

    • 4-byte ネットワークバイトオーダー整数で、オブジェクトが格納されている場所をパックファイル先頭からのオフセットとして記録します。

    • 適切なサイズの1つのオブジェクト名。

  • ファイルはトレーラーで締めくくられています:

    対応するパックファイルの最後にあるパックチェックサムのコピー。

  • 上記すべてのインデックスチェックサム。

パックIdxファイル:

        --  +--------------------------------+
fanout      | fanout[0] = 2 (for example)    |-.
table       +--------------------------------+ |
            | fanout[1]                      | |
            +--------------------------------+ |
            | fanout[2]                      | |
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
            | fanout[255] = total objects    |---.
        --  +--------------------------------+ | |
main        | offset                         | | |
index       | object name 00XXXXXXXXXXXXXXXX | | |
table       +--------------------------------+ | |
            | offset                         | | |
            | object name 00XXXXXXXXXXXXXXXX | | |
            +--------------------------------+<+ |
          .-| offset                         |   |
          | | object name 01XXXXXXXXXXXXXXXX |   |
          | +--------------------------------+   |
          | | offset                         |   |
          | | object name 01XXXXXXXXXXXXXXXX |   |
          | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   |
          | | offset                         |   |
          | | object name FFXXXXXXXXXXXXXXXX |   |
        --| +--------------------------------+<--+
trailer   | | packfile checksum              |
          | +--------------------------------+
          | | idxfile checksum               |
          | +--------------------------------+
          .-------.
                  |
Pack file entry: <+

パックされたオブジェクトのヘッダー:

byte size extension bit (MSB)
  • type (next 3 bit)

  • size0 (lower 4-bit)

  • n-byte sizeN (MSBがセットされている限り。各7ビット) size0..sizeN form 4+7+7+..+7 ビット整数で、size0 は最も下位で、 sizeN が最も上位です。

パックされたオブジェクトのデータ
  • DELTAでない場合は、解凍されたバイト(上記のサイズは圧縮前のサイズです)。

  • REF_DELTAの場合、ベースオブジェクト名(上記サイズは後続のデルタデータのサイズです)。

  • 圧縮されたデルタデータ。

  • OFS_DELTAの場合、nバイトオフセット(以下参照)は、ofs-deltaエントリのヘッダーのタイプバイトからの負のオフセットとして解釈されます(上記サイズは、後続のデルタデータのサイズです)。

  • 圧縮されたデルタデータ。

offset encoding

最後の1つを除くすべてにMSBが設定されたnバイト。 オフセットは、各バイトの下位7ビットを連結して作成された数値であり、n >= 2 の場合、結果に 2^7 + 2^14 + ... + 2^(7*(n-1)) を加算します。

バージョン2 pack-*.idx ファイルは4GiBより大きいパックをサポートし、他のいくつかの再編成があります。それらの形式は以下のとおりです:

  • 4-byte マジックナンバー \377tOc は、 unreasonable fanout[0] 値です。

  • 4-byte バージョン番号 (= 2)

  • v1と同様の256エントリのファンアウトテーブル。

  • ソートされたオブジェクト名のテーブル。 これらはオフセット値なしで一緒にパックされ、特定のオブジェクト名のバイナリ検索のキャッシュフットプリント(cache footprint)を削減します。

  • パックされたオブジェクトデータの4バイトCRC32値のテーブル。 これはv2の新機能で、再パック中に、未検出データ破損無しで圧縮データをパックからパックに直接コピーできます。

  • 4バイトのオフセット値のテーブル(ネットワークバイトオーダー)。 これらは通常31ビットパックファイルオフセットですが、ラージオフセットは、msbitが設定された次のテーブルへのインデックスとしてエンコードされます。

  • 8バイトのオフセットエントリのテーブル(2 GiB未満のパックファイルの場合は空)。 パックファイルは、頻繁に使用されるオブジェクトを手前に配置するように編成されているため、ほとんどのオブジェクト参照はこのテーブルを参照する必要はありません。

    • v1パックファイルと同一のトレーラー:

      A copy of the pack checksum at the end of the
      corresponding packfile.
      上記すべてのインデックスチェックサム。

pack-*.rev ファイルは以下の形式です:

  • 4-byte マジックナンバー 0x52494458 (RIDX).

  • 4-byte バージョンID(= 1)。

  • 4-byte ハッシュ機能ID(= 1:SHA-1, 2:SHA-256)。

  • インデックス位置のテーブル(パックされたオブジェクトごとに1つ、合計 num_objects、それぞれネットワークオーダーで4バイトの符号なし整数)。パックファイル内の対応するオフセットでソートされます。

  • トレーラーは、対応するパックファイルのチェックサムと、上記のすべてのチェックサムを含みます。

全ての 4-byte 数値はネットワークオーダーです。

pack-*.mtimes files have the format:

全ての 4バイト数はネットワーク・バイト・オーダーです。

  • 4バイト。マジック・ナンバー 0x4d544d45 (MTME)

  • 4-byte バージョンID(= 1)。

  • 4-byte ハッシュ機能ID(= 1:SHA-1, 2:SHA-256)。

  • 4バイトの符号なし整数の表。 i 番目の値は、 対応するパック内の i 番目のオブジェクトの変更時間(mtime)であり、 辞書順(インデックス順)です。 mtimes は、 標準エポック秒をカウントします。

  • 対応するパックファイルのチェックサムと上記すべてのチェックサムを含むトレーラー (それぞれ指定されたハッシュ関数に応じた長さ)。

multi-pack-index (MIDX) ファイルの形式は以下の通り:

multi-pack-indexファイルは、複数のパックファイル(pack-files)と緩いオブジェクト(loose objects)を参照します。

MIDXにデータを追加する拡張機能を使用できるようにするために、ボディを「チャンク」に編成し、ボディの先頭にルックアップテーブルを提供します。 ヘッダーには、パックの数、ベースMIDXファイルの数、ハッシュの長さ、タイプなど、特定の長さ値達が含まれます。

全ての 4-byte 数値はネットワークオーダーです。

HEADER:

4-byte シグネチャ

The signature is: {M, I, D, X}

1-byte バージョン番号

Gitはバージョン 1 のみを書き込みまたは認識します。

1-byte オブジェクトIDバージョン(= 1: SHA-1, 2: SHA-256)

この値からオブジェクトID(OID)の長さを推測します。 ハッシュタイプがリポジトリのハッシュアルゴリズムと一致しない場合は、multi-pack-indexファイルを無視して、ユーザーに警告を表示する必要があります。

1-byte チャンクの数

チャンクの数

1-byte 「ベース multi-pack-index ファイル」の数

この値は現在のところ常にゼロです。

4-byte パックファアイルの数

パックファアイルの数

CHUNK LOOKUP:

  • (C + 1) * 12 bytes はチャンクオフセットを提供します

    最初の4バイトはチャンクIDです。値 0 はラベル終端です。

    他の8バイトは、現在のファイルでチャンクを開始するためのオフセットを提供します。(チャンクはファイル順に提供されるため、必要に応じて次のチャンク位置を使用して長さを推測できます。)

  • CHUNK LOOKUP は、チャンク・ベースのファイル形式の目次と一致します。 gitformat-chunk(5) を参照してください。

  • ボディの残りのデータは一度に1つのチャンクで記述され、これらのチャンクは任意の順序で指定できます。 特に指定がない限り、チャンクは必要です。

CHUNK DATA:

Packfile Names (ID: {P, N, A, M})

パックファイル名達を連結されたnullで終了する文字列として格納します。名前による高速ルックアップを行うには、パックファイルを辞書式順序でリストする必要があります。 これは、長さが4バイトの倍数であることが保証されていない唯一のチャンクであるため、アライメント上の理由から最後のチャンクにする必要があります。

OID Fanout (ID: {O, I, D, F})

i番目のエントリF[i]は、最初のバイトが最大iのOIDの数を格納します。 したがって、F[255]はオブジェクトの総数を格納します。

OID Lookup (ID: {O, I, D, L})

MIDX内のすべてのオブジェクトのOIDは、このチャンクに辞書式順序(lexicographic order)で格納されます。

Object Offsets (ID: {O, O, F, F})

オブジェクトごとに2つの4バイト値を格納します。

  1. このオブジェクトを格納するパックの pack-int-id。

  2. パック内オフセット。 すべてのオフセットが 2^32 未満(less than)の場合、 巨大オフセット・チャック(large offset chunk)は存在せず、 IDX v1 としてオフセットが格納されます。 2^32-1 を超える(larger than)オフセット値が少なくとも 1 つある場合、 巨大オフセット・チャック(large offset chunk)が存在する必要があり、 2^31-1 を超えるオフセットはそこに格納されなければなりません。 巨大オフセット・チャック(large offset chunk)が存在し、 31 番目のビットがオンの場合、 そのビットを削除すると、 このオブジェクトの 8バイト・オフセットを含む、巨大オフセット(large offsets)の行位置が判ります。

[オプション] Object Large Offsets (ID: {L, O, F, F})

8-byte 大きなパックファイル(large packfiles)へのオフセット。

[Optional] Bitmap pack order (ID: {R, I, D, X})

MIDX 位置のリスト(MIDX 内のオブジェクトごとに 1 つ、 合計で num_objects 個、 それぞれがネットワーク・バイト順で 4 バイトの符号なし整数)で、相対的な ビットマップ/疑似パック 位置に従って並べ替えられます。

TRAILER:

(C + 1) * 12 bytes providing the chunk offsets: First 4 bytes describe chunk id. Value 0 is a terminating label. Other 8 bytes provide offset in current file for chunk to start. (Chunks are provided in file-order, so you can infer the length using the next chunk position if necessary.)

CHUNK LOOKUP は、チャンク・ベースのファイル形式の目次と一致します。 linkgit:gitformat-chunk[5] を参照してください。
ボディの残りのデータは一度に1つのチャンクで記述され、これらのチャンクは任意の順序で指定できます。 特に指定がない限り、チャンクは必要です。

CHUNK DATA:

Packfile Names (ID: {'P', 'N', 'A', 'M'})
    Store the names of packfiles as a sequence of NUL-terminated
    strings. There is no extra padding between the filenames,
    and they are listed in lexicographic order. The chunk itself
    is padded at the end with between 0 and 3 NUL bytes to make the
    chunk size a multiple of 4 bytes.
Bitmapped Packfiles (ID: {'B', 'T', 'M', 'P'})
    Stores a table of two 4-byte unsigned integers in network order.
    Each table entry corresponds to a single pack (in the order that
    they appear above in the `PNAM` chunk). The values for each table
    entry are as follows:
    - The first bit position (in pseudo-pack order, see below) to
      contain an object from that pack.
    - The number of bits whose objects are selected from that pack.

OID Fanout (ID: {O, I, D, F}) The ith entry, F[i], stores the number of OIDs with first byte at most i. Thus F[255] stores the total number of objects.

OID Lookup (ID: {O, I, D, L}) The OIDs for all objects in the MIDX are stored in lexicographic order in this chunk.

Object Offsets (ID: {O, O, F, F}) Stores two 4-byte values for every object. 1: The pack-int-id for the pack storing this object. 2: The offset within the pack. If all offsets are less than 232, then the large offset chunk will not exist and offsets are stored as in IDX v1. If there is at least one offset value larger than 232-1, then the large offset chunk must exist, and offsets larger than 2^31-1 must be stored in it instead. If the large offset chunk exists and the 31st bit is on, then removing that bit reveals the row in the large offsets containing the 8-byte offset of this object.

[Optional] Object Large Offsets (ID: {L, O, F, F}) 8-byte offsets into large packfiles.

[Optional] Bitmap pack order (ID: {R, I, D, X}) A list of MIDX positions (one per object in the MIDX, num_objects in total, each a 4-byte unsigned integer in network byte order), sorted according to their relative bitmap/pseudo-pack positions.

TRAILER:

Index checksum of the above contents.

multi-pack-index reverse indexes

パックベースのリバースインデックスと同様に、マルチパックインデックスを使用してリバースインデックスを生成することもできます。

この逆インデックスは、offset、pack-、index の位置の間でマッピングする代わりに、MIDX内のオブジェクトの位置と、MIDXが記述する疑似パック内のそのオブジェクトの位置の間でマッピングします(つまり、マルチパック逆インデックスのi番目のエントリは、i番目のオブジェクトのMIDX位置を疑似パック順に保持します)。

これらの順序の違いを明確にするために、マルチパック到達可能性ビットマップ(まだ存在していませんが、現在これを目指して開発中です)を検討してください。 各ビットはMIDX内のオブジェクトに対応する必要があるため、ビット位置からMIDX位置への効率的なマッピングが必要です。

解決策の一つは、ビットがMIDXによって格納された、oidソートされたインデックスの同じ位置を占めるようにすることです。 ただし、oidは事実上ランダムであるため、結果として得られる到達可能性ビットマップには局所性がなく、圧縮が不十分になります。 (これが、シングルパックビットマップが同じ目的で、 .idx順序ではなく、パック順序を使用する理由です。)

そのため、パックの順序に基づいてMIDX全体の順序を定義します。これにより、局所性が大幅に向上します(したがって、より効率的に圧縮されます)。 MIDX内のすべてのパックを連結して作成された疑似パックを考えることができます。 たとえば、3つのパック(a、b、c)、それぞれ10、15、および20個のオブジェクトを含むMIDXがある場合、以下のようなオブジェクトの順序を想像できます:

|a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|

ここで、パックの順序はMIDXのパックリストによって定義され、各パック内のオブジェクトの順序は実際のパックファイルでの順序と同じです。

パックのリストとオブジェクトの数を考えると、その疑似パックの順序を簡単に再構築できます(たとえば、パック「a」と「b」がスロットの25を消費したため、位置27のオブジェクトは(c、1)でなければなりません)。 しかし、落とし穴があります。 オブジェクトはパック間で複製される可能性があるのです。その場合、MIDXはオブジェクトへのポインターを1つだけ格納します(したがって、ビットマップに1つのスロットのみが必要です)。

呼び出し元は、ビット位置の順にオブジェクトを読み取ることで重複を処理できますが、オブジェクトの数は直線的であり、通常のビットマップルックアップにはコストがかかりすぎます。 逆インデックスを作成すると、これが解決されます。これは、インデックスの論理的な逆であり、そのインデックスはすでに重複を削除しているためです。 ただし、その場で逆インデックスを作成すると、コストがかかる可能性があります。 パックベースの逆インデックス用のオンディスク形式がすでにあるので、MIDXの疑似パックにも再利用する事しましょう。

MIDXのオブジェクトは、疑似パックをつなぎ合わせるために次のように順序付けられます。 pack(o) がMIDXによって o が選択されたパックを返し、(MIDXによって保存された)数値IDに基づいてパックの順序を定義します。 offset(o) が pack(o) 内の o のオブジェクトオフセットを返すようにします。 次に、o1 と` o2`を以下のように比較します:

  • pack(o1) と pack(o2) の一方が優先され、もう一方が優先されない場合、優先される方が最初にソートされます。

    (詳細に言うと、これは、MIDXビットマップがビット位置0にあるオブジェクトを含むパックをMIDXに求めることができるので、パック再利用メカニズムによって使用されるべきパックを決定することを可能にします)。

  • pack(o1) ≠ pack(o2) の場合、パックIDに基づいて2つのオブジェクトを降順で並べ替えます。

  • それ以外の場合、 pack(o1) = pack(o2) であり、オブジェクトはパック順に並べ替えられます(つまり、 offset(o1) < offset(o2) の場合、o1o2 よりも先に並べ替えられます)。

要するに、MIDXの擬似パックは、MIDXによって保存されたパック内のオブジェクトをパック順に並べ、パックをMIDX順(優先パックが先に来る)に並べたものを重複排除して連結したものです。

MIDX の逆インデックスは、 MIDX 自体内の、オプションの RIDX チャンクに格納されます。

BTMP chunk

The Bitmapped Packfiles (BTMP) chunk encodes additional information about the objects in the multi-pack index’s reachability bitmap. Recall that objects from the MIDX are arranged in "pseudo-pack" order (see above) for reachability bitmaps.

From the example above, suppose we have packs "a", "b", and "c", with 10, 15, and 20 objects, respectively. In pseudo-pack order, those would be arranged as follows:

|a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|

When working with single-pack bitmaps (or, equivalently, multi-pack reachability bitmaps with a preferred pack), git-pack-objects(1) performs “verbatim” reuse, attempting to reuse chunks of the bitmapped or preferred packfile instead of adding objects to the packing list.

When a chunk of bytes is reused from an existing pack, any objects contained therein do not need to be added to the packing list, saving memory and CPU time. But a chunk from an existing packfile can only be reused when the following conditions are met:

  • The chunk contains only objects which were requested by the caller (i.e. does not contain any objects which the caller didn’t ask for explicitly or implicitly).

  • All objects stored in non-thin packs as offset- or reference-deltas also include their base object in the resulting pack.

The BTMP chunk encodes the necessary information in order to implement multi-pack reuse over a set of packfiles as described above. Specifically, the BTMP chunk encodes three pieces of information (all 32-bit unsigned integers in network byte-order) for each packfile p that is stored in the MIDX, as follows:

bitmap_pos

The first bit position (in pseudo-pack order) in the multi-pack index’s reachability bitmap occupied by an object from p.

bitmap_nr

The number of bit positions (including the one at bitmap_pos) that encode objects from that pack p.

For example, the BTMP chunk corresponding to the above example (with packs “a”, “b”, and “c”) would look like:

bitmap_pos

bitmap_nr

packfile “a”

0

10

packfile “b”

10

15

packfile “c”

25

20

With this information in place, we can treat each packfile as individually reusable in the same fashion as verbatim pack reuse is performed on individual packs prior to the implementation of the BTMP chunk.

cruft packs

残り物パック(cruft pack)機能は、 到達不能オブジェクトを削除するという Git の従来のメカニズムに代わる手段を提供します。 このドキュメントでは、 Git の刈り込み(pruning)メカニズムの概要と、 代わりに残り物パックを使用して同一のことを実現する方法について説明します。

Background

到達不能なオブジェクトをリポジトリから削除するために、 Git は git repack -Ad を提供しています(git-repack(1) を参照)。 以下、ドキュメントから引用します:

[...] 以前のパックの到達不能オブジェクトは、 古いパックに残されるのではなく、
パック解凍された緩いブジェクトになります。 [...] 到達不能なオブジェクトは、
次の `git gc` 呼び出しで通常の有効期限ルールに従って削除されます。

到達不能なオブジェクトはすぐには削除されません。 すぐに削除してしまうと、 削除しようとしているオブジェクトを参照する可能性のある後続のプッシュと競合する可能性があるためです。 代わりに、 これらの到達不能オブジェクトは緩いオブジェクトとして保存され、 期限切れウィンドウ(expiration window)より古くなるまでそのままの状態で保管されます。 期限切れになった時点で git-prune(1) で削除されます。

Git は、オブジェクトごとの mtime を追跡するために、 これらの到達不能オブジェクトを緩い(loose)オブジェクトに保存する必要があります。 これらの到達不能オブジェクトが 1 つの大きなパックに書き込まれた場合、 そのパックを(その中に含まれるオブジェクトが書き直されたため)リフレッシュするするか、 または到達不能オブジェクトの新しいパックを作成すると、 パックの mtime が更新され、 その中のオブジェクトが有効期限ウィンドウから離脱することは決してありません。 代わりに、 個々のオブジェクトの mtimes を追跡し、 すべての残り物(cruft)オブジェクトが一度に更新される状況を回避するために、 オブジェクトは緩いオブジェクトとして格納されます。

これにより、猶予期間を過ぎていない到達不能オブジェクトがリポジトリに多数含まれている場合に、望ましくない状況が発生する可能性があります。 .git/objects の一部(shard)に大きなディレクトリがあると、 リポジトリのパフォーマンスが低下する可能性があります。 また、 到達不能なオブジェクトがとても沢山ある場合、 i ノードの枯渇につながり、 システム全体のパフォーマンスを低下させる可能性があります。 これらのオブジェクトをパックすることはできないため、 これらのリポジトリは多くの場合、 大量のディスク領域を占有します。 それらは zlib 圧縮することしかできず、デルタ・チェーンに格納することはできないためです。

Cruft packs

残り物パック(cruft pack)は、 すべての緩い(loose)オブジェクトを含む単一のパックと一緒に、 オブジェクトごとの mtimes を別のファイルに含めることで、 到達不能なオブジェクトを緩いオブジェクト状態で保存する必要をなくします。

残り物パックは、 新しいパックを生成するときに git repack --cruft によって書き込まれます。 注意: git repack --cruft は古典的なオールインワンの再パックであることに注意してください。 つまり、結果のパック内のすべてが到達可能であり、 他のすべては到達不能です。 --cruft オプションを記述すると、git repack に対して、前のステップでパックされなかったオブジェクトのみを含む別のパックを生成するように指示されます (これは、すべての到達不能オブジェクトを一緒にパックすることと同じです)。 これは以下のとおりに進行します:

  1. すべてのオブジェクトを列挙し、 (a)「keep-pack に含まれていないオブジェクト」および、 (b)「mtime がトラバーサル・ヒントとしての猶予期間内にあるオブジェクト」をマークします。

  2. 前のステップで収集したヒントに基づいて到達可能性のトラバーサルを実行し、 その途中ですべてのオブジェクトをパックに追加します。

  3. オブジェクトごとのタイムスタンプを記録する .mtimes ファイルとともに、 パックを書き出します。

このモードは、 残り物パック(cruft pack)を作成するように指示されたときに、 git-repack(1) によって内部的に呼び出されます。 重要なことは、コア内に保持されたパックのセットは、 再パックによって削除されないパックのセットであることで、 つまり、リポジトリの到達可能なすべてのオブジェクトが含まれています。

リポジトリに既に残り物パック(cruft pack)がある場合、 git repack --cruft は通常、 それにオブジェクトを追加するだけです。 これに対する例外は、 git repack--cruft-expiration オプションが与えられた場合です。 これにより生成された残り物パックは、 後で git-gc(1) がそれらのオブジェクトを期限切れにするのを待つ代わりに、 期限切れのオブジェクトを省略できます。

通常、 期限切れの到達不能オブジェクトの削除を担当するのは git-gc(1) です。

Alternatives

この設計の注目すべき代替案は以下のとおりです:

  • The location of the per-object mtime data.

mtime データの配置においては、 .idx 形式の複雑化を避けるために、 パックに関連付けられた新しい補助ファイルが選択されました。 .idx 形式がオプションのデータ・チャンクのサポートを獲得したならば、 .mtimes 形式を .idx 自体に統合することは理にかなっているかもしれません。

GIT

Part of the git(1) suite