# Packfile _Объектная модель · GitLab Knowledge Base_ **TL;DR:** Сжатый файл в `.git/objects/pack/`, в который Git упаковывает множество loose-объектов, чтобы экономить место и ускорять сетевые операции. Использует дельта-компрессию между похожими объектами. Когда объект только появился (от `git add`, `git commit`), он лежит отдельным файлом - *loose object*: `.git/objects/8d/0e41...`. Удобно для записи, неудобно для хранения миллионов файлов. Поэтому Git периодически сжимает их в *packfiles*. ## Что внутри packfile В `.git/objects/pack/` появляются пары файлов: ``` pack-abc123def456.pack # сжатые объекты pack-abc123def456.idx # индекс по SHA для быстрого поиска ``` Внутри `.pack`: - объекты упакованы один за другим, каждый в zlib-сжатом виде; - между похожими объектами вычисляется *дельта* - хранится только разница относительно базы; - всё это дополнительно сжато на уровне потока. ## Дельта-компрессия Главная экономия в Git происходит здесь. Допустим, есть две версии большого файла, отличающиеся на пять строк. В loose-формате это два blob'а, каждый занимает почти полный размер файла. В packfile одна версия лежит целиком, вторая - как «возьми вот ту, примени следующие правки». Алгоритм похож на xdelta/bsdiff. Git подбирает базу не по имени файла, а по эвристике: пытается найти похожий объект схожего типа и размера. Поэтому могут быть дельты между двумя совершенно разными файлами, если они случайно похожи. ## Когда packfiles создаются - При `git gc` (manual или auto). - При `git push/fetch` - стороны обмениваются объектами в packfile- формате, а не по одному. - При `git clone` - сервер сразу отдаёт всё содержимое в packfile. Авто-gc срабатывает при превышении порогов: - больше 6700 loose-объектов; - больше 50 packfile'ов. Эти пороги настраиваются: `gc.auto`, `gc.autoPackLimit`. ## Чтение объектов из packfile Команды Git работают одинаково независимо от того, где лежит объект - в loose-формате или в packfile. `git cat-file -p ` найдёт объект в любой форме. Просмотр содержимого pack'а руками: ```bash git verify-pack -v .git/objects/pack/pack-abc.idx # SHA type size packfile-offset base-SHA? ``` Видно, какие объекты - base, какие - дельта, и от кого они зависят. ## Подводные камни - Дельта не значит, что Git «диффы хранит». Логически модель данных остаётся snapshot-based ([commit](/courses/git/kb/commit.md) держит [tree](/courses/git/kb/tree.md), а не diff). Дельта - это уровень физического хранения. - При очень большом packfile отдельный read может быть медленным: Git распаковывает цепочку дельт. Поэтому есть лимит `pack.deltaCacheSize`. - `git gc --aggressive` пересчитывает дельты с нуля, выбирая лучшие базы. Долго, но даёт меньший размер. Стоит делать раз в несколько месяцев на больших проектах. ## Команды ```bash git gc ``` Собрать loose-объекты в packfile, удалить недостижимое ```bash git verify-pack -v ``` Распечатать содержимое packfile с типами и размерами ```bash git count-objects -v ``` Показать сколько loose-объектов и packfile'ов в репозитории ## См. также - [Blob](/courses/git/kb/blob.md) - [Tree](/courses/git/kb/tree.md) - [Commit](/courses/git/kb/commit.md)