Как Git вычисляет хэши файлов?
хэши SHA1, хранящиеся в объектах дерева (как возвращено git ls-tree
) не совпадают хэши SHA1 содержимого файла (как возвращено sha1sum
)
$ git cat-file blob 4716ca912495c805b94a88ef6dc3fb4aff46bf3c | sha1sum
de20247992af0f949ae8df4fa9a37e4a03d7063e -
как git вычисляет хэши файлов? Сжимает ли он содержимое перед вычислением хэша?
5 ответов:
git префиксы объекта с "blob", а затем длина (как a читаемое человеком целое число), за которым следует символ NUL
$ echo -e 'blob 14Hello, World!' | shasum 8ab686eafeb1f44702738c8b0f24f2567c36da6d
Источник:http://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html
я только расширяю ответ на
@Leif Gruenwoldt
и подробно то, что находится в ссылка предоставлен@Leif Gruenwoldt
Сделай Это Сам..
- Шаг 1. Создайте пустой текстовый документ (имя не имеет значения) в вашем репозитории
- Шаг 2. Этап и зафиксировать документ
- Шаг 3. Определите хэш большого двоичного объекта, выполнив
git ls-tree HEAD
- Шаг 4. Найдите хэш большого двоичного объекта быть
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
- Шаг 5. Вырвитесь из своего удивления и прочитайте ниже
как GIT вычисляет свои хэши фиксации
Commit Hash (SHA1) = SHA1("blob " + <size_of_file> + "" + <contents_of_file>)
текст
blob⎵
постоянный префикс итакже является постоянным и является
NULL
символ. Элемент<size_of_file>
и<contents_of_file>
в зависимости от файла.и это все люди!
но подождите!, вы заметили, что
<filename>
это не a параметр, используемый для вычисления хэша? Два файла потенциально могут иметь один и тот же хэш, если их содержимое одинаково безразлично к дате и времени их создания и их имени. Это одна из причин, по которой git обрабатывает перемещения и переименовывает лучше, чем другие системы управления версиями.Сделай Это Сам (Ext)
- Шаг 6. Создайте еще один пустой файл с другим
filename
в том же каталоге- Шаг 7. Сравните хэши обоих ваших файлов.
Примечание:
ссылка не упоминает, как
git hash-object
это быстрый способ проверить свой метод тестирования:
s='abc' printf "$s" | git hash-object --stdin printf "blob $(printf "$s" | wc -c)$s" | sha1sum
выход:
f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f -
здесь
sha1sum
находится в GNU Coreutils.тогда это сводится к пониманию формата каждого типа объекта. Мы уже рассмотрели тривиальное
blob
вот и остальные:
на основе Лейф Gruenwoldt ответ, вот функция оболочки заменить на
git hash-object
:git-hash-object () { # substitute when the `git` command is not available local type=blob [ "" = "-t" ] && shift && type= && shift # depending on eol/autocrlf settings, you may want to substitute CRLFs by LFs # by using `perl -pe 's/\r$//g'` instead of `cat` in the next 2 commands local size=$(cat | wc -c | sed 's/ .*$//') ( echo -en "$type $size"; cat "" ) | sha1sum | sed 's/ .*$//' }
тест:
$ echo 'Hello, World!' > test.txt $ git hash-object test.txt 8ab686eafeb1f44702738c8b0f24f2567c36da6d $ git-hash-object test.txt 8ab686eafeb1f44702738c8b0f24f2567c36da6d
мне это было нужно для некоторых модульных тестов в Python 3, поэтому я решил оставить его здесь.
def git_blob_hash(data): if isinstance(data, str): data = data.encode() data = b'blob ' + str(len(data)).encode() + b'' + data h = hashlib.sha1() h.update(data) return h.hexdigest()
Я придерживаюсь
\n
окончания строк везде, но в некоторых случаях Git также может быть изменение окончаний строк перед вычислением этого хэша, так что вам может понадобиться.replace('\r\n', '\n')
там тоже.