gitformat-pack
Название
gitformat-pack — формат pack-файлов Git
Краткое описание
$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 Описание
Формат pack-файлов Git — это способ хранения большей части основных данных репозитория Git. Со временем свободные объекты (если они есть) и небольшие pack-файлы объединяются в более крупные pack-файлы. См. git-gc[1] и git-pack-objects[1].
Формат pack-файлов также используется при передаче данных по сети; см., например, gitprotocol-v2[5]. Кроме того, он входит в состав других контейнерных форматов, например gitformat-bundle[5].
Контрольные суммы и идентификаторы объектов
В репозитории, использующем традиционный SHA-1, упомянутые ниже контрольные суммы pack-файлов и индексов, а также идентификаторы объектов (имена объектов) вычисляются с помощью SHA-1. Аналогично, в репозиториях SHA-256 эти значения вычисляются с помощью SHA-256.
Контрольные суммы CRC32 всегда вычисляются для всего упакованного объекта, включая заголовок (тип и длину в n байтах), имя или смещение базового объекта, если они есть, и весь сжатый объект. Используется алгоритм CRC32 из zlib.
Файлы pack-*.pack имеют следующий формат:
-
В начале находится заголовок, состоящий из следующего:
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.
-
За заголовком следует несколько записей объектов, каждая из которых имеет следующий вид:
(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.
-
В конце записывается контрольная сумма pack-файла, вычисленная для всех данных выше.
Типы объектов
Допустимые типы объектов:
-
OBJ_COMMIT (1)
-
OBJ_TREE (2)
-
OBJ_BLOB (3)
-
OBJ_TAG (4)
-
OBJ_OFS_DELTA (6)
-
OBJ_REF_DELTA (7)
Тип 5 зарезервирован для будущих расширений. Тип 0 недопустим.
Кодирование объектов
В отличие от свободных объектов, упакованные объекты не имеют префикса, содержащего тип, размер и байт NUL. В этом нет необходимости, поскольку эти значения можно определить по n-байтовым типу и длине, предшествующим данным, поэтому они не включаются в сжатые и дельта-кодированные данные.
При вычислении идентификатора объекта этот префикс по-прежнему используется: при необходимости он восстанавливается из типа и длины.
Кодирование размера
В этом документе используется следующее «кодирование размера» неотрицательных целых чисел: из каждого байта берутся семь младших значащих битов, из которых формируется результирующее целое число. Пока старший значащий бит равен 1, процесс продолжается; байт со старшим битом 0 содержит последние семь битов. Семибитные фрагменты объединяются. Более поздние значения имеют больший вес.
Это кодирование размера не следует путать с «кодированием смещения», которое также используется в этом документе.
При кодировании размера объекта без дельта-кодирования в pack-файле указывается размер несжатого исходного объекта. Для объектов, закодированных дельтой, указывается размер несжатой дельты. Имя или смещение базового объекта при вычислении размера не учитывается.
Дельта-представление
Концептуально существуют только четыре типа объектов: commit, tree, tag и blob. Однако для экономии места объект может храниться как «дельта» другого объекта — «базового» объекта. Для таких представлений назначены новые типы ofs-delta и ref-delta, допустимые только в pack-файле.
И ofs-delta, и ref-delta хранят «дельту», которую следует применить к другому объекту (называемому base object), чтобы восстановить объект. Они различаются тем, что ref-delta напрямую кодирует имя базового объекта. Если базовый объект находится в том же pack-файле, ofs-delta вместо этого кодирует смещение базового объекта в pack-файле.
Базовый объект также может быть закодирован дельтой, если он находится в том же pack-файле. Ref-delta может ссылаться и на объект за пределами pack-файла (то есть на объект в так называемом «тонком pack-файле»). Однако при хранении на диске pack-файл должен быть самодостаточным, чтобы избежать циклической зависимости.
Данные дельты начинаются с размера базового объекта и размера объекта, который требуется восстановить. Эти размеры кодируются описанным выше способом кодирования размера. Остаток данных дельты представляет собой последовательность инструкций для восстановления объекта из базового объекта. Если базовый объект закодирован дельтой, его сначала необходимо преобразовать в каноническую форму. Каждая инструкция добавляет данные к целевому объекту, пока он не будет сформирован полностью. Поддерживаются два типа инструкций: копирование диапазона байтов из исходного объекта и добавление новых данных, встроенных в саму инструкцию.
Длина каждой инструкции переменная. Тип инструкции определяется седьмым битом первого октета. На следующих схемах используется соглашение из RFC 1951 (формат сжатых данных Deflate).
Инструкция копирования из базового объекта
+----------+---------+---------+---------+---------+-------+-------+-------+ | 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 | +----------+---------+---------+---------+---------+-------+-------+-------+
Эта инструкция копирует диапазон байтов из исходного объекта. В ней кодируются смещение начала копирования и количество копируемых байтов. Смещение и размер задаются в порядке от младшего байта к старшему.
Все байты смещения и размера необязательны. Это позволяет уменьшить размер инструкции при кодировании небольших смещений или размеров. Первые семь битов первого октета определяют, какие из следующих семи октетов присутствуют. Если установлен бит ноль, присутствует offset1. Если установлен бит один, присутствует offset2 и так далее.
Обратите внимание: более компактная инструкция не меняет способ кодирования смещения и размера. Например, если, как показано ниже, опущен только offset2, offset3 по-прежнему содержит биты 16–23. Он не становится offset2 и не содержит биты 8–15, даже если расположен сразу после offset1.
+----------+---------+---------+ | 10000101 | offset1 | offset3 | +----------+---------+---------+
В наиболее компактной форме эта инструкция занимает всего один байт (0x80): смещение и размер опущены, поэтому по умолчанию равны нулю. Есть ещё одно исключение: нулевой размер автоматически преобразуется в 0x10000.
Инструкция добавления новых данных
+----------+============+ | 0xxxxxxx | data | +----------+============+
Эта инструкция формирует целевой объект без использования базового объекта. Следующие данные добавляются к целевому объекту. Первые семь битов первого октета задают размер данных в байтах. Размер должен быть ненулевым.
Зарезервированная инструкция
+----------+============ | 00000000 | +----------+============
Эта инструкция зарезервирована для будущих расширений.
Исходные файлы pack-*.idx (версия 1) имеют следующий формат:
-
Заголовок состоит из 256 четырёхбайтовых целых чисел в сетевом порядке байтов. N-я запись этой таблицы содержит количество объектов в соответствующем pack-файле, первый байт имени объекта которых меньше или равен N. Эта таблица называется
first-level fan-out. -
За заголовком следуют отсортированные 24-байтовые записи — по одной на каждый объект в pack-файле. Каждая запись имеет следующий вид:
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.
-
В конце файла находится трейлер:
A copy of the pack checksum at the end of the corresponding packfile.
Index checksum of all of the above.
Файл индекса pack-файла:
-- +--------------------------------+
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.
Файлы pack-*.idx версии 2 поддерживают pack-файлы размером более 4 ГиБ и
have some other reorganizations. They have the format:
-
Четырёхбайтовое магическое число
\377tOc, представляющее собой недопустимое значение fanout[0]. -
Четырёхбайтовый номер версии (= 2)
-
Таблица fan-out из 256 записей, как и в версии 1.
-
Таблица отсортированных имён объектов. Они расположены подряд, без значений смещения, чтобы сократить объём кэшируемых данных при двоичном поиске заданного имени объекта.
-
Таблица четырёхбайтовых значений CRC32 для упакованных данных объектов. Она появилась в версии 2, чтобы при перепаковке сжатые данные можно было напрямую копировать из одного pack-файла в другой без риска незамеченного повреждения данных.
-
Таблица четырёхбайтовых значений смещения (в сетевом порядке байтов). Обычно это 31-битные смещения в pack-файле, но большие смещения кодируются как индекс следующей таблицы с установленным старшим битом.
-
Таблица восьмибайтовых значений смещения (пустая для pack-файлов размером менее 2 ГиБ). В pack-файлах часто используемые объекты располагаются в начале, поэтому большинству ссылок на объекты не требуется обращаться к этой таблице.
-
Тот же трейлер, что и в pack-файле версии 1:
A copy of the pack checksum at the end of the corresponding packfile.
Index checksum of all of the above.
Файлы pack-*.rev имеют следующий формат:
-
Четырёхбайтовое магическое число
0x52494458(RIDX). -
Четырёхбайтовый идентификатор версии (= 1).
-
Четырёхбайтовый идентификатор хеш-функции (= 1 для SHA-1, 2 для SHA-256).
-
Таблица позиций в индексе (по одной на каждый упакованный объект, всего num_objects; каждое значение — четырёхбайтовое беззнаковое целое в сетевом порядке байтов), отсортированных по соответствующим смещениям в pack-файле.
-
Трейлер, содержащий:
checksum of the corresponding packfile, and
a checksum of all of the above.
Все четырёхбайтовые числа записываются в сетевом порядке байтов.
Файлы pack-*.mtimes имеют следующий формат:
Все четырёхбайтовые числа записываются в сетевом порядке байтов.
-
Четырёхбайтовое магическое число
0x4d544d45(MTME). -
Четырёхбайтовый идентификатор версии (= 1).
-
Четырёхбайтовый идентификатор хеш-функции (= 1 для SHA-1, 2 для SHA-256).
-
Таблица четырёхбайтовых беззнаковых целых чисел. i-е значение — время изменения (mtime) i-го объекта в соответствующем pack-файле согласно лексикографическому порядку (порядку в индексе). Значения mtime представляют стандартное время в секундах от эпохи Unix.
-
Трейлер, содержащий контрольную сумму соответствующего pack-файла и контрольную сумму всех данных выше (длина каждой определяется указанной хеш-функцией).
Файлы multi-pack-index (midx) имеют следующий формат:
Файлы multi-pack-index ссылаются на несколько pack-файлов и свободные объекты.
Чтобы обеспечить возможность добавления расширений, включающих дополнительные данные в MIDX, тело файла организовано в виде «чанков», а в начале тела расположена таблица поиска. Заголовок содержит некоторые значения длины, например количество pack-файлов, количество базовых файлов MIDX, длины и типы хешей.
Все четырёхбайтовые числа записываются в сетевом порядке байтов.
ЗАГОЛОВОК:
4-byte signature:
The signature is: {'M', 'I', 'D', 'X'} 1-byte version number:
Git writes the version specified by the "midx.version"
configuration option, which defaults to 2. It recognizes
both versions 1 and 2. 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
ТАБЛИЦА ПОИСКА ЧАНКОВ:
(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.
ДАННЫЕ ЧАНКОВ:
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. Version 1 MIDXs are required to
list their packs in lexicographic order, but version 2 MIDXs may
list their packs in any arbitrary order. 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. ТРЕЙЛЕР:
Index checksum of the above contents.
Обратные индексы multi-pack-index
Как и обратный индекс на основе pack-файлов, multi-pack-index также можно использовать для создания обратного индекса.
Вместо отображения соответствий между смещением, pack-файлом и позицией в индексе этот обратный индекс отображает позицию объекта в MIDX в позицию этого объекта в псевдо-pack-файле, описываемом MIDX (то есть i-я запись обратного индекса multi-pack содержит позицию в MIDX i-го объекта в порядке псевдо-pack-файла).
Чтобы прояснить разницу между этими порядками, рассмотрим bitmap достижимости для нескольких pack-файлов (которого пока не существует, но именно к его созданию мы здесь стремимся). Каждый бит должен соответствовать объекту в MIDX, поэтому нам необходимо эффективное отображение позиции бита в позицию MIDX.
Одно из решений — расположить биты на тех же позициях, что и в индексе, отсортированном по oid и хранящемся в MIDX. Но поскольку oid фактически случайны, результирующие bitmap-файлы достижимости будут лишены локальности и потому будут плохо сжиматься. (По этой причине bitmap-файлы для одного pack-файла используют порядок объектов в pack-файле, а не порядок в .idx, для той же цели.)
Поэтому мы хотели бы определить порядок для всего MIDX на основе порядка объектов в pack-файлах, который обладает гораздо лучшей локальностью (и, следовательно, позволяет эффективнее сжимать данные). Можно представить псевдо-pack-файл, созданный конкатенацией всех pack-файлов в MIDX. Например, если бы у нас был MIDX с тремя pack-файлами (a, b, c), содержащими 10, 15 и 20 объектов соответственно, объекты можно было бы упорядочить так:
|a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|
Порядок pack-файлов определяется списком pack-файлов в MIDX, а порядок объектов в каждом pack-файле совпадает с их порядком в самом pack-файле.
Имея список pack-файлов и число объектов в каждом из них, можно наивно восстановить такой порядок псевдо-pack-файла (например, объект на позиции 27 должен быть (c,1), поскольку pack-файлы «a» и «b» заняли первые 25 позиций). Но есть одна проблема. Объекты могут дублироваться в разных pack-файлах; в этом случае MIDX хранит только один указатель на объект (и, следовательно, в bitmap-файле нужна только одна позиция).
Вызывающие программы могли бы самостоятельно обрабатывать дубликаты, читая объекты в порядке позиций битов, но это линейная операция по числу объектов, слишком затратная для обычного поиска по bitmap. Эту проблему решает создание обратного индекса, поскольку он является логической инверсией индекса, в котором дубликаты уже удалены. Однако создание обратного индекса на лету может быть затратным. Поскольку для обратных индексов на основе pack-файлов уже существует дисковый формат, давайте использовать его и для псевдо-pack-файла MIDX.
Чтобы объединить объекты из MIDX в псевдо-pack-файл, они упорядочиваются следующим образом. Пусть pack(o) возвращает pack-файл, из которого o был выбран MIDX, а порядок pack-файлов определяется их числовыми идентификаторами (хранящимися в MIDX). Пусть offset(o) возвращает смещение объекта o в pack(o). Тогда o1 и o2 сравниваются следующим образом:
-
Если один из объектов
pack(o1) иpack(o2) является предпочтительным, а другой нет, то предпочтительный объект располагается первым.(Это позволяет bitmap-файлу MIDX определять, какой pack-файл следует использовать механизму повторного использования pack-файлов: он может запросить у MIDX pack-файл, содержащий объект на позиции бита 0.)
-
Если pack(o1) ≠ pack(o2), объекты сортируются в порядке убывания идентификатора pack-файла.
-
В противном случае
pack(o1)=pack(o2), и объекты сортируются в порядке pack-файла (то естьo1располагается передo2тогда и только тогда, когда offset(o1) < offset(o2)).
Иными словами, псевдо-pack-файл MIDX представляет собой конкатенацию объектов из хранящихся в MIDX pack-файлов без дубликатов, упорядоченных так же, как в pack-файлах, причём сами pack-файлы расположены в порядке MIDX (предпочтительный pack-файл идёт первым).
Обратный индекс MIDX хранится в необязательном чанке RIDX внутри самого MIDX.
Чанк BTMP
Чанк Bitmapped Packfiles (BTMP) кодирует дополнительные сведения об объектах в bitmap-файле достижимости multi-pack index. Напомним, что для bitmap-файлов достижимости объекты из MIDX расположены в порядке «псевдо-pack-файла» (см. выше).
В приведённом выше примере предположим, что у нас есть pack-файлы «a», «b» и «c», содержащие 10, 15 и 20 объектов соответственно. В порядке псевдо-pack-файла они будут расположены так:
|a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|
При работе с bitmap-файлами для одного pack-файла (или, что эквивалентно, с bitmap-файлами достижимости для нескольких pack-файлов и предпочтительным pack-файлом) git-pack-objects[1] выполняет «дословное» повторное использование, пытаясь повторно использовать фрагменты bitmap-файла или предпочтительного pack-файла вместо добавления объектов в список упаковки.
При повторном использовании фрагмента байтов из существующего pack-файла содержащиеся в нём объекты не требуется добавлять в список упаковки, что позволяет сэкономить память и процессорное время. Однако фрагмент из существующего pack-файла можно повторно использовать только при соблюдении следующих условий:
-
Фрагмент содержит только объекты, запрошенные вызывающей программой (то есть не содержит объектов, которые вызывающая программа явно или неявно не запрашивала).
-
Все объекты, хранящиеся в не тонких pack-файлах как дельты со смещением или ссылкой, включают в результирующий pack-файл и свой базовый объект.
Чанк BTMP кодирует сведения, необходимые для повторного использования данных из нескольких pack-файлов, как описано выше. В частности, чанк BTMP кодирует для каждого pack-файла p, хранящегося в MIDX, три значения (все — 32-битные беззнаковые целые числа в сетевом порядке байтов):
-
bitmap_pos -
Позиция первого бита в bitmap-файле достижимости multi-pack index (в порядке псевдо-pack-файла), занятого объектом из
p. -
bitmap_nr -
Количество позиций битов (включая позицию
bitmap_pos), кодирующих объекты из этого pack-файлаp.
Например, чанк BTMP для приведённого выше примера (с pack-файлами «a», «b» и «c») будет выглядеть так:
bitmap_pos | bitmap_nr | |
|---|---|---|
pack-файл «a» |
|
|
pack-файл «b» |
|
|
pack-файл «c» |
|
|
Имея эти сведения, мы можем повторно использовать каждый pack-файл отдельно так же, как отдельные pack-файлы дословно переиспользовались до появления чанка BTMP.
Pack-файлы с мусорными объектами
Функция pack-файлов с мусорными объектами предлагает альтернативу традиционному механизму Git для удаления недостижимых объектов. В этом документе описывается механизм очистки Git и то, как вместо него можно использовать pack-файл с мусорными объектами для достижения той же цели.
Предыстория
Для удаления недостижимых объектов из репозитория Git предоставляет команду git repack -Ad (см. git-repack[1]). Цитата из документации:
[...] 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.
Недостижимые объекты удаляются не сразу, поскольку это может привести к гонке с входящей отправкой, которая может ссылаться на объект, подлежащий удалению. Вместо этого такие недостижимые объекты хранятся как свободные и остаются в таком состоянии, пока не истечёт срок хранения; после этого они удаляются командой git-prune[1].
Git должен хранить эти недостижимые объекты в свободном виде, чтобы отслеживать время изменения каждого объекта. Если записать эти недостижимые объекты в один большой pack-файл, то как его обновление (из-за повторной записи содержащегося в нём объекта), так и создание нового pack-файла с недостижимыми объектами приведёт к обновлению времени изменения pack-файла. В результате объекты в нём никогда не выйдут за пределы срока хранения. Поэтому объекты хранятся в свободном виде, чтобы отслеживать время изменения каждого объекта и избежать ситуации, когда все мусорные объекты одновременно получают новое время изменения.
Это может привести к нежелательным ситуациям, если в репозитории содержится много недостижимых объектов, срок хранения которых ещё не истёк. Большие каталоги в шардах .git/objects могут снизить производительность репозитория. При достаточно большом количестве недостижимых объектов может возникнуть нехватка индексных дескрипторов, что ухудшит производительность всей системы. Поскольку такие объекты невозможно упаковать, эти репозитории часто занимают много места на диске: их можно сжать только с помощью zlib, но нельзя хранить в цепочках дельт.
Pack-файлы с мусорными объектами
Pack-файл с мусорными объектами устраняет необходимость хранить недостижимые объекты в свободном виде: времена изменения отдельных объектов записываются в отдельный файл рядом с одним pack-файлом, содержащим все свободные объекты.
Pack-файл с мусорными объектами создаётся командой git repack --cruft при создании нового pack-файла. Параметр --cruft команды git-pack-objects[1]. Обратите внимание, что git repack --cruft выполняет классическую перепаковку всех объектов в один файл: всё содержимое результирующего pack-файла достижимо, а всё остальное — недостижимо. После его создания параметр --cruft указывает команде git repack создать ещё один pack-файл, содержащий только объекты, не упакованные на предыдущем шаге (то есть объединить все недостижимые объекты). Процесс выполняется следующим образом:
-
Перечислить все объекты и отметить как начальные точки обхода те, которые (а) не входят в сохраняемый pack-файл и (б) имеют время изменения в пределах срока хранения.
-
Выполнить обход достижимости от начальных точек, собранных на предыдущем шаге, добавляя каждый встреченный объект в pack-файл.
-
Записать pack-файл вместе с файлом
.mtimes, содержащим временные метки отдельных объектов.
Этот режим вызывается внутри git-repack[1], когда требуется создать pack-файл с мусорными объектами. Важно, что набор сохраняемых pack-файлов в памяти в точности совпадает с набором pack-файлов, которые не будут удалены при перепаковке; иными словами, они содержат все достижимые объекты репозитория.
Если в репозитории уже есть pack-файл с мусорными объектами, команда git repack --cruft обычно только добавляет в него объекты. Исключение возникает, когда команде git repack передан параметр --cruft-expiration, позволяющий не включать в создаваемый pack-файл объекты с истёкшим сроком хранения, вместо того чтобы ждать, пока git-gc[1] удалит их позднее.
Обычно за удаление недостижимых объектов с истёкшим сроком хранения отвечает git-gc[1].
Альтернативы
К заметным альтернативам этому решению относятся:
-
Расположение данных о времени изменения отдельных объектов.
Для хранения данных о времени изменения был выбран новый вспомогательный файл, связанный с pack-файлом, чтобы не усложнять формат .idx. Если формат .idx когда-нибудь получит поддержку необязательных чанков данных, может иметь смысл объединить формат .mtimes с самим .idx.
gitformat-pack
© 2005–2026 Linus Torvalds and others
Licensed under the GNU General Public License version 2.
https://git-scm.com/docs/gitformat-pack