Но почему создается впечатление, что каждый раз, когда я добавляю изменение в файл, создается новый большой двоичный объект, то есть в отличие от редактирования существующего большого двоичного объекта или создания нового большого двоичного объекта и удаления старого?
Ни одна капля не может быть изменена.Это то же самое, что и правило о коммитах: ни один коммит не может быть изменен.
Причина в том, что хэш-идентификатор каждого объекта 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 или другую цифровую подпись вместе со всем, что вам нравится. Затем вы можете указать легкий тег на объект аннотированного тега, чтобы получить аннотированный тег.)