Einrichtung und Konfiguration
Projekte holen und erstellen
Grundlegende Snapshots
Branching und Merging
Projekte teilen und aktualisieren
Inspektion und Vergleich
Patching
Debugging
Externe Systeme
Server-Administration
Anleitungen
- gitattributes
- Konventionen der Kommandozeile
- Tägliches Git
- Häufig gestellte Fragen (FAQ)
- Glossar
- Hooks
- gitignore
- gitmodules
- Revisionen
- Submodule
- Tutorial
- Workflows
- Alle Anleitungen...
Administration
Plumbing-Befehle
-
2.52.0
2025-11-17
- 2.44.1 → 2.51.2 keine Änderungen
-
2.44.0
2024-02-23
- 2.43.1 → 2.43.7 keine Änderungen
-
2.43.0
2023-11-20
- 2.41.1 → 2.42.4 keine Änderungen
-
2.41.0
2023-06-01
- 2.38.1 → 2.40.4 keine Änderungen
-
2.38.0
2022-10-02
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
BESCHREIBUNG
Das Git Pack-Format ist, wie Git die meisten seiner primären Repository-Daten speichert. Über die Lebensdauer eines Repositorys werden lose Objekte (falls vorhanden) und kleinere Packs zu größeren Packs konsolidiert. Siehe git-gc[1] und git-pack-objects[1].
Das Pack-Format wird auch über das Netzwerk verwendet, siehe z. B. gitprotocol-v2[5], und ist auch Teil anderer Containerformate im Fall von gitformat-bundle[5].
Prüfsummen und Objekt-IDs
In einem Repository, das das traditionelle SHA-1 verwendet, werden Pack-Prüfsummen, Index-Prüfsummen und Objekt-IDs (Objektnamen), die unten erwähnt werden, alle mit SHA-1 berechnet. Ebenso werden in SHA-256-Repositories diese Werte mit SHA-256 berechnet.
CRC32-Prüfsummen werden immer über das gesamte gepackte Objekt berechnet, einschließlich des Headers (n-Byte-Typ und -Länge); des Basisobjektnamens oder Offsets, falls vorhanden; und des gesamten komprimierten Objekts. Der verwendete CRC32-Algorithmus ist der von zlib.
pack-*.pack Dateien haben das folgende Format
-
Ein Header erscheint am Anfang und besteht aus Folgendem
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 number of objects contained in the pack (network byte order)
Observation: we cannot have more than 4G versions ;-) and more than 4G objects in a pack.
-
Dem Header folgt eine Anzahl von Objekt-Einträgen, von denen jeder wie folgt aussieht
(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.
-
Der Trailer zeichnet eine Pack-Prüfsumme von allem oben Genannten auf.
Objekttypen
Gültige Objekttypen sind
-
OBJ_COMMIT (1)
-
OBJ_TREE (2)
-
OBJ_BLOB (3)
-
OBJ_TAG (4)
-
OBJ_OFS_DELTA (6)
-
OBJ_REF_DELTA (7)
Typ 5 ist für zukünftige Erweiterungen reserviert. Typ 0 ist ungültig.
Objekt-Kodierung
Im Gegensatz zu losen Objekten haben gepackte Objekte kein Präfix, das Typ, Größe und ein NUL-Byte enthält. Diese sind nicht notwendig, da sie durch den n-Byte-Typ und die Länge, die den Daten vorangestellt sind, bestimmt werden können, und daher aus den komprimierten und deltifizierten Daten weggelassen werden.
Die Berechnung der Objekt-ID verwendet dieses Präfix immer noch, indem es bei Bedarf aus Typ und Länge rekonstruiert wird.
Größenkodierung
Dieses Dokument verwendet die folgende "Größenkodierung" von nicht-negativen ganzen Zahlen: Von jedem Byte werden die sieben niederwertigsten Bits verwendet, um die resultierende ganze Zahl zu bilden. Solange das höchstwertige Bit 1 ist, wird dieser Prozess fortgesetzt; das Byte mit MSB 0 liefert die letzten sieben Bits. Die Sieben-Bit-Chunks werden verkettet. Spätere Werte sind signifikanter.
Diese Größenkodierung sollte nicht mit der "Offset-Kodierung" verwechselt werden, die ebenfalls in diesem Dokument verwendet wird.
Bei der Kodierung der Größe eines undeltifizierten Objekts in einem Pack ist die Größe die des unkomprimierten Rohobjekts. Für deltifizierte Objekte ist es die Größe des unkomprimierten Deltas. Der Basisobjektname oder der Offset sind nicht in der Größenberechnung enthalten.
Deltifizierte Darstellung
Konzeptionell gibt es nur vier Objekttypen: Commit, Tree, Tag und Blob. Um jedoch Platz zu sparen, könnte ein Objekt als "Delta" eines anderen "Basis"-Objekts gespeichert werden. Diesen Darstellungen werden neue Typen zugewiesen: ofs-delta und ref-delta, die nur in einer Pack-Datei gültig sind.
Sowohl ofs-delta als auch ref-delta speichern das "Delta", das auf ein anderes Objekt (genannt Basisobjekt) angewendet wird, um das Objekt zu rekonstruieren. Der Unterschied zwischen ihnen ist, dass ref-delta direkt den Basisobjektnamen kodiert. Wenn das Basisobjekt im selben Pack ist, kodiert ofs-delta stattdessen den Offset des Basisobjekts im Pack.
Das Basisobjekt könnte ebenfalls deltifiziert werden, wenn es im selben Pack ist. Ref-delta kann auch auf ein Objekt außerhalb des Packs verweisen (d. h. das sogenannte "Thin Pack"). Wenn es auf der Festplatte gespeichert wird, sollte das Pack jedoch in sich abgeschlossen sein, um zyklische Abhängigkeiten zu vermeiden.
Die Delta-Daten beginnen mit der Größe des Basisobjekts und der Größe des zu rekonstruierenden Objekts. Diese Größen werden mit der obigen Größenkodierung kodiert. Der Rest der Delta-Daten ist eine Sequenz von Anweisungen zur Rekonstruktion des Objekts aus dem Basisobjekt. Wenn das Basisobjekt deltifiziert ist, muss es zuerst in kanonische Form konvertiert werden. Jede Anweisung hängt mehr und mehr Daten an das Zielobjekt an, bis es vollständig ist. Bisher werden zwei Anweisungen unterstützt: eine zum Kopieren eines Bytebereichs aus dem Quellobjekt und eine zum Einfügen neuer Daten, die in die Anweisung selbst eingebettet sind.
Jede Anweisung hat variable Länge. Der Anweisungstyp wird durch das siebte Bit des ersten Oktetts bestimmt. Die folgenden Diagramme folgen der Konvention in RFC 1951 (Deflate compressed data format).
Anweisung zum Kopieren aus dem Basisobjekt
+----------+---------+---------+---------+---------+-------+-------+-------+ | 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 | +----------+---------+---------+---------+---------+-------+-------+-------+
Dies ist das Anweisungsformat zum Kopieren eines Bytebereichs aus dem Quellobjekt. Es kodiert den Offset, von dem kopiert werden soll, und die Anzahl der zu kopierenden Bytes. Offset und Größe sind in Little-Endian-Reihenfolge.
Alle Offset- und Größenbytes sind optional. Dies dient dazu, die Anweisungsgröße bei der Kodierung kleiner Offsets oder Größen zu reduzieren. Die ersten sieben Bits des ersten Oktetts bestimmen, welches der nächsten sieben Oktette vorhanden ist. Wenn Bit Null gesetzt ist, ist offset1 vorhanden. Wenn Bit Eins gesetzt ist, ist offset2 vorhanden und so weiter.
Beachten Sie, dass eine kompaktere Anweisung die Offset- und Größenkodierung nicht ändert. Wenn beispielsweise nur offset2 weggelassen wird, wie unten gezeigt, enthält offset3 immer noch die Bits 16-23. Es wird nicht zu offset2 und enthält die Bits 8-15, auch wenn es direkt neben offset1 liegt.
+----------+---------+---------+ | 10000101 | offset1 | offset3 | +----------+---------+---------+
In seiner kompaktesten Form benötigt diese Anweisung nur ein Byte (0x80) mit weggelassenen Offset- und Standardwerten von Null. Es gibt eine weitere Ausnahme: Größe Null wird automatisch in 0x10000 umgewandelt.
Anweisung zum Hinzufügen neuer Daten
+----------+============+ | 0xxxxxxx | data | +----------+============+
Dies ist die Anweisung zum Erstellen des Zielobjekts ohne das Basisobjekt. Die folgenden Daten werden an das Zielobjekt angehängt. Die ersten sieben Bits des ersten Oktetts bestimmen die Größe der Daten in Bytes. Die Größe muss ungleich Null sein.
Originale (Version 1) pack-*.idx Dateien haben das folgende Format
-
Der Header besteht aus 256 4-Byte-Ganzzahlen in Netzwerk-Byte-Reihenfolge. Der N-te Eintrag dieser Tabelle zeichnet die Anzahl der Objekte im entsprechenden Pack auf, deren Objektname (erstes Byte) kleiner oder gleich N ist. Dies wird als First-Level Fan-out Tabelle bezeichnet.
-
Dem Header folgen sortierte 24-Byte-Einträge, ein Eintrag pro Objekt im Pack. Jeder Eintrag ist
4-byte network byte order integer, recording where the object is stored in the packfile as the offset from the beginning.
one object name of the appropriate size.
-
Die Datei wird mit einem Trailer abgeschlossen
A copy of the pack checksum at the end of the corresponding packfile.
Index checksum of all of the above.
Pack Idx Datei
-- +--------------------------------+
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: <+
packed object header:
1-byte size extension bit (MSB)
type (next 3 bit)
size0 (lower 4-bit)
n-byte sizeN (as long as MSB is set, each 7-bit)
size0..sizeN form 4+7+7+..+7 bit integer, size0
is the least significant part, and sizeN is the
most significant part.
packed object data:
If it is not DELTA, then deflated bytes (the size above
is the size before compression).
If it is REF_DELTA, then
base object name (the size above is the
size of the delta data that follows).
delta data, deflated.
If it is OFS_DELTA, then
n-byte offset (see below) interpreted as a negative
offset from the type-byte of the header of the
ofs-delta entry (the size above is the size of
the delta data that follows).
delta data, deflated.
offset encoding: n bytes with MSB set in all but the last one. The offset is then the number constructed by concatenating the lower 7 bit of each byte, and for n >= 2 adding 2^7 + 2^14 + ... + 2^(7*(n-1)) to the result.
Version 2 pack-*.idx Dateien unterstützen Packs größer als 4 GiB und
have some other reorganizations. They have the format:
-
Eine 4-Byte-Magische Zahl \377tOc, die ein unwahrscheinlicher Fanout[0]-Wert ist.
-
Eine 4-Byte-Versionsnummer (= 2)
-
Eine 256-Einträge-Fan-out-Tabelle genau wie bei v1.
-
Eine Tabelle von sortierten Objektnamen. Diese sind ohne Offset-Werte zusammengepackt, um den Cache-Footprint der binären Suche nach einem bestimmten Objektnamen zu reduzieren.
-
Eine Tabelle von 4-Byte-CRC32-Werten der gepackten Objektdaten. Dies ist neu in v2, so dass komprimierte Daten während des Repackens direkt von Pack zu Pack kopiert werden können, ohne dass es zu unentdeckten Datenbeschädigungen kommt.
-
Eine Tabelle von 4-Byte-Offset-Werten (in Netzwerk-Byte-Reihenfolge). Dies sind normalerweise 31-Bit-Pack-Datei-Offsets, aber große Offsets werden als Index in die nächste Tabelle mit gesetztem MSBit kodiert.
-
Eine Tabelle von 8-Byte-Offset-Einträgen (leer für Pack-Dateien kleiner als 2 GiB). Pack-Dateien sind so organisiert, dass stark genutzte Objekte sich vorne befinden, daher müssen die meisten Objektverweise nicht auf diese Tabelle verweisen.
-
Der gleiche Trailer wie bei einer v1-Pack-Datei
A copy of the pack checksum at the end of the corresponding packfile.
Index checksum of all of the above.
pack-*.rev Dateien haben das Format
-
Eine 4-Byte-Magische Zahl 0x52494458 (RIDX).
-
Eine 4-Byte-Hashfunktionskennung (= 1 für SHA-1, 2 für SHA-256).
-
Eine 4-Byte-Versionskennung (= 1).
-
Eine Tabelle von Indexpositionen (eine pro gepacktes Objekt, insgesamt num_objects, jeweils eine 4-Byte-Ganzzahl ohne Vorzeichen in Netzwerkordnung), sortiert nach ihren entsprechenden Offsets im Packfile.
-
Ein Trailer, der eine enthält
checksum of the corresponding packfile, and
a checksum of all of the above.
Alle 4-Byte-Zahlen sind in Netzwerkordnung.
pack-*.mtimes Dateien haben das Format
Alle 4-Byte-Zahlen sind in Netzwerk-Byte-Reihenfolge.
-
Eine 4-Byte-Magische Zahl 0x4d544d45 (MTME).
-
Eine 4-Byte-Hashfunktionskennung (= 1 für SHA-1, 2 für SHA-256).
-
Eine 4-Byte-Versionskennung (= 1).
-
Eine Tabelle von 4-Byte-Ganzzahlen ohne Vorzeichen. Der i-te Wert ist die Änderungszeit (mtime) des i-ten Objekts im entsprechenden Pack nach lexikografischer (Index-)Reihenfolge. Die mtimes zählen Standard-Epochensekunden.
-
Ein Trailer, der eine Prüfsumme des entsprechenden Packfiles und eine Prüfsumme von allem oben Genannten enthält (jeweils mit einer Länge gemäß der angegebenen Hashfunktion).
multi-pack-index (MIDX) Dateien haben das folgende Format
Die Multi-Pack-Index-Dateien verweisen auf mehrere Pack-Dateien und lose Objekte.
Um Erweiterungen zu ermöglichen, die zusätzliche Daten zum MIDX hinzufügen, organisieren wir den Body in "Chunks" und stellen eine Nachschlagetabelle am Anfang des Bodys bereit. Der Header enthält bestimmte Längenwerte, wie die Anzahl der Packs, die Anzahl der Basis-MIDX-Dateien, Hash-Längen und -Typen.
Alle 4-Byte-Zahlen sind in Netzwerkordnung.
HEADER
4-byte signature:
The signature is: {'M', 'I', 'D', 'X'}
1-byte version number:
Git only writes or recognizes version 1.
1-byte Object Id Version
We infer the length of object IDs (OIDs) from this value:
1 => SHA-1
2 => SHA-256
If the hash type does not match the repository's hash algorithm,
the multi-pack-index file should be ignored with a warning
presented to the user.
1-byte number of "chunks"
1-byte number of base multi-pack-index files:
This value is currently always zero.
4-byte number of pack files
CHUNK NACHSCHLAGE
(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.)
The CHUNK LOOKUP matches the table of contents from the chunk-based file format, see gitformat-chunk[5].
The remaining data in the body is described one chunk at a time, and these chunks may be given in any order. Chunks are required unless otherwise specified.
CHUNK DATEN
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 2^32, 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 2^32-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-Indizes
Ähnlich wie der Pack-basierte Reverse-Index kann auch der Multi-Pack-Index verwendet werden, um einen Reverse-Index zu generieren.
Anstatt zwischen Offset-, Pack- und Indexposition zu übersetzen, ordnet dieser Reverse-Index zwischen der Position eines Objekts innerhalb des MIDX und der Position dieses Objekts innerhalb eines Pseudo-Packs, das der MIDX beschreibt (d. h. der i-te Eintrag des Multi-Pack-Reverse-Index enthält die MIDX-Position des i-ten Objekts in Pseudo-Pack-Reihenfolge).
Um den Unterschied zwischen diesen Reihenfolgen zu verdeutlichen, betrachten wir eine Multi-Pack-Erreichbarkeits-Bitmap (die noch nicht existiert, aber worauf wir hier hinarbeiten), die wir für eine Multi-Pack-Erreichbarkeits-Bitmap erstellen. Jedes Bit muss einer Objektposition im MIDX entsprechen, und wir benötigen eine effiziente Zuordnung von Bitposition zu MIDX-Position.
Eine Lösung ist, Bits die gleiche Position im vom MIDX gespeicherten OID-sortierten Index einnehmen zu lassen. Aber da OIDs effektiv zufällig sind, hätten ihre resultierenden Erreichbarkeits-Bitmaps keine Lokalität und komprimieren daher schlecht. (Dies ist der Grund, warum Single-Pack-Bitmaps die Pack-Reihenfolge und nicht die .idx-Reihenfolge für denselben Zweck verwenden.)
Daher möchten wir eine Reihenfolge für den gesamten MIDX definieren, die sich um die Pack-Reihenfolge dreht, die eine weitaus bessere Lokalität aufweist (und somit effizienter komprimiert). Wir können uns einen Pseudo-Pack vorstellen, der durch die Verkettung aller Packs im MIDX erstellt wird. Wenn wir zum Beispiel einen MIDX mit drei Packs (a, b, c) mit 10, 15 bzw. 20 Objekten hätten, können wir uns eine Reihenfolge der Objekte vorstellen wie
|a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|
wobei die Reihenfolge der Packs durch die Packliste des MIDX definiert ist und dann die Reihenfolge der Objekte innerhalb jedes Packs die gleiche ist wie die Reihenfolge im tatsächlichen Packfile.
Angesichts der Liste der Packs und ihrer Objektanzahlen können Sie diesen Pseudo-Pack-Reihenfolge naiv rekonstruieren (z. B. muss das Objekt an Position 27 (c,1) sein, da die Packs "a" und "b" 25 der Slots verbraucht haben). Aber es gibt einen Haken. Objekte können zwischen Packs dupliziert werden, in welchem Fall der MIDX nur einen Zeiger auf das Objekt speichert (und wir somit nur einen Slot in der Bitmap wollen).
Aufrufer könnten Duplikate selbst behandeln, indem sie Objekte in der Reihenfolge ihrer Bit-Position lesen, aber das ist linear zur Anzahl der Objekte und viel zu teuer für normale Bitmap-Abfragen. Das Erstellen eines Reverse-Index löst dies, da es die logische Umkehrung des Index ist, und dieser Index Duplikate bereits entfernt hat. Aber das Erstellen eines Reverse-Index auf der Fliege kann teuer sein. Da wir bereits ein Festplattenformat für Pack-basierte Reverse-Indizes haben, lassen Sie es uns auch für den Pseudo-Pack des MIDX wiederverwenden.
Objekte aus dem MIDX werden wie folgt geordnet, um den Pseudo-Pack zu verketten. Sei pack(o) gibt das Pack zurück, aus dem o vom MIDX ausgewählt wurde, und definieren Sie eine Reihenfolge von Packs basierend auf ihrer numerischen ID (wie vom MIDX gespeichert). Sei offset(o) gibt den Objekt-Offset von o innerhalb von pack(o) zurück. Vergleichen Sie dann o1 und o2 wie folgt
-
Wenn eines von
pack(o1) undpack(o2) bevorzugt ist und das andere nicht, dann sortiert sich das bevorzugte zuerst.(Dies ist ein Detail, das es der MIDX-Bitmap ermöglicht festzustellen, welcher Pack vom Pack-Wiederverwendungsmechanismus verwendet werden soll, da sie den MIDX nach dem Pack fragen kann, das das Objekt an Bitposition 0 enthält).
-
Wenn pack(o1) ≠ pack(o2), dann sortieren Sie die beiden Objekte absteigend nach der Pack-ID.
-
Andernfalls ist
pack(o1)=pack(o2), und die Objekte werden in Pack-Reihenfolge sortiert (d. h.o1sortiert sich voro2genau dann, wenn offset(o1) < offset(o2)).
Kurz gesagt, ein Pseudo-Pack eines MIDX ist die de-duplizierte Verkettung von Objekten in Packs, die vom MIDX gespeichert werden, in Pack-Reihenfolge angelegt, und die Packs sind in MIDX-Reihenfolge angeordnet (mit dem bevorzugten Pack zuerst).
Der Reverse-Index des MIDX wird im optionalen RIDX-Chunk innerhalb des MIDX selbst gespeichert.
BTMP Chunk
Der Bitmapped Packfiles (BTMP) Chunk kodiert zusätzliche Informationen über die Objekte in der Erreichbarkeits-Bitmap des Multi-Pack-Index. Zur Erinnerung: Objekte aus dem MIDX werden für Erreichbarkeits-Bitmaps in "Pseudo-Pack"-Reihenfolge (siehe oben) angeordnet.
Aus dem obigen Beispiel, nehmen wir an, wir haben die Packs "a", "b" und "c" mit 10, 15 und 20 Objekten. In Pseudo-Pack-Reihenfolge wären diese wie folgt angeordnet
|a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|
Bei der Arbeit mit Single-Pack-Bitmaps (oder äquivalent Multi-Pack-Erreichbarkeits-Bitmaps mit einem bevorzugten Pack) führt git-pack-objects[1] "wörtliche" Wiederverwendung durch, indem versucht wird, Chunks der bitmapped oder bevorzugten Packdatei wiederzuverwenden, anstatt Objekte zur Packliste hinzuzufügen.
Wenn ein Byte-Chunk aus einem bestehenden Pack wiederverwendet wird, müssen keine darin enthaltenen Objekte zur Packliste hinzugefügt werden, was Speicher und CPU-Zeit spart. Ein Chunk aus einer bestehenden Packdatei kann jedoch nur wiederverwendet werden, wenn die folgenden Bedingungen erfüllt sind
-
Der Chunk enthält nur Objekte, die vom Aufrufer angefordert wurden (d. h. enthält keine Objekte, die der Aufrufer nicht explizit oder implizit angefordert hat).
-
Alle Objekte, die in Nicht-Thin-Packs als Offset- oder Referenz-Deltas gespeichert sind, enthalten auch ihr Basisobjekt im resultierenden Pack.
Der BTMP Chunk kodiert die notwendigen Informationen, um die Multi-Pack-Wiederverwendung über eine Menge von Packfiles wie oben beschrieben zu implementieren. Speziell kodiert der BTMP Chunk drei Informationen (alles 32-Bit unsigned Integers in Netzwerk-Byte-Reihenfolge) für jede Packdatei p, die im MIDX gespeichert ist, wie folgt
Zum Beispiel würde der BTMP Chunk, der dem obigen Beispiel entspricht (mit den Packs "a", "b" und "c"), so aussehen
bitmap_pos |
bitmap_nr |
|
|---|---|---|
Packdatei "a" |
|
|
Packdatei "b" |
|
|
Packdatei "c" |
|
|
Mit diesen Informationen kann jede Packdatei einzeln wiederverwendet werden, ähnlich wie die wörtliche Pack-Wiederverwendung auf einzelnen Packs vor der Implementierung des BTMP Chunks durchgeführt wird.
Cruft Packs
Die Cruft Packs-Funktion bietet eine Alternative zu Git's traditionellem Mechanismus zum Entfernen von unerreichbaren Objekten. Dieses Dokument gibt einen Überblick über Git's Pruning-Mechanismus und wie stattdessen ein Cruft Pack verwendet werden kann, um dasselbe zu erreichen.
Hintergrund
Um unerreichbare Objekte aus Ihrem Repository zu entfernen, bietet Git git repack -Ad (siehe git-repack[1]). Zitiert aus der Dokumentation
[...] unreachable objects in a previous pack become loose, unpacked objects, instead of being left in the old pack. [...] loose unreachable objects will be pruned according to normal expiry rules with the next 'git gc' invocation.
Unerreichbare Objekte werden nicht sofort entfernt, da dies mit einem eingehenden Push in Konflikt geraten könnte, der auf ein Objekt verweist, das gerade gelöscht wird. Stattdessen werden diese unerreichbaren Objekte als lose Objekte gespeichert und bleiben so, bis sie älter als das Ablaufzeitfenster sind, zu welchem Zeitpunkt sie von git-prune[1] entfernt werden.
Git muss diese unerreichbaren Objekte lose speichern, um ihre mtimes pro Objekt nachverfolgen zu können. Wenn diese unerreichbaren Objekte in ein einziges großes Pack geschrieben würden, würde entweder das Auffrischen dieses Packs (weil ein darin enthaltenes Objekt neu geschrieben wurde) oder das Erstellen eines neuen Packs mit unerreichbaren Objekten die mtime des Packs aktualisieren, und die Objekte darin würden niemals das Ablaufzeitfenster verlassen. Stattdessen werden Objekte lose gespeichert, um die individuellen Objekt-mtimes zu verfolgen und eine Situation zu vermeiden, in der alle Cruft-Objekte gleichzeitig aufgefrischt werden.
Dies kann zu unerwünschten Situationen führen, wenn ein Repository viele unerreichbare Objekte enthält, die das Gnadenzeitfenster noch nicht verlassen haben. Große Verzeichnisse in den Shards von .git/objects können zu einer geringeren Leistung des Repositorys führen. Aber bei genügend unerreichbaren Objekten kann dies zu Inode-Mangel führen und die Leistung des gesamten Systems beeinträchtigen. Da wir diese Objekte nie packen können, nehmen diese Repositorys oft viel Speicherplatz ein, da wir sie nur zlib-komprimieren, aber nicht in Delta-Ketten speichern können.
Cruft Packs
Ein Cruft Pack eliminiert die Notwendigkeit, unerreichbare Objekte im losen Zustand zu speichern, indem die mtimes pro Objekt in einer separaten Datei neben einem einzigen Pack gespeichert werden, das alle losen Objekte enthält.
Ein Cruft Pack wird von git repack --cruft beim Generieren eines neuen Packs geschrieben. Die Option --cruft von git-pack-objects[1]. Beachten Sie, dass git repack --cruft ein klassisches All-in-One-Repack ist, was bedeutet, dass alles im resultierenden Pack erreichbar ist und alles andere unerreichbar ist. Nach dem Schreiben weist die Option --cruft git repack an, ein weiteres Pack zu generieren, das nur Objekte enthält, die im vorherigen Schritt nicht gepackt wurden (was dem Packen aller unerreichbaren Objekte zusammen entspricht). Dies schreitet wie folgt vor
-
Zählen Sie jedes Objekt auf und markieren Sie jedes Objekt, das (a) nicht in einem gespeicherten Pack enthalten ist und (b) dessen mtime innerhalb des Gnadenzeitfensters liegt, als Traversal-Spitze.
-
Führen Sie eine Erreichbarkeits-Traversal basierend auf den im vorherigen Schritt gesammelten Spitzen durch und fügen Sie dabei jedes Objekt zum Pack hinzu.
-
Schreiben Sie das Pack aus, zusammen mit einer
.mtimes-Datei, die die Zeitstempel pro Objekt aufzeichnet.
Dieser Modus wird intern von git-repack[1] aufgerufen, wenn angewiesen, ein Cruft Pack zu schreiben. Entscheidend ist, dass die Menge der im Speicher gehaltenen Packs genau die Menge der Packs ist, die vom Repack nicht gelöscht werden; mit anderen Worten, sie enthalten alle erreichbaren Objekte des Repositorys.
Wenn ein Repository bereits ein Cruft Pack hat, fügt git repack --cruft normalerweise nur Objekte hinzu. Eine Ausnahme ist, wenn git repack mit der Option --cruft-expiration gegeben wird, die es dem generierten Cruft Pack ermöglicht, abgelaufene Objekte wegzulassen, anstatt darauf zu warten, dass git-gc[1] diese Objekte später ablaufen lässt.
Es ist git-gc[1], das typischerweise für die Entfernung abgelaufener unerreichbarer Objekte zuständig ist.
Alternativen
Bemerkenswerte Alternativen zu diesem Design sind
-
Der Speicherort der mtime-Daten pro Objekt.
Bezüglich des Speicherorts von mtime-Daten wurde eine neue Hilfsdatei, die mit dem Pack verknüpft ist, gewählt, um das .idx-Format nicht zu komplizieren. Wenn das .idx-Format jemals Unterstützung für optionale Datenblöcke erhalten sollte, könnte es sinnvoll sein, das .mtimes-Format in das .idx selbst zu integrieren.
GIT
Teil der git[1] Suite