2009-02-16 36 views
134

据我了解,当Git为一个文件分配一个SHA1哈希值时,这个SHA1对于该文件根据其内容是唯一的。如何将Git SHA1分配给没有Git的文件?

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

Git如何计算SHA1摘要?它是否在完整的未压缩文件内容上做到这一点?

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

+0

http://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html – 2011-08-29 01:46:10

回答

240

这是Git是如何计算SHA1一个文件(或者,在Git的术语中,“斑点”):

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

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

例如,一个空文件的哈希:

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

非常有用。谢谢 – 2009-11-22 19:14:49

+4

这真棒,+10,如果我能的人! – hasen 2010-03-15 15:36:08

+0

这个答案是否假设Python 2?当我在Python 3上尝试这个时,我得到一个'TypeError:Unicode-objects必须在第一个's.update()`行的哈希异常之前被编码。 – 2013-06-10 00:05:47

4

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

8

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

git_id() { printf 'blob %s\0' "$(ls -l "$1" | awk '{print $5;}')" | cat - "$1" | sha1sum | awk '{print $1}'; } 
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#的溶液。

17

小礼包:在外壳

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

而且在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(); 
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 
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() 
-4

这是有趣的是,明显的Git增加了一个换行符的数据到底会被散列之前。只包含“Hello World!”的文件获得980a0d5的一团散列...,这与此相同之一:

$ php -r 'echo sha1("blob 13" . chr(0) . "Hello World!\n") , PHP_EOL;' 
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 
1

一个小bash脚本,应该产生相同的输出git hash-object

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