Что на самом деле делает git, когда говорит, что «разрешает дельты»?

187

Во время первого клона репозитория git сначала получает объекты (что достаточно очевидно), а затем тратит примерно столько же времени на «разрешение дельт». Что на самом деле происходит во время этой фазы клона?

Ник Рейман
источник
Связанный: stackoverflow.com/questions/9478023/…
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功
1
См. Также для Git 2.20 (Q4 2018) и других дельта-островов: stackoverflow.com/a/52458712/6309
VonC

Ответы:

54

Git использует дельта-кодирование для хранения некоторых объектов в пакетных файлах. Тем не менее, вы не хотите , чтобы воспроизвести каждое изменение когда - либо на данный файл, чтобы получить текущую версию, поэтому Git также случайные снимки содержимого файлов , хранящееся , а также. «Устранение дельт» - это шаг, обеспечивающий согласованность всего этого.

Вот глава из раздела «Git Internals» книги Pro Git, которая доступна в Интернете, где говорится об этом.

янтарный
источник
80
Этот ответ неверен. Кажется, чтобы описать, как работает Mercurial, а не Git. Эта проблема возникает в поиске Google, поэтому я чувствую необходимость ответить. Git не хранит различия между коммитами как дельты; Git - это магазин "всего объекта". Таким образом, Git не нужны «снимки» для отображения какого-либо файла, потому что историю файлов не нужно восстанавливать из дельт. Вот как работает Mercurial.
говорит нексус
12
Единственное место, где дельта-кодирование вступает в игру, находится в файле пакета, который предназначен исключительно для сжатия и передачи - он не меняет того, как Git «видит» мир. ( kernel.org/pub/software/scm/git/docs/v1.6.2.3/technical/… ) Пожалуйста, посмотрите ответ araqnid ниже для точного ответа.
говорит нексус
4
Все «снимки» означают в этом контексте полную копию состояния файла, а не версию с кодировкой дельты. Как вы упомянули, Git делает использование дельта-кодирование в packfiles. Никто не сказал, что это «меняет то, как Git видит мир»; пожалуйста, прекратите проецировать свои собственные предположения.
Янтарный
2
Ваш ответ все еще неточный. «В Git также иногда хранятся снимки содержимого файлов». - это не правильно. «Устранение дельт» - это шаг, обеспечивающий согласованность всего этого ». - это также не правильно, ответ Аракнида ниже является правильным.
говорит нексус
1
Как описано в главе, упомянутой выше, Git всегда сохраняет полное содержимое файла последней версии. Предыдущие версии хранятся в виде дельта-кодированных файлов, когда они являются «свободными» файлами. Периодически (либо путем вызова, git gcлибо всякий раз, когда Git сочтет это необходимым), Git сжимает все «свободные» файлы в файл пакета, чтобы сэкономить место, и файл индекса в этот файл пакета будет создан. Таким образом, zlib будет сжимать свой собственный дельта-алгоритм, но Git использует дельта-кодирование для хранения предыдущих версий. Поскольку наиболее распространенным и частым доступом является последняя версия, она сохраняется в виде снимка.
BrionS
118

Этапы git clone:

  1. Получите файл "pack" всех объектов в базе данных репо
  2. Создать индексный файл для полученного пакета
  3. Проверьте ревизию головы (для не голого репо, очевидно)

«Разрешение дельт» - это сообщение, отображаемое на втором этапе, индексирующее файл пакета («git index-pack»).

Файлы пакета не имеют реальных идентификаторов объектов, только содержимое объекта. Таким образом, чтобы определить идентификаторы объектов, git должен выполнить декомпрессию + SHA1 для каждого объекта в пакете, чтобы получить идентификатор объекта, который затем записывается в индексный файл.

Объект в файле пакета может быть сохранен как дельта, то есть последовательность изменений, чтобы сделать к некоторому другому объекту. В этом случае git необходимо извлечь базовый объект, применить команды и получить результат SHA1. Сам базовый объект может быть получен путем применения последовательности дельта-команд. (Несмотря на то, что в случае клона базовый объект уже встречался, существует ограничение на количество кешируемых объектов в памяти).

Таким образом, стадия «разрешения дельт» включает распаковку и контрольную сумму всей базы данных репо, что неудивительно, что занимает довольно много времени. Предположительно распаковка и вычисление SHA1 на самом деле занимает больше времени, чем применение дельта-команд.

В случае последующей выборки полученный файл пакета может содержать ссылки (в качестве базисов дельта-объектов) на другие объекты, которые, как ожидается, уже получит получающий git. В этом случае принимающий git фактически переписывает полученный файл пакета, чтобы включить в него любые такие объекты, на которые ссылаются, так что любой сохраненный файл пакета является самодостаточным. Это может быть там, где возникло сообщение «Разрешение дельт».

araqnid
источник
7
Можно ли это распараллелить?
brooksbp
Является ли это дельта-сжатие чем-то большим, чем хранение нескольких объектов в одном потоке данных zlib?
fuz
1
@FUZxxl да, он использует алгоритм, такой как diff или xdelta, для сравнения двух BLOB-объектов и создания сценария редактирования
araqnid
@brooksbp: только с ограничениями. Поскольку объект с идентификатором 103fa49 может нуждаться в декодировании df85b51, но когда вы получаете 103fa49, df85b51 еще не существует (файлы пакетов строго упорядочены хэшами sha1). Таким образом, для всего, что ссылается только на то, что уже есть, все просто, но для всего остального вам придется подождать, пока оно не будет получено. И это дельта-сжатие может быть вложенным, так что 103fa49 может понадобиться 4e9ba42, который, в свою очередь, нуждается в 29ad945, который, в свою очередь, нуждается в c9e645a ... вы получите картину. [да, я заметил, что прошло> 4 года;)]
Бодо Тизен,
2
@brooksbp: Оказывается, я был не прав, файл пакета НЕ нужно сортировать по хэшам sha1. Кроме того, при написании git записывает нужные объекты до того, как объекты нуждаются в них. Итак, на самом деле вы должны быть в состоянии распараллелить это. Остается только один недостаток: поскольку вы не знаете, какие объекты вам понадобятся позже, вам придется воссоздавать некоторые объекты снова и снова. Смотрите здесь: kernel.org/pub/software/scm/git/docs/technical/…
Бодо Тизен,
4

Янтарь, кажется, описывает объектную модель, которую использует Mercurial или аналогичные. Git хранит не дельты между последующими версиями объекта, а скорее полные снимки объекта каждый раз. Затем он сжимает эти снимки с использованием дельта-сжатия, пытаясь найти хорошие дельты для использования, независимо от того, где в истории они существуют.

Johan
источник
5
На самом деле, хотя Git может хранить незакрепленные объекты, они не всегда сохраняются как таковые - поскольку незакрепленные объекты можно удалять и заменять упакованным содержимым. Я не думаю, что ответ Амбер где-либо говорил о последующих версиях.
AlBlue