私が理解しているように、GitがSHA1ハッシュをファイルに割り当てるとき、このSHA1はその内容に基づいてファイルに固有です。
その結果、ファイルがあるリポジトリから別のリポジトリに移動した場合、ファイルのSHA1は、その内容が変更されていないので同じままです。
GitはSHA1ダイジェストをどのように計算しますか?それは完全な非圧縮ファイルの内容でそれをしますか?
Gitの外部でSHA1を割り当てることをエミュレートしたいと思います。
私が理解しているように、GitがSHA1ハッシュをファイルに割り当てるとき、このSHA1はその内容に基づいてファイルに固有です。
その結果、ファイルがあるリポジトリから別のリポジトリに移動した場合、ファイルのSHA1は、その内容が変更されていないので同じままです。
GitはSHA1ダイジェストをどのように計算しますか?それは完全な非圧縮ファイルの内容でそれをしますか?
Gitの外部でSHA1を割り当てることをエミュレートしたいと思います。
回答:
これは、Gitがファイル(またはGit用語では「blob」)のSHA1を計算する方法です。
sha1("blob " + filesize + "\0" + data)
したがって、Gitをインストールしなくても、自分で簡単に計算できます。「\ 0」はNULL文字であり、2文字の文字列ではないことに注意してください。
たとえば、空のファイルのハッシュ:
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
通常はエコーによって追加される改行を抑制します。あなたのファイルには、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の manページをご覧ください。これを使用して、特定のファイルの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(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();
JavaScriptで
const crypto = require('crypto')
const bytes = require('utf8-bytes')
function sha1(data) {
const shasum = crypto.createHash('sha1')
shasum.update(data)
return shasum.digest('hex')
}
function shaGit(data) {
const total_bytes = bytes(data).length
return sha1(`blob ${total_bytes}\0${data}`)
}
興味深いことに、Gitは明らかに、ハッシュされる前にデータの最後に改行文字を追加します。「Hello World!」のみを含むファイル 980a0d5 ...のblobハッシュを取得します。これは次のものと同じです。
$ 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...
代わりに。