Почему git создает новые двоичные объекты между командами git add? - PullRequest
1 голос
/ 29 марта 2019

Итак, я недавно обнаружил инструмент git cat-file, и я играл с ним. Я знаю, что Git использует BLOB-объекты для хранения реального содержимого. Но почему создается впечатление, что каждый раз, когда я git add изменяю файл, создается новый BLOB-объект, т. Е. В отличие от редактирования существующего BLOB-объекта или создания нового BLOB-объекта и удаления старого?

, например

touch hello.txt
// change hello.txt to contains 'hello'
git add hello.txt // creates a blob abc123 containing: 'hello'  

// change hello.txt to 'hello world'
git add hello.txt // creates a blob cba321 containing: 'hello world'  

git commit // creates a commit with tree pointing at blob cba321

Таким образом, назначение большого двоичного объекта, содержащего мое промежуточное поэтапное изменение, то есть большого двоичного объекта abc123, содержащего «привет», не очевидно.

Что касается коммитов, hello.txt перешел из "" прямо в "привет мир", и я даже не могу вернуть свое промежуточное изменение abc123, не копаясь в git blob.

Ответы [ 2 ]

1 голос
/ 30 марта 2019

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

Ни одна капля не может быть изменена.Это то же самое, что и правило о коммитах: ни один коммит не может быть изменен.

Причина в том, что хэш-идентификатор каждого объекта Git - двоичные объекты и коммиты являются двумя из четырех типоввнутреннего объекта Git - это просто криптографическая контрольная сумма содержимого, хранящегося как этот объект.В случае файла («blob») фактическим содержимым являются пять символов ASCII b, l, o, b, пробел , затем размер BLOB-объектав десятичном виде и также сохраняется в ASCII, затем ASCII NUL-байт, а затем сохраненные данные.Например, hello хранится как то, что Python может представлять как b"blob 5\0hello".

(Вы можете вычислить этот хеш, используя хэш SHA1 или git hash-object:

$ echo -n hello | git hash-object --stdin
b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0

или:

$ python3
[snip]
>>> import hashlib
>>> hashlib.sha1(b"blob 5\0hello").hexdigest()
'b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0'

Таким образом, любой BLOB-объект с хэш-идентификатором b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0 обязательно является файлом hello, или, если это не так, вы не можете сохранить файл, содержащий hello (без перевода строки)в этом репозитории Git. Поиск двойника для некоторого файла (злой двойник, который предотвращает хранение какого-либо другого файла) нетривиален: см. Как недавно обнаруженное столкновение SHA-1 влияет на Git? для деталей.

Итак, когда вы git add файл, Git создает новый большой двоичный объект или повторно использует существующий большой двоичный объект, в зависимости от того, существуют ли данные этого файла в качестве большого двоичного объекта в хранилище.Затем вы git commit, Git постоянно сохраняет содержимое, связанное с новым объектом фиксации.Если вы никогда не зафиксируете этот BLOB-объект и , ни один другой коммит или другая сущность также не ссылаются на него, Git в конце концов истекает BLOB через егосборка мусора рrocess (см. git gc).

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

(Для полноты,Два других типа объектов Git: дерево и аннотированный тег . Объекты дерева хранят файл names , отображая имя в идентификатор хэша BLOB-объекта вместе с исполняемым битомдля файла. Объект фиксации ссылается по хэш-идентификатору на дерево, представляющее моментальный снимок. аннотированный тег объект представляет собой особую структуру данных, которая содержит хэш-идентификатор другого объекта Git плюс полезную нагрузку данных;в этой полезной нагрузке вы можете хранить подпись GPG или другую цифровую подпись вместе со всем, что вам нравится. Затем вы можете указать легкий тег на объект аннотированного тега, чтобы получить аннотированный тег.)

1 голос
/ 29 марта 2019

git add действительно создает BLOB-объекты, так как индекс (или промежуточная область, у него много имен ...) имеет цель подготовить моментальный снимок , который будет составлять следующий коммит.

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

И чтобы ответить на ваш последний вопрос, нет, вы не можете «даже» вернуться в состояние вы не считаю целесообразным экономить.

...