Почему git pack-objects выполняет «Сжатие объектов», если объекты уже сжаты? - PullRequest
0 голосов
/ 12 января 2019

Насколько я понимаю, свободные объекты, хранящиеся в [голом] хранилище git, сжаты ...

... так почему git pack-objects (и все связанные с ним команды repack и gc) имеют действительно длинную Compressing objects стадию? Разве это не просто копирование их?

Например:

objects/75/f0debd8e421ab3f9cc8b6aeb539796ae86b705 уже сжат. В файле пакета этот файл должен быть побайтно скопирован на место сразу же после его заголовка, потому что формат файла пакета указывает, что сжатые данные идут туда ... Так почему же его нужно повторно сжать, если он уже сжат?

Если, возможно, он пытается использовать другое сжатие ... как я могу сказать, что нет, а вместо этого просто использовать файл как есть?

Обновлены примечания:

  • Я установил настройки и параметры так, чтобы дельта-сжатие эффективно не происходило. Дельта-сжатие бесполезно для хранения 2 ТБ изображений .NEF.

1 Ответ

0 голосов
/ 12 января 2019

Насколько я понимаю, свободные объекты, хранящиеся в [голом] хранилище git, сжаты ...

Они есть. Но они zlib-deflate сжаты.

... так почему у объектов git pack (и всех связанных с ними команд repack и gc) действительно длинный этап Compressing objects?

Эти команды - git pack-objects и git repack, в любом случае; git gc просто запускает git repack для вас - объедините множество объектов в один файл пакета .

Файл пакета - это другой способ сжатия объектов. Свободный объект является автономным: Git нужно только прочитать свободный объект и выполнить над ним проход zlib inflate, чтобы получить несжатые данные для этого объекта. Файл пакета, напротив, содержит много объектов, причем некоторые из этих объектов, во-первых, с дельта-сжатием .

Дельта-сжатие работает, говоря, по сути: Чтобы создать этот объект, сначала создайте этот другой объект. Затем добавьте эти байты сюда и / или удалите N байтов здесь. Повторяйте это добавление и / или удаление до тех пор, пока я не закончу со списком дельт. (Сами инструкции дельты также могут быть дефлированы zlib.) Вы можете распознать это как своего рода diff, и на самом деле, некоторые системы контроля версий, не относящиеся к Git, действительно используют diff или свой собственный внутренний механизм сравнения для создания своих файлов, сжатых дельтой.

Традиционно для этого используется наблюдение, что некоторый файл (скажем, foo.cc или foo.py) имеет тенденцию изменяться с течением времени, добавляя и / или удаляя несколько строк где-то в файле, но сохраняя большую часть его неизменным. , Если мы можем сказать: взять все предыдущие версии, но затем добавить и / или удалить эти строки , мы можем хранить обе версии на гораздо меньшем пространстве, чем требуется для хранения одной из них.

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

Некоторые (не Git) системы останавливаются здесь: каждый файл сохраняется либо как изменение предыдущей версии, либо, каждый раз, когда вы сохраняете файл, система сохраняет последнюю версию и поворачивает предыдущую полную копию (которая использовалась чтобы быть последним, и, следовательно, было полной копией) в дельту, необходимую для преобразования «последнего» в «предыдущий». Первый метод называется прямое дельта-хранилище , а второй, конечно, обратное дельта-хранилище . Прямые дельты, как правило, имеют ужасный недостаток, поскольку для извлечения последней версии файла требуется извлечь первую версию, а затем применить очень длинную последовательность дельт, что занимает много времени. Поэтому RCS использует обратные дельты, что означает быстрое получение последней версии; он получает очень старую версию, которая работает медленно. (Однако по техническим причинам это работает только для того, что RCS называет trunk . Вместо этого в «ветвях» RCS используются прямые дельты.) Mercurial использует прямые дельты, но иногда сохраняет новую полную копию файла, поэтому чтобы длина цепи дельта была короткой. Одна система, SCCS, использует метод, который SCCS вызывает с перемежением дельт , который дает линейное время для извлечения любого файла (но его сложнее генерировать).

Git, однако, не сохраняет файлы как files . Вы уже знаете, что данные файла хранятся как объект blob , который изначально просто zlib-дефлирован, а в остальном не поврежден. Учитывая набор объектов, некоторые из которых являются данными файла, а некоторые нет (являются коммитами, деревьями или аннотированными объектами тегов), совершенно не очевидно, какие данные принадлежат какому файлу (файлам). Поэтому Git находит вероятного кандидата: некоторый объект, который, похоже, очень напоминает какой-то другой объект, лучше всего выразить словами: начните с другого объекта, затем внесите эти дельта-изменения.

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

Более подробную информацию о пакетных файлах, которые со временем претерпели несколько изменений, смотрите в каталоге Documentation / technical в Git .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...