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
Git パック形式は現在、Git のプライマリ・リポジトリ・データのほとんどを格納しています。 リポジトリの存続期間中、(もしあれば)緩いオブジェクトと小さなパックは、より大きなパック達に統合されていきます。 git-gc(1) と 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を超えることはできません。
-
ヘッダーの後には、オブジェクトエントリの数が続き、各エントリは以下のようになります
- (非デルタ化表現)
-
n-byte type and length (type:3ビット幅、length: (n-1)*7+4 ビット幅)
圧縮データ
- (デルタ化表現)
-
n-byte type and length (type:3ビット幅、length: (n-1)*7+4 ビット幅)
OBJ_REF_DELTAの場合はベースオブジェクト名、OBJ_OFS_DELTAオブジェクトの場合はパック内のデルタオブジェクトの位置からの負の相対オフセット
圧縮デルタデータ
-
所見: 各オブジェクトの長さは可変長形式でエンコードされ、32ビットなどに制限されません。
-
トレーラー(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))を参照することもできます。 ただし、ディスクに保存する場合は、循環依存を回避するためにパックを自己完結型にする必要があります。
デルタデータは、ベースオブジェクトのサイズと再構築されるオブジェクトのサイズから始まります。 これらのサイズは、上記サイズエンコーディングを使用してエンコードされます。 デルタデータの残りの部分は、ベースオブジェクトからオブジェクトを再構築するための一連の命令です。 ベースオブジェクトが削除されている場合は、最初に標準形に変換する必要があります。 各命令は、完了するまでターゲットオブジェクトにどんどんデータを追加します。現時点でサポートされている命令は2つあります。1つはソースオブジェクトからバイト範囲をコピーするためのもので、もう1つは命令自体に埋め込まれた新しいデータを挿入するためのものです。
各命令の長さは可変です。 命令タイプは、最初のオクテット(訳注:1バイト(8ビット))のビット7(訳注:つまりこのバイトの最上位ビット)によって決定されます。 以下の図は、RFC 1951(Deflate compressed data format;圧縮データ形式の解凍)の規則に従います。
ベースオブジェクトからのコピー命令
+----------+---------+---------+---------+---------+-------+-------+-------+
| 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 |
+----------+---------+---------+---------+---------+-------+-------+-------+
これは、ソースオブジェクトからバイト範囲をコピーするための命令です。 コピー元のオフセットとコピーするバイト数をエンコードします。 オフセットとサイズはリトルエンディアンです。
すべてのオフセットバイトとサイズバイトはオプションです。 これは、小さなオフセットまたはサイズをエンコードするときに命令サイズを減らすためです。 最初のオクテットの最初の7つのビット(訳注:bit6〜0)は、次の7つのオクテットのどれが存在するかを決定します。 ビットゼロが設定されている場合、offset1が存在します。 ビット1が設定されている場合、offset2が存在します。
注意: よりコンパクトな形式は、オフセットとサイズのエンコーディングを変更しないことに注意してください。 たとえば、以下のようにoffset2のみが省略されている場合でも、offset3にはビット16〜23が含まれています。 それはoffset1の隣に続くからoffset2という訳ではなくて、(offset3の)ビット8〜15が含まれています。
+----------+---------+---------+
| 10000101 | offset1 | offset3 |
+----------+---------+---------+
最もコンパクトな形式では、この命令はオフセットとサイズの両方が省略された1バイト(0x80)のみを使用し、デフォルト値はゼロになります。 もうひとつ例外があります。サイズゼロは自動的に 0x10000 に変換されます。
新データ追加命令
+----------+============+
| 0xxxxxxx | data |
+----------+============+
これは、ベースオブジェクトなしでターゲットオブジェクトを構築するための命令です。続くデータがターゲットオブジェクトに追加されます。最初のオクテットの最初の7つのビット(訳注:bit6〜0)は、データのサイズをバイト単位で決定します。サイズはゼロ以外でなければなりません。
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パックファイルと同一のトレーラー:
対応するパックファイルの最後にあるパックチェックサムのコピー。
-
上記すべてのインデックスチェックサム。
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バイト値を格納します。
-
このオブジェクトを格納するパックの pack-int-id。
-
パック内オフセット。 すべてのオフセットが
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:
-
上記の内容のインデックスチェックサム。
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)
の場合、o1
はo2
よりも先に並べ替えられます)。
要するに、MIDXの擬似パックは、MIDXによって保存されたパック内のオブジェクトをパック順に並べ、パックをMIDX順(優先パックが先に来る)に並べたものを重複排除して連結したものです。
MIDX の逆インデックスは、 MIDX 自体内の、オプションの RIDX
チャンクに格納されます。
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
に対して、前のステップでパックされなかったオブジェクトのみを含む別のパックを生成するように指示されます (これは、すべての到達不能オブジェクトを一緒にパックすることと同じです)。 これは以下のとおりに進行します:
-
すべてのオブジェクトを列挙し、 (a)「keep-pack に含まれていないオブジェクト」および、 (b)「mtime がトラバーサル・ヒントとしての猶予期間内にあるオブジェクト」をマークします。
-
前のステップで収集したヒントに基づいて到達可能性のトラバーサルを実行し、 その途中ですべてのオブジェクトをパックに追加します。
-
オブジェクトごとのタイムスタンプを記録する
.mtimes
ファイルとともに、 パックを書き出します。
このモードは、 残り物パック(cruft pack)を作成するように指示されたときに、 git-repack(1) によって内部的に呼び出されます。 重要なことは、コア内に保持されたパックのセットは、 再パックによって削除されないパックのセットであることで、 つまり、リポジトリの到達可能なすべてのオブジェクトが含まれています。
リポジトリに既に残り物パック(cruft pack)がある場合、 git repack --cruft
は通常、 それにオブジェクトを追加するだけです。 これに対する例外は、 git repack
に --cruft-expiration
オプションが与えられた場合です。 これにより生成された残り物パックは、 後で git-gc(1) がそれらのオブジェクトを期限切れにするのを待つ代わりに、 期限切れのオブジェクトを省略できます。
通常、 期限切れの到達不能オブジェクトの削除を担当するのは git-gc(1) です。
Caution for mixed-version environments
残り物パック(cruft pack)を含むリポジトリは、 古いバージョンの Git で引き続き動作します。 ただし、 .mtimes
ファイルを認識しない以前のバージョンの Git は、残り物パックの mtime をその中のすべてのオブジェクトの mtime として使用することに注意してください。 つまり、 Git の古い (残り物パック以前の) バージョンが .mtimes
ファイルの内容を解釈したり、読み取ったりすることを期待しないでください。
注意 Git GC実行結果のバージョンが混在していると、 到達不能なオブジェクトが完全に刈り込みされない可能性があることに注意してください。 これは以下の状況で発生する可能性があります:
-
古いバージョンの Git の GC 実行は、 残り物パックの mtime を使用して、 既存の残り物パックのコンテンツを緩いオブジェクトにします。
-
新しいバージョンのGit の GC 実行は、 これらの緩いオブジェクトを残り物パックに収集します。
.mtime
ファイルは緩いオブジェクトの実際の mtime を反映しますが、残り物パックの mtime の値は「現在」になります。
このプロセスを繰り返すと、 オブジェクトの mtime を現在の時刻に繰り返しリセットした結果、 到達不能オブジェクトが刈り込みされなくなります。
バージョンが混在する環境でリポジトリを GC する場合は、 git-repack(1) や git-gc(1) を使用するときに --cruft
オプションを省略し、 すべてのライター(writer)が残り物パック(cruft pack)を理解するまで gc.cruftPacks
設定を false
のままにすることを検討してください。
Alternatives
この設計の注目すべき代替案は以下のとおりです:
-
オブジェクトごとの mtime データの配置と、
-
到達不能なオブジェクトの複数の残り物パックへの格納。
mtime データの配置においては、 .idx
形式の複雑化を避けるために、 パックに関連付けられた新しい補助ファイルが選択されました。 .idx
形式がオプションのデータ・チャンクのサポートを獲得したならば、 .mtimes
形式を .idx
自体に統合することは理にかなっているかもしれません。
複数の残り物パック(cruft pack)間(たとえば、 各再パック操作中に、 以前の残り物パックにまだ格納されていない到達不能オブジェクトのみを含む新しい残り物パックを作成)で到達不能オブジェクトを格納することは、 構築するのが非常に複雑であるため、 ここでは追求しません。 現在の実装の明らかな欠点は、 残り物パック全体を最初から書き直さなければならないことです。
GIT
Part of the git(1) suite