如何将Git SHA1分配给没有Git的文件?

据我了解,当Git给一个文件分配一个SHA1哈希值时,这个SHA1对于该文件是基于其内容而言是唯一的。

因此,如果文件从一个存储库移动到另一个存储库,文件的SHA1保持不变,而其内容没有改变。

Git如何计算SHA1摘要? 它是否在完整的未压缩的文件内容?

我想仿效在Git之外分配SHA1。

这就是Git如何计算一个文件的SHA1(或者在Git中,是一个“blob”):

sha1("blob " + filesize + "\0" + data) 

所以你可以很容易地自己计算,而不必安装Git。 请注意“\ 0”是空字节,而不是两个字符的string。

例如,一个空文件的散列:

 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() 

一个小东西:壳

 echo -en "blob ${#CONTENTS}\0$CONTENTS" | sha1sum 

如果你没有安装git,你可以做一个bash shell函数来计算它。

 git_id () { printf 'blob %s\0' "$(ls -l "$1" | awk '{print $5;}')" | cat - "$1" | sha1sum | awk '{print $1}'; } 

看看git-hash-object的手册页。 你可以使用它来计算任何特定文件的git散列。 我认为 ,git提供的不仅仅是文件的内容到哈希algorithm,但我不知道,如果它提供额外的数据,我不知道它是什么。

完整的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() 
 /// 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#中的一个解决scheme。

在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 

在Perl中(另请参阅http://search.cpan.org/dist/Git-PurePerl/上的; Git :: PurePerl)

 use strict; use warnings; use Digest::SHA1; my @input = &lt;&gt;; 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

 #!/bin/sh ( echo -en 'blob '"$(stat -c%s "$1")"'\0'; cat "$1" ) | sha1sum | cut -d\ -f 1 

有意思的是,显然Git会在数据结束之前在数据的末尾添加换行符。 一个不包含“Hello World!”的文件 得到一个980a0d5 …的blob哈希,和这个一样:

 $ php -r 'echo sha1("blob 13" . chr(0) . "Hello World!\n") , PHP_EOL;'