144 votes

Comment attribuer les SHA1 de Git à 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.

Par conséquent, si un fichier est déplacé d'un dépôt à un autre, le SHA1 du fichier reste le même car son contenu n'a pas changé.

Comment Git calcule-t-il le condensé SHA1 ? Est-ce qu'il le fait sur le contenu complet du fichier non compressé ?

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

0 votes

0 votes

262voto

Ferdinand Beyer Points 27723

C'est ainsi que Git calcule le SHA1 d'un fichier (ou, en termes de Git, d'un "blob") :

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

Vous pouvez donc 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()

0 votes

Cette réponse s'applique-t-elle à Python 2 ? Lorsque j'essaie de faire cela avec Python 3, j'obtiens une TypeError: Unicode-objects must be encoded before hashing exception au premier s.update() ligne.

3 votes

Avec python 3, vous devez coder les données : s.update(("blob %u\0" % filesize).encode('utf-8')) pour éviter le TypeError .

0 votes

L'encodage en utf-8 fonctionnera, mais il est probablement préférable de le construire à partir d'une chaîne d'octets en premier lieu (l'encodage utf-8 fonctionne parce qu'aucun des caractères unicode n'est non-ASCII).

18voto

knittl Points 64110

Un petit bonbon : en coquille

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

1 votes

Je compare echo -en "blob ${#CONTENTS}\0$CONTENTS" | sha1sum à la sortie de git hash-object path-to-file et ils produisent des résultats différents. Cependant, echo -e ... produit les résultats corrects, sauf qu'il y a une queue de poisson. - ( git hash-object produit pas de caractères de fin de ligne). Dois-je m'en inquiéter ?

2 votes

@FrustratedWithFormsDesigner : La queue - est utilisé par sha1sum s'il a calculé le hachage depuis stdin et non depuis un fichier. Rien à craindre. Une chose étrange cependant à propos du -n qui devrait supprimer la nouvelle ligne normalement ajoutée par echo. Est-ce que, par hasard, votre fichier a une dernière ligne vide, que vous avez oublié d'ajouter dans votre commande CONTENTS variable ?

0 votes

Oui, vous avez raison. Et j'avais pensé que la sortie de sha1sum devait uniquement être le hash, mais il n'est pas difficile de l'enlever avec sed ou autre.

9voto

Charles Bailey Points 244082

Vous pouvez créer une fonction shell bash pour le 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}'; }

1 votes

Un peu plus court : (stat --printf="blob %s\0" "$1"; cat "$1") | sha1sum -b | cut -d" " -f1 .

4voto

Dale Hagglund Points 7159

Jetez un coup d'œil à la page de manuel de git-hash-object . Vous pouvez l'utiliser pour calculer le hachage git d'un fichier particulier. I pensez à que git introduit plus que le contenu du fichier dans l'algorithme de hachage, mais je n'en suis pas sûr, et s'il introduit des données supplémentaires, je ne sais pas lesquelles.

2voto

forki23 Points 1225
/// 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

Il s'agit d'une solution en F#.

0 votes

J'ai toujours des problèmes avec les trémas : calcGitSHA1("ü").ShouldBeEqualTo("0f0f3e3b1ff2bc6722afc3e3812e6b782683896f") Mais ma fonction donne 0d758c9c7bc06c1e307f05d92d896aaf0a8a6d2c. Une idée sur la façon dont git hash-object gère les trémas ?

0 votes

Il devrait traiter le blob comme un bytestream, ce qui signifie que ü a probablement la longueur 2 (unicode), la propriété Length de F retournera la longueur 1 (parce qu'il n'y a qu'un seul caractère visible)

0 votes

Mais System.Text.Encoding.ASCII.GetBytes("ü") renvoie un tableau d'octets avec 1 élément.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X