Quelle quantité de git sha est * généralement * considérée comme nécessaire pour identifier de manière unique un changement dans une base de code donnée?

212

Si vous allez construire, disons, une structure de répertoires dans laquelle un répertoire est nommé pour une validation dans un référentiel Git, et que vous voulez qu'il soit suffisamment court pour que vos yeux ne saignent pas, mais suffisamment longtemps pour que les chances de collision serait négligeable, quelle proportion de la sous-chaîne SHA est généralement requise?

Disons que je veux identifier de manière unique ce changement: https://github.com/wycats/handlebars.js/commit/e62999f9ece7d9218b9768a908f8df9c11d7e920

Je peux utiliser aussi peu que les quatre premiers caractères: https://github.com/wycats/handlebars.js/commit/e629

Mais je pense que ce serait risqué. Mais en résumant une base de code qui, sur quelques années, pourrait avoir - disons - 30 000 changements, quelles sont les chances de collision si j'utilise 8 caractères? 12? Y a-t-il un nombre qui est généralement considéré comme acceptable pour ce genre de chose?

Jun-Dai Bates-Kobashigawa
la source

Réponses:

230

Cette question trouve sa réponse dans le chapitre 7 du livre Pro Git :

Généralement, huit à dix caractères sont plus que suffisants pour être uniques dans un projet. L'un des plus grands projets Git, le noyau Linux, commence à avoir besoin de 12 caractères sur les 40 possibles pour rester unique.

7 chiffres est la valeur par défaut de Git pour un SHA court, donc c'est bien pour la plupart des projets. L'équipe Kernel a augmenté la leur plusieurs fois, comme mentionné, car elle compte plusieurs centaines de milliers de commits. Donc, pour vos ~ 30k commits, 8 ou 10 chiffres devraient être parfaitement bien.

Nevik Rehnel
la source
38
Notez également que gitc'est assez intelligent en ce qui concerne cela. Vous pouvez définir l'abréviation courte, disons à 4, et gitutiliserez 4 chiffres pour autant de hachages que possible, mais passez à 5 ou plus quand il sait que l'abréviation n'est pas unique ...
twalberg
31
Notez également que cela ne s'applique bien sûr que pour le moment où Git imprime le SHA. Si vous "enregistrez" des SHA abrégés (par exemple, dans les journaux, les e-mails, les messages instantanés, etc.) et les utilisez plus tard pour faire référence aux validations, ils pourraient ne plus être uniques! Bien que cela soit certainement peu probable pour des longueurs normales comme 7-12 caractères, si vous descendez à 4 ou 5, et que vous obtenez quelques dix mille nouveaux objets (ou commits, selon le contexte), cela pourrait en effet revenir vous mordre.
Nevik Rehnel
140

Remarque: vous pouvez demander git rev-parse --shortle SHA1 le plus court et pourtant unique.
Voir " git get short hash from regular hash "

git rev-parse --short=4 921103db8259eb9de72f42db8b939895f5651489
92110

Comme vous pouvez le voir dans mon exemple, le SHA1 a une longueur de 5 même si j'ai spécifié une longueur de 4.


Pour les gros dépôts, 7 n'est pas suffisant depuis 2010, et engagez dce9648 par Linus Torvalds lui-même (git 1.7.4.4, octobre 2010):

La valeur par défaut de 7 vient d'un développement assez précoce dans git, lorsque sept chiffres hexadécimaux étaient beaucoup (il couvre environ 250+ millions de valeurs de hachage).
À l'époque, je pensais que 65 000 révisions, c'était beaucoup (c'était ce que nous allions frapper dans BK), et chaque révision a tendance à être d'environ 5 à 10 nouveaux objets, donc un million d'objets était un grand nombre.

(BK = BitKeeper)

De nos jours, le noyau n'est même pas le plus grand projet git, et même le noyau a environ 220k révisions ( beaucoup plus grand que l'arbre BK) et nous approchons de deux millions d'objets.
À ce stade, sept chiffres hexadécimaux sont encore uniques pour beaucoup d'entre eux, mais lorsque nous parlons de seulement deux ordres de grandeur entre le nombre d'objets et la taille de hachage, il y aura des collisions dans les valeurs de hachage tronquées.
Ce n'est même plus près d'être irréaliste - cela arrive tout le temps.

Nous devons à la fois augmenter l'abréviation par défaut qui était trop petite et ajouter un moyen pour les gens de définir leur propre projet par défaut dans le fichier de configuration git .

core.abbrev

Définissez la longueur des noms d'objet en abrégé.
Si elles ne sont pas spécifiées, de nombreuses commandes sont abrégées en 7 chiffres hexadécimaux, ce qui peut ne pas être suffisant pour que les noms d'objet abrégés restent uniques pendant suffisamment longtemps.

environment.c:

int minimum_abbrev = 4, default_abbrev = 7;

Remarque: Comme commenté ci-dessous par marco.m , a core.abbrevLengthété renommé core.abbrevdans ce même Git 1.7.4.4 dans commit a71f09f

Renommer core.abbrevlengthencore.abbrev

Cela correspond à l' --abbrev=$noption de ligne de commande après tout.


Plus récemment, Linus a ajouté dans commit e6c587c (pour Git 2.11, Q4 2016):
(comme mentionné dans la réponse de Matthieu Moy )

