Подтвердить что ты не робот

Почему хэш-объект git возвращает другой хэш, чем openssl sha1?

Контекст: я загрузил файл (Audirvana 0.7.1.zip) из code.google на мой MacBook Pro (Mac OS X 10.6. 6).

Я хотел проверить контрольную сумму, которая для этого конкретного файла размещена как 862456662a11e2f386ff0b24fdabcb4f6c1c446a (SHA-1). git hash-object дал мне другой хеш, но openssl sha1 возвратил ожидаемый 862456662a11e2f386ff0b24fdabcb4f6c1c446a.

Следующий эксперимент, по-видимому, исключает любые возможные различия в загрузке или новой строке и указывает на то, что в игре есть два разных алгоритма:

$ echo A > foo.txt
$ cat foo.txt
A
$ git hash-object foo.txt 
f70f10e4db19068f79bc43844b49f3eece45c4e8
$ openssl sha1 foo.txt 
SHA1(foo.txt)= 7d157d7c000ae27db146575c08ce30df893d3a64

Что происходит?

4b9b3361

Ответ 1

Вы видите разницу, потому что git hash-object не просто принимает хэш из байтов в файле - он добавляет строку "blob", а затем размер файла и NUL в содержимое файла перед хэшированием. В этом другом ответе на переполнение стека есть более подробная информация:

Или, чтобы убедить себя, попробуйте что-то вроде:

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

$ printf 'blob 5\0hello' > test.txt
$ openssl sha1 test.txt
SHA1(test.txt)= b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0

Ответ 2

Сборник SHA1 вычисляется по строке заголовка, за которой следуют данные файла. Заголовок состоит из типа объекта, пробела и длины объекта в байтах как десятичного. Это отделяется от данных нулевым байтом.

Итак:

$ git hash-object foo.txt
f70f10e4db19068f79bc43844b49f3eece45c4e8
$ ( perl -e '$size = (-s shift); print "blob $size\x00"' foo.txt \
               && cat foo.txt ) | openssl sha1
f70f10e4db19068f79bc43844b49f3eece45c4e8

Одним из следствий этого является то, что "пустое дерево" и "пустая ячейка" имеют разные идентификаторы. То есть:

e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 всегда означает "пустой файл", 4b825dc642cb6eb9a060e54bf8d69288fbee4904 всегда означает "пустой каталог"

Вы обнаружите, что на самом деле вы можете сделать git ls-tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 в новом репозитории git без регистрации объектов, поскольку он распознается как особый случай и никогда не хранится на самом деле (с современными версиями git). В отличие от этого, если вы добавите пустой файл в свое репо, будет сохранен блок "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391".

Ответ 3

Ответ лежит здесь:

Как назначить файл Git SHA1 для файла без Git?

git вычисляет метаданные файла + содержимое, а не только содержимое.

На данный момент это достаточно хороший ответ, и вынос заключается в том, что git не является инструментом для загрузки контрольных сумм.