Насколько я понимаю, когда Git назначает хеш SHA1 файлу, этот SHA1 уникален для файла в зависимости от его содержимого.
В результате, если файл перемещается из одного репозитория в другой, SHA1 для файла остается прежним, поскольку его содержимое не изменилось.
Как Git вычисляет дайджест SHA1? Это происходит с полным несжатым содержимым файла?
Я хотел бы подражать присвоению SHA1 вне Git.
Ответы:
Вот как Git вычисляет SHA1 для файла (или, в терминах Git, «blob»):
sha1("blob " + filesize + "\0" + data)
Таким образом, вы можете легко вычислить это самостоятельно, не устанавливая Git. Обратите внимание, что «\ 0» - это NULL-байт, а не двухсимвольная строка.
Например, хеш пустого файла:
sha1("blob 0\0") = "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" $ touch empty $ git hash-object empty e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
Другой пример:
sha1("blob 7\0foobar\n") = "323fae03f4606ea9991df8befbb2fca795e648fa" $ echo "foobar" > foo.txt $ git hash-object foo.txt 323fae03f4606ea9991df8befbb2fca795e648fa
Вот реализация Python:
from hashlib import sha1 def githash(data): s = sha1() s.update("blob %u\0" % len(data)) s.update(data) return s.hexdigest()
источник
TypeError: Unicode-objects must be encoded before hashing
исключение в первойs.update()
строке.s.update(("blob %u\0" % filesize).encode('utf-8'))
чтобы избежатьTypeError
.Немного вкусности: в оболочке
echo -en "blob ${#CONTENTS}\0$CONTENTS" | sha1sum
источник
echo -en "blob ${#CONTENTS}\0$CONTENTS" | sha1sum
результат,git hash-object path-to-file
и они дают разные результаты. Тем не менее,echo -e ...
производит правильные результаты, за исключением того, существует скользящий-
(git hash-object
не производит ни одного хвостовых символов). Об этом мне следует беспокоиться?-
используется,sha1sum
если он вычисляет хэш из стандартного ввода, а не из файла. Не о чем беспокоиться. Странная вещь о том-n
, что это должно подавлять новую строку, обычно добавляемую echo. В вашем файле случайно есть пустая последняя строка, которую вы забыли добавить в своюCONTENTS
переменную?cat file | sha1sum
вместоsha1sum file
(хотя больше процессов и трубопроводов)Если у вас не установлен git, вы можете создать функцию оболочки bash для ее вычисления.
git_id () { printf 'blob %s\0' "$(ls -l "$1" | awk '{print $5;}')" | cat - "$1" | sha1sum | awk '{print $1}'; }
источник
(stat --printf="blob %s\0" "$1"; cat "$1") | sha1sum -b | cut -d" " -f1
.Взгляните на страницу руководства для git-hash-object . Вы можете использовать его для вычисления хэша git любого конкретного файла. Я думаю, что git передает в алгоритм хеширования больше, чем просто содержимое файла, но я не знаю наверняка, и если он действительно передает дополнительные данные, я не знаю, что это такое.
источник
/// Calculates the SHA1 for a given string let calcSHA1 (text:string) = text |> System.Text.Encoding.ASCII.GetBytes |> (new System.Security.Cryptography.SHA1CryptoServiceProvider()).ComputeHash |> Array.fold (fun acc e -> let t = System.Convert.ToString(e, 16) if t.Length = 1 then acc + "0" + t else acc + t) "" /// Calculates the SHA1 like git let calcGitSHA1 (text:string) = let s = text.Replace("\r\n","\n") sprintf "blob %d%c%s" (s.Length) (char 0) s |> calcSHA1
Это решение на F #.
источник
Полная реализация Python3:
import os from hashlib import sha1 def hashfile(filepath): filesize_bytes = os.path.getsize(filepath) s = sha1() s.update(b"blob %u\0" % filesize_bytes) with open(filepath, 'rb') as f: s.update(f.read()) return s.hexdigest()
источник
В Perl:
#!/usr/bin/env perl use Digest::SHA1; my $content = do { local $/ = undef; <> }; print Digest::SHA1->new->add('blob '.length($content)."\0".$content)->hexdigest(), "\n";
В качестве команды оболочки:
perl -MDigest::SHA1 -E '$/=undef;$_=<>;say Digest::SHA1->new->add("blob ".length()."\0".$_)->hexdigest' < file
источник
И в Perl (см. Также Git :: PurePerl на http://search.cpan.org/dist/Git-PurePerl/ )
use strict; use warnings; use Digest::SHA1; my @input = <>; my $content = join("", @input); my $git_blob = 'blob' . ' ' . length($content) . "\0" . $content; my $sha1 = Digest::SHA1->new(); $sha1->add($git_blob); print $sha1->hexdigest();
источник
Используя Ruby, вы можете сделать что-то вроде этого:
require 'digest/sha1' def git_hash(file) data = File.read(file) size = data.bytesize.to_s Digest::SHA1.hexdigest('blob ' + size + "\0" + data) end
источник
Небольшой сценарий Bash, который должен выдавать идентичный результат
git hash-object
:источник
В JavaScript
источник
Интересно отметить, что очевидно, что Git добавляет символ новой строки в конец данных перед их хешированием. Файл, не содержащий ничего, кроме "Hello World!" получает хэш blob-объекта 980a0d5 ..., который совпадает с этим:
$ php -r 'echo sha1("blob 13" . chr(0) . "Hello World!\n") , PHP_EOL;'
источник
git hash-object
. Обратите внимание, что выполнениеecho "Hello World!" | git hash-object --stdin
дает980a0d5...
, а использование вместо этогоecho -n
дает хешc57eff5...
.