Dans les premiers jours, nous avons en quelque sorte décidé d'abréger les noms des objets jusqu'à 7 chiffres hexadécimaux, mais au fur et à mesure que les projets se développent, il est de plus en plus probable de voir des noms d'objet aussi courts créés dans les premiers jours et enregistrés dans les messages du journal qui ne sont plus uniques.

Actuellement, le projet du noyau Linux a besoin de 11 à 12 chiffres hexadécimaux, tandis que Git lui-même a besoin de 10 chiffres hexadécimaux pour identifier de manière unique les objets dont ils disposent, tandis que de nombreux projets plus petits peuvent toujours convenir avec la valeur par défaut d'origine à 7 chiffres hexadécimaux. La taille unique ne convient pas à tous les projets.

Introduisez un mécanisme, où nous estimons le nombre d'objets dans le référentiel à la première demande d'abréger un nom d'objet avec le paramètre par défaut et trouver une valeur par défaut saine pour le référentiel. Sur la base de l'attente que nous 2^(2N)verrions une collision dans un référentiel avec des objets lors de l'utilisation de noms d'objets raccourcis aux N premiers bits, utilisez un nombre suffisant de chiffres hexadécimaux pour couvrir le nombre d'objets dans le référentiel.
Chaque hexadigit (4 bits) que nous ajoutons au nom abrégé nous permet d'avoir quatre fois (2 bits) autant d'objets dans le référentiel.

Voir commit e6c587c (01 octobre 2016) par Linus Torvalds ( torvalds) .
Voir commit 7b5b772 , commit 65acfea (01 oct.2016 ) par Junio ​​C Hamano ( gitster) .
(Fusionné par Junio ​​C Hamano - gitster- en commit bb188d0 , 03 oct.2016 )

Cette nouvelle propriété (deviner une valeur par défaut raisonnable pour la valeur d'abréviation SHA1) a un effet direct sur la façon dont Git calcule son propre numéro de version pour publication .

VonC
la source
3
Cette réponse permet de vérifier quel est le hachage "raccourci" le plus long dans un référentiel unique: stackoverflow.com/a/32406103/1858225
Kyle Strand
1
Notez qu'il core.abbrevLengtha été renommé core.abbrev.
marco.m
@ marco.m Merci. J'ai modifié la réponse en conséquence. Et j'ai lié au commit Git qui enregistre ce nouveau nom pour core.abbrev.
VonC
Je vais juste ajouter à cela que vous pouvez exécuter git rev-parse --short=10 --verify HEADpour générer 10 caractères. Nous utilisions git log -1 --format=%h, mais cela n'a généré que 7 caractères et nous avons eu une collision.
grayaii
Merci pour l'explication, les documents ( git-scm.com/docs/git-rev-parse ) sont périmés.
André Werlang
36

Ceci est connu comme le problème d'anniversaire.

Pour des probabilités inférieures à 1/2, la probabilité d'une collision peut être approximée comme

p ~ = (n 2 ) / (2m)

Où n est le nombre d'articles et m est le nombre de possibilités pour chaque article.

Le nombre de possibilités pour une chaîne hexadécimale est de 16 c où c est le nombre de caractères.

Donc pour 8 caractères et 30K commits

30K ~ = 2 15

p ~ = (n 2 ) / (2m) = ~ ((2 15 ) 2 ) / (2 * 16 8 ) = 2 30 /2 33 = ⅛

L'augmenter à 12 caractères

p ~ = (n 2 ) / (2m) = ~ ((2 15 ) 2 ) / (2 * 16 12 ) = 2 30 /2 49 = 2 -19

plugwash
la source
Exactement la question que j'essayais de résoudre, merci! Le tableau de probabilité lié dans la réponse de @ Messa est également utile.
Kyle Chadha
excellent, nous n'avons besoin de rien d'autre mais de plus comme ça, expliquez non seulement ce que c'est mais aussi comment ça se fait ...
workplaylifecycle
13

Cette question a été répondue, mais pour tous ceux qui recherchent les mathématiques derrière - cela s'appelle Problème d'anniversaire ( Wikipedia ).

Il s'agit de la probabilité d'avoir 2 (ou plus) personnes d'un groupe de N personnes pour fêter leur anniversaire le même jour de l'année. Ce qui est analogue à probablement 2 commits git (ou plus) à partir du référentiel ayant N commits au total ayant le même préfixe de hachage de longueur X.

Regardez le tableau des probabilités . Par exemple, pour une chaîne hexadécimale de hachage de longueur 8, la probabilité d'avoir une collision atteint 1% lorsque le référentiel contient à peu près 9300 éléments (git s'engage). Pour 110 000 commits, la probabilité est de 75%. Mais si vous avez une chaîne hexadécimale de hachage de longueur 12, la probabilité de collision dans 100 000 commits est inférieure à 0,1%.

Messa
la source
2

Git version 2.11 (ou peut-être 2.12?) Contiendra une fonctionnalité qui adapte le nombre de caractères utilisés dans les identifiants courts (par exemple git log --oneline) à la taille du projet. Une fois que vous utilisez une telle version de Git, la réponse à votre question peut être "choisissez la longueur que Git vous donne avecgit log --oneline , c'est assez sûr".

Pour plus de détails, voir Changer la valeur par défaut de «core.abbrev»? discussion dans Git Rev News édition 20 et validez bb188d00f7 .

Matthieu Moy
la source