Стандартизирован ли алгоритм двоичного разложения git (дельта-хранилище)?

Git использует дельта-сжатие для хранения объектов, которые похожи друг на друга.

Этот алгоритм стандартизирован и используется в других инструментах? Есть ли документация, описывающая формат? Совместим ли он с xdelta/VCDIFF/RFC 3284?

Ответ 1

Я думаю, что diff algo, используемый для файлов pack, был связан с одним из дельта-кодировок: сначала (2005) xdelta, а затем libXDiff.
Но затем, как подробно описано ниже, он переключился на пользовательскую реализацию.

Во всяком случае, как упоминалось здесь:

Git делает deltification только в packfiles.
Но когда вы нажимаете SSH, git генерирует пакетный файл с фиксацией другой стороны, а эти пакеты - тонкие пакеты, поэтому у них также есть дельта... но удаленная сторона добавляет базы к тем тонким пакетам, что делает их автономный.

(примечание: создание многих packfiles или получение информации в огромном пакете является дорогостоящим, и объясните, почему git не справляется с огромными файлами или огромным репо.
См. Больше в " git с большими файлами ")

Эта тема также напоминает нам:

Фактически packfiles и deltification (LibXDiff, а не xdelta) были из того, что я помню и понимал, изначально из-за пропускной способности сети (что намного дороже дискового пространства) и производительности ввода-вывода для использования одного mmapped файла вместо очень большого числа рыхлых предметов.

LibXDiff упоминается в этом потоке 2008 года.

Однако с тех пор алгоритм эволюционировал, возможно, в пользовательском, как показано в этом потоке 2011 года, и, как указывает заголовок diff-delta.c:

Итак, строго говоря, текущий код в Git вообще не имеет никакого сходства с кодом libxdiff.
Однако основной алгоритм, лежащий в основе обеих реализаций, тот же.
Изучение версии libxdiff, вероятно, проще, чтобы понять, как это работает.

/*
 * diff-delta.c: generate a delta between two buffers
 *
 * This code was greatly inspired by parts of LibXDiff from Davide Libenzi
 * http://www.xmailserver.org/xdiff-lib.html
 *
 * Rewritten for GIT by Nicolas Pitre <[email protected]>, (C) 2005-2007
 */

Подробнее о пакетах Git Book:

packfile format


Git 2.18 добавляет описание дельта в этот новый раздел документации, который теперь (Q2 2018) гласит:

Типы объектов

Допустимые типы объектов:

  • OBJ_COMMIT (1)
  • OBJ_TREE (2)
  • OBJ_BLOB (3)
  • OBJ_TAG (4)
  • OBJ_OFS_DELTA (6)
  • OBJ_REF_DELTA (7)

Тип 5 зарезервирован для будущего расширения. Тип 0 недействителен.

Дефицированное представление

Концептуально существует только четыре типа объектов: commit, tree, tag и blob.
Однако для экономии места объект может быть сохранен как "дельта" другого "базового" объекта.
Этим представлениям присваиваются новые типы-delta и ref-delta, которые действительны только в файле пакета.

В обоих случаях ofs-delta и ref-delta хранится "дельта", которая применяется к другому объекту (называемому "базовым объектом") для восстановления объекта.
Разница между ними,

  • ref-delta напрямую кодирует 20-байтовое имя базового объекта.
    • Если базовый объект находится в одном пакете, by-delta вместо этого кодирует смещение базового объекта в пакете.

Базовый объект также может быть делит, если он находится в одном пакете.
Ref-delta также может ссылаться на объект вне упаковки (т.е. Так называемый "тонкий пакет"). Однако при хранении на диске пакет должен быть автономным, чтобы избежать циклической зависимости.

Дельта-данные представляют собой последовательность инструкций по восстановлению объекта из базового объекта.
Если базовый объект делит, он сначала должен быть преобразован в каноническую форму. Каждая команда добавляет все больше данных к целевому объекту до его завершения.
До сих пор есть две поддерживаемые инструкции:

  • один для копирования диапазона байтов из исходного объекта и
  • один для вставки новых данных, встроенных в собственно инструкцию.

Каждая команда имеет переменную длину. Тип инструкции определяется седьмым битом первого октета. Следующие диаграммы следуют за соглашением в RFC 1951 (формат сжатых данных с дефлятом).

Ответ 2

Git Дельта-кодирование основано на копировании/вставке.

Это означает, что производный файл кодируется как последовательность кодов операций, которые могут представлять собой копию инструкции (например: копирование из базового файла y байтов, начиная со смещения x в целевой буфер) или вставить инструкции (например: вставить следующие x байты в целевой буфер).

В качестве очень простого примера (взятого из статьи "Поддержка файловой системы для сжатия Delta" ), подумайте о том, что мы хотим создать буфер дельта, чтобы преобразовать текст "прокси и кеширование" в "Кэш   прокси". Результирующие инструкции должны быть:

  • Скопируйте 5 байтов из смещения 7 (скопируйте "кеш" из базового буфера)
  • Вставьте два пробела
  • Скопируйте 5 байтов из смещения 0 (скопируйте "прокси" из базового буфера)

Что переводится в кодировку git, становится:

(байты 1-3 представляют первую инструкцию)

  • 0x91 (10010001), который делится на
    • 0x80 (10000000) (самый старший бит задает команду "копировать из базы для вывода" )
    • 0x01 (00000001) (означает "продвигать один байт и использовать его в качестве базового смещения" )
    • 0x10 (00010000) (продвигайте один байт и используйте его как длину)
  • 0x07 (смещение)
  • 0x05 (длина)

(байты 4-6 представляют вторую инструкцию)

  • 0x02 (поскольку MSB не установлен, это означает "вставить следующие два байта в выходной файл" )
  • 0x20 (пробел)
  • 0x20 (пробел)

(байты 7-8 представляют последнюю инструкцию)

  • 0x90 (10010000), который делится на
    • 0x80 (10000000) (означает "копировать" )
    • 0x10 (00010000) (продвигайте один байт и используйте его как длину)
  • 0x05 (длина)

Обратите внимание, что в последней команде копирования не указано смещение, которое означает смещение 0. Другие биты в коде операции копирования также можно установить, когда требуются большие смещения/длины.

Результирующий дельта-буфер в этом примере имеет 8 байтов, что не является большим количеством сжатия поскольку целевой буфер имеет 12 байтов, но когда это кодирование применяется к большим текстовым файлам, оно может имеют огромное значение.

Недавно я нажал node.js-библиотеку на github который реализует функции diff/patch с использованием дельта-кодирования git. код должен быть более читаемым и прокомментирован, чем тот, что находится в источнике git, который сильно оптимизирован.

Я также написал несколько тесты, которые объясняют выходные коды операций, используемые в каждом примере, с форматом, аналогичным описанному выше.

Ответ 3

Этот алгоритм стандартизирован и используется в других инструментах?

Формат пакета является частью общедоступного API: протоколы передачи, используемые для операций push и fetch, используют его для отправки меньше данных по сети.

Они реализованы, по крайней мере, в двух других основных реализациях Git помимо ссылки: JGit и libgit2.

Поэтому очень маловероятно, что в формат будут внесены обратно несовместимые изменения, и в этом смысле их можно считать "стандартизованными".

Этот удивительный файл из документации описывает эвристику, используемую в алгоритме пакета, как забавный комментарий по электронной почте от Linus: https://github.com/git/git/blob/v2.9.1/Documentation/technical/pack-heuristics.txt