web-dev-qa-db-fra.com

Comment assigner un Git SHA1 à un fichier sans Git?

Si je comprends bien, lorsque Git attribue un hachage SHA1 à un fichier, ce SHA1 est unique pour le fichier en fonction de son contenu. 

En conséquence, si un fichier passe d'un référentiel à un autre, SHA1 reste le même car son contenu n'a pas changé. 

Comment Git calcule-t-il le résumé SHA1? Le fait-il sur le contenu complet du fichier non compressé? 

Je voudrais émuler l'attribution de SHA1 en dehors de Git.

137
git-noob

Voici comment Git calcule le SHA1 pour un fichier (ou, en termes git, un "blob"):

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

Ainsi, vous pouvez facilement le calculer vous-même sans avoir installé Git. Notez que "\ 0" est l'octet NULL et non une chaîne de deux caractères.

Par exemple, le hachage d'un fichier vide:

sha1("blob 0\0") = "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"

$ touch empty
$ git hash-object empty
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391

Un autre exemple:

sha1("blob 7\0foobar\n") = "323fae03f4606ea9991df8befbb2fca795e648fa"

$ echo "foobar" > foo.txt
$ git hash-object foo.txt 
323fae03f4606ea9991df8befbb2fca795e648fa

Voici une implémentation Python:

from hashlib import sha1
def githash(data):
    s = sha1()
    s.update("blob %u\0" % len(data))
    s.update(data)
    return s.hexdigest()
248
Ferdinand Beyer

Un petit goodie: dans Shell

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

Vous pouvez créer une fonction shell bash pour la calculer assez facilement si vous n’avez pas installé git.

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

Jetez un coup d’œil à la page de manuel relative à git-hash-object . Vous pouvez l'utiliser pour calculer le hachage git d'un fichier particulier. Je pense que git alimente plus que le contenu du fichier dans l'algorithme de hachage, mais je ne le sais pas avec certitude, et s'il contient des données supplémentaires, je ne sais pas ce que c'est.

4
Dale Hagglund

Implémentation complète de 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

Ceci est une solution en F #.

2
forki23

Et en Perl (voir aussi Git :: PurePerl sur 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
Alec the Geek

Un petit script Bash qui devrait produire une sortie identique à git hash-object:

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

En 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";

En tant que commande Shell:

Perl -MDigest::SHA1 -E '$/=undef;$_=<>;say Digest::SHA1->new->add("blob ".length()."\0".$_)->hexdigest' < file
1
dolmen

En utilisant Ruby, vous pourriez faire quelque chose comme ceci:

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

En 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