Как Git вычисляет хэши файлов?

хэши SHA1, хранящиеся в объектах дерева (как возвращено git ls-tree) не соответствуют хэшам SHA1 содержимого файла (как возвращено sha1sum)

$ git cat-file blob 4716ca912495c805b94a88ef6dc3fb4aff46bf3c | sha1sum
de20247992af0f949ae8df4fa9a37e4a03d7063e  -

как Git вычисляет хэш-код? Сжимает ли он содержимое перед вычислением хэша?

5 ответов


git префиксы объекта с " blob ", а затем длина (как читаемое человеком целое число), за которым следует символ 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. Определите хэш blob, выполнив git ls-tree HEAD
  • Шаг 4. Найдите хэш blob быть e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
  • Шаг 5. Snap из вашего удивления и читать ниже

как Git вычисляет свои хэши фиксации

    Commit Hash (SHA1) = SHA1("blob " + <size_of_file> + "" + <contents_of_file>)

текст blob⎵ постоянный префикс и также является постоянным и является NULL символ. The <size_of_file> и <contents_of_file> в зависимости от файла.

и это все люди!

но подождите!, вы заметили, что <filename> не параметр, используемый для вычисления хэша? Два файла потенциально могут иметь одинаковый хэш, если их содержимое одинаково безразлично к дате и времени их создания и их имени. Это одна из причин, почему 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') там тоже.