Как вычисляется хэш git?

Я пытаюсь понять, как git вычисляет хэш ссылок.

$ git ls-remote https://github.com/git/git  

....
29932f3915935d773dc8d52c292cadd81c81071d    refs/tags/v2.4.2
9eabf5b536662000f79978c4d1b6e4eff5c8d785    refs/tags/v2.4.2^{}
....

клонировать РЕПО локально. Проверьте refs/tags/v2.4.2^{} ref by sha

$ git cat-file -p 9eabf5b536662000f79978c4d1b6e4eff5c8d785 

tree 655a20f99af32926cbf6d8fab092506ddd70e49c
parent df08eb357dd7f432c3dcbe0ef4b3212a38b4aeff
author Junio C Hamano <gitster@pobox.com> 1432673399 -0700
committer Junio C Hamano <gitster@pobox.com> 1432673399 -0700

Git 2.4.2

Signed-off-by: Junio C Hamano <gitster@pobox.com>

скопируйте распакованный контент, чтобы мы могли его хэшировать.(AFAIK git использует несжатую версию, когда она хеширует)

git cat-file -p 9eabf5b536662000f79978c4d1b6e4eff5c8d785 > fi

давайте SHA-1 контент, используя собственную команду хэша git

git hash-object fi
3cf741bbdbcdeed65e5371912742e854a035e665

почему выход не [9e]abf5b536662000f79978c4d1b6e4eff5c8d785? Я понимаю, первые два символа (9e) является длина в hex. Как я должен хэшировать содержимое fi так что я могу получить git ref abf5b536662000f79978c4d1b6e4eff5c8d785 ?

2 ответов


как описано в "как формируется git commit sha1 ", формула имеет следующий вид:

(printf "<type> %s" $(git cat-file <type> <ref> | wc -c); git cat-file <type> <ref>)|sha1sum

в случае commit 9eabf5b536662000f79978c4d1b6e4eff5c8d785 (что v2.4.2^{}, и который ссылается на дерево):

(printf "commit %s" $(git cat-file commit 9eabf5b536662000f79978c4d1b6e4eff5c8d785 | wc -c); git cat-file commit 9eabf5b536662000f79978c4d1b6e4eff5c8d785 )|sha1sum

это даст 9eabf5b536662000f79978c4d1b6e4eff5c8d785.

как:

(printf "commit %s" $(git cat-file commit v2.4.2{} | wc -c); git cat-file commit v2.4.2{})|sha1sum

(все еще 9eabf5b536662000f79978c4d1b6e4eff5c8d785)

аналогично, вычисляя SHA1 V2 тегов.4.2 должен быть:

(printf "tag %s" $(git cat-file tag v2.4.2 | wc -c); git cat-file tag v2.4.2)|sha1sum

это даст 29932f3915935d773dc8d52c292cadd81c81071d.


здесь немного путаницы. Git использует различные типы объектов: капли, деревья и фиксации. Следующая команда:

git cat-file -t <hash>

сообщает вам тип объекта для данного хэша. Таким образом, в вашем примере хэш 9eabf5b536662000f79978c4d1b6e4eff5c8d785 соответствует объекту фиксации.

теперь, как вы сами поняли, запустив это:

git cat-file -p 9eabf5b536662000f79978c4d1b6e4eff5c8d785

дает содержание объекта в соответствии с его типом (в данном случае совершать.)

а это:

git hash-object fi

...вычисляет хэш для blob, содержимое которого является выходом предыдущей команды (в вашем примере), но это может быть что-то еще (например, "hello world!"). Вот попробуйте это:

echo "blob 277$(cat fi)" | shasum

вывод такой же, как и предыдущая команда. Это в основном, как Git хеширует blob. Так хэширования в интернет, вы создаете объект типа Blob. Но, как мы видели, 9eabf5b536662000f79978c4d1b6e4eff5c8d785-это фиксация, а не blob. Итак, ты не может хэшировать fi, как это, чтобы получить тот же хэш.

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

Анатомия git commit

таким образом, вы можете получить тот же хэш, предоставив все данные, указанные в статье, с теми же значениями, что и в оригинале совершать.

Это также может быть полезно:

Git снизу вверх