web-dev-qa-db-ja.com

GitなしでGit SHA1をファイルに割り当てる方法

GitがファイルにSHA1ハッシュを割り当てると、このSHA1はその内容に基づいてファイルに一意であることがわかります。

その結果、ファイルが1つのリポジトリから別のリポジトリに移動した場合、そのファイルのSHA1は内容が変更されていないため同じままです。

GitはSHA1ダイジェストをどのように計算しますか?完全な非圧縮ファイルの内容でそれを行いますか?

Gitの外部でSHA1の割り当てをエミュレートしたいと思います。

138
git-noob

これは、Gitがファイル(または、Gitの用語では「ブロブ」)の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()
250
Ferdinand Beyer

ちょっとしたおやつ:Shell

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

Gitをインストールしていない場合は、bashシェル関数を作成して簡単に計算できます。

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

git-hash-object のmanページをご覧ください。これを使用して、特定のファイルのgitハッシュを計算できます。 Ithinkgitはファイルのコンテンツだけでなくハッシュアルゴリズムにフィードしますが、確かではありません。追加データでは、それが何であるかわかりません。

4
Dale Hagglund

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() 
2
Tomer
/// 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#のソリューションです。

2
forki23

そして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();
1
Alec the Geek

git hash-objectと同一の出力を生成する小さなBashスクリプト:

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

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
1
dolmen

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
Leif

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}`)
}
0
EnZo