web-dev-qa-db-fra.com

Comment git compute le fichier de hachage?

Les hachages SHA1 stockés dans les objets de l'arborescence (tels que retournés par git ls-tree) ne correspond pas aux hachages SHA1 du contenu du fichier (tel que retourné par sha1sum)

$ git cat-file blob 4716ca912495c805b94a88ef6dc3fb4aff46bf3c | sha1sum
de20247992af0f949ae8df4fa9a37e4a03d7063e  -

Comment git compute le fichier de hachage? Compresse-t-il le contenu avant de calculer le hachage?

119
netvope

Git préfixe l'objet avec "blob", suivi de la longueur (sous forme d'entier lisible par l'homme), suivi d'un caractère NUL

$ echo -e 'blob 14\0Hello, World!' | shasum 8ab686eafeb1f44702738c8b0f24f2567c36da6d

Source: http://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html

114
Leif Gruenwoldt

Je ne fais que développer la réponse de @Leif Gruenwoldt et en détaillant le contenu de la référence fournie par @Leif Gruenwoldt

Faites-le vous-même ..

  • Étape 1. Créez un document texte vide (le nom importe peu) dans votre référentiel
  • Étape 2. Mettez en scène et engagez le document
  • Étape 3. Identifiez le hachage du blob en exécutant git ls-tree HEAD
  • Étape 4. Trouvez le hash du blob devant être e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
  • Étape 5. Sortez de votre surprise et lisez ci-dessous

Comment GIT calcule-t-il ses hachages de validation

    Commit Hash (SHA1) = SHA1("blob " + <size_of_file> + "\0" + <contents_of_file>)

Le texte blob⎵ est un préfixe constant et \0 est également constant et constitue le caractère NULL. Le <size_of_file> et <contents_of_file> varie en fonction du fichier.

Voir: Quel est le format de fichier d'un objet git commit?

Et c'est tout le monde!

Mais attendez! , avez-vous remarqué que le <filename> n'est-ce pas un paramètre utilisé pour le calcul du hachage? Deux fichiers peuvent potentiellement avoir le même hash si leur contenu est indifférent de la date et de l'heure de leur création et de leur nom. C'est l'une des raisons pour lesquelles Git gère les mouvements et renomme mieux que d'autres systèmes de contrôle de version.

Faites-le vous-même (Ext)

  • Étape 6. Créez un autre fichier vide avec un autre filename dans le même répertoire
  • Étape 7. Comparez les hachages de vos deux fichiers.

Remarque:

Le lien ne mentionne pas comment l'objet tree est haché. Je ne suis pas certain de l'algorithme et des paramètres, mais d'après mon observation, il calcule probablement un hachage basé sur tous les blobs et trees (leurs hachages probablement) qu'il contient.

34
Lordbalmon

git hash-object

C'est un moyen rapide de vérifier votre méthode de test:

s='abc'
printf "$s" | git hash-object --stdin
printf "blob $(printf "$s" | wc -c)\0$s" | sha1sum

Sortie:

f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f
f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f  -

sha1sum est dans GNU Coreutils.

Ensuite, il faut comprendre le format de chaque type d'objet. Nous avons déjà couvert le trivial blob, voici les autres:

J'avais besoin de cela pour certains tests unitaires dans Python 3 alors j'ai pensé le laisser ici.

def git_blob_hash(data):
    if isinstance(data, str):
        data = data.encode()
    data = b'blob ' + str(len(data)).encode() + b'\0' + data
    h = hashlib.sha1()
    h.update(data)
    return h.hexdigest()

Je m'en tiens à la fin de la ligne \n Partout, mais dans certaines circonstances, Git peut aussi être changer la fin de la ligne avant de calculer ce hachage afin que vous puissiez avoir besoin d'un .replace('\r\n', '\n') dedans aussi.

3
Samuel Harmer

Sur la base de Leif Gruenwoldt answer, voici une fonction Shell qui remplace substitut à git hash-object :

git-hash-object () { # substitute when the `git` command is not available
    local type=blob
    [ "$1" = "-t" ] && shift && type=$1 && shift
    # depending on eol/autocrlf settings, you may want to substitute CRLFs by LFs
    # by using `Perl -pe 's/\r$//g'` instead of `cat` in the next 2 commands
    local size=$(cat $1 | wc -c | sed 's/ .*$//')
    ( echo -en "$type $size\0"; cat "$1" ) | sha1sum | sed 's/ .*$//'
}

Tester:

$ echo 'Hello, World!' > test.txt
$ git hash-object test.txt
8ab686eafeb1f44702738c8b0f24f2567c36da6d
$ git-hash-object test.txt
8ab686eafeb1f44702738c8b0f24f2567c36da6d
3
Lucas Cimon