据我所知,当Git为文件分配SHA1哈希时,此SHA1根据其内容对文件是唯一的。
因此,如果文件从一个存储库移动到另一个存储库,则该文件的SHA1保持不变,因为其内容未更改。
Git如何计算SHA1摘要?它是在完整的未压缩文件内容上执行的吗?
我想模仿在Git之外分配SHA1。
答案 0 :(得分:249)
这就是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()
答案 1 :(得分:17)
一点点好事:在shell中
echo -en "blob ${#CONTENTS}\0$CONTENTS" | sha1sum
答案 2 :(得分:8)
如果你没有安装git,你可以使用bash shell函数来轻松计算它。
git_id () { printf 'blob %s\0' "$(ls -l "$1" | awk '{print $5;}')" | cat - "$1" | sha1sum | awk '{print $1}'; }
答案 3 :(得分:4)
查看git-hash-object的手册页。您可以使用它来计算任何特定文件的git哈希。我认为 git不仅仅将文件的内容提供给哈希算法,但我不确定,如果它确实提供了额外的数据,我不知道它是什么是
答案 4 :(得分:2)
/// 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#中的解决方案。
答案 5 :(得分:2)
完整的Python3实现:
import os
from hashlib import sha1
def hashfile(filepath):
filesize_bytes = os.path.getsize(filepath)
s = sha1()
s.update(("blob %u\0" % filesize_bytes).encode('utf-8'))
with open(filepath, 'rb') as f:
s.update(f.read())
return s.hexdigest()
答案 6 :(得分:1)
在Perl中(另见http://search.cpan.org/dist/Git-PurePerl/的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();
答案 7 :(得分:1)
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";
作为shell命令:
perl -MDigest::SHA1 -E '$/=undef;$_=<>;say Digest::SHA1->new->add("blob ".length()."\0".$_)->hexdigest' < file
答案 8 :(得分:1)
使用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
答案 9 :(得分:1)
一个小的Bash脚本,它应该产生与git hash-object
相同的输出:
#!/bin/sh
(
echo -en 'blob '"$(stat -c%s "$1")"'\0';
cat "$1"
) | sha1sum | cut -d\ -f 1
答案 10 :(得分:0)
在JavaScript中
public static void doSomethingToCommands(List<? extends Command> commands) {
commands.forEach(this::doSomething);
}
List<FooCommand> fooCommands = getFooCommands();
doSomethingToComamnds(fooCommands); // Allowed
List<Command> commands = getRandomCommands();
doSomethingToComamnds(commands); // Not allowed.
答案 11 :(得分:0)
您也可以对文件应用相同的内容
$ echo "foobar" > foo.txt
$ echo "$(cat foo.txt)"|(read f; echo -en "blob "$((${#f}+1))"\0$f\n" )|openssl sha1
323fae03f4606ea9991df8befbb2fca795e648fa
答案 12 :(得分:-4)
值得注意的是,显然Git会在数据结尾之前添加换行符,然后才会进行哈希处理。一个包含“Hello World!”的文件。得到一个980a0d5的blob哈希...,与此相同:
$ php -r 'echo sha1("blob 13" . chr(0) . "Hello World!\n") , PHP_EOL;'