Quanto di un git sha è * generalmente * considerato necessario per identificare in modo univoco una modifica in una data base di codice?


212

Se hai intenzione di costruire, diciamo, una struttura di directory in cui una directory è nominata per un commit in un repository Git e vuoi che sia abbastanza corta da non far sanguinare gli occhi, ma abbastanza a lungo da permettergli di scontrarsi sarebbe trascurabile, quanta parte della sottostringa SHA è generalmente richiesta?

Diciamo che voglio identificare in modo univoco questa modifica: https://github.com/wycats/handlebars.js/commit/e62999f9ece7d9218b9768a908f8df9c11d7e920

Posso usare solo i primi quattro caratteri: https://github.com/wycats/handlebars.js/commit/e629

Ma penso che sarebbe rischioso. Ma supponendo una base di codice che, nel giro di un paio d'anni, potrebbe avere - diciamo - cambiamenti di 30k, quali sono le possibilità di collisione se uso 8 caratteri? 12? C'è un numero generalmente considerato accettabile per questo genere di cose?


Risposte:


230

A questa domanda viene effettivamente data risposta nel capitolo 7 del libro Pro Git :

Generalmente, da otto a dieci personaggi sono più che sufficienti per essere unici all'interno di un progetto. Uno dei più grandi progetti Git, il kernel Linux, inizia a richiedere 12 caratteri su 40 possibili per rimanere unico.

7 cifre è l'impostazione predefinita Git per un breve SHA, quindi va bene per la maggior parte dei progetti. Il team del Kernel ha aumentato le loro diverse volte, come detto, perché ha diverse centinaia di migliaia di commit. Quindi per i tuoi ~ 30k commit, 8 o 10 cifre dovrebbero andare perfettamente bene.


38
Si noti inoltre che gitè abbastanza intelligente quando si tratta di questo. Puoi impostare l'abbreviazione breve, diciamo a 4, e gituserai 4 cifre per il maggior numero di hash che può, ma passa a 5 o più quando sa che l'abbreviazione non è unica ...
twalberg

31
Nota anche che questo ovviamente vale solo per il momento in cui Git stampa lo SHA. Se "salvi" gli SHA abbreviati (ad esempio nei registri, nelle e-mail, nei messaggi istantanei, ecc.) E li usi in seguito per fare riferimento ai commit, potrebbero non essere più unici! Sebbene sia improbabile per lunghezze normali come 7-12 caratteri, se scendi a 4 o 5, e ottieni alcune diecimila nuovi oggetti (o commetti, a seconda del contesto), questo potrebbe effettivamente tornare a morderti.
Nevik Rehnel,

140

Nota: è possibile richiedere git rev-parse --shortlo SHA1 più corto ma unico.
Vedi " git get hash corto da hash regolare "

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

Come puoi vedere nel mio esempio, SHA1 ha una lunghezza di 5 anche se ho specificato una lunghezza di 4.


Per i grandi repository, 7 non è abbastanza dal 2010 e impegna dce9648 dallo stesso Linus Torvalds (git 1.7.4.4, ott 2010):

Il valore predefinito di 7 proviene da uno sviluppo git abbastanza precoce, quando sette cifre esadecimali erano molte (copre circa 250+ milioni di valori hash).
Allora pensavo che le revisioni a 65k fossero molte (era quello che stavamo per colpire in BK), e ogni revisione tendeva ad essere circa 5-10 nuovi oggetti o giù di lì, quindi un milione di oggetti era un grande numero.

(BK = BitKeeper)

In questi giorni, il kernel non è nemmeno il più grande progetto git, e anche il kernel ha circa 220k revisioni ( molto più grande di quanto l'albero BK sia mai stato) e ci stiamo avvicinando a due milioni di oggetti.
A quel punto, sette cifre esadecimali sono ancora uniche per molti di loro, ma quando parliamo solo di due ordini di differenza di grandezza tra il numero di oggetti e la dimensione dell'hash, ci saranno collisioni nei valori di hash troncati.
Non è nemmeno più vicino all'irrealistico: succede sempre.

Dovremmo sia aumentare l'abbrevia predefinito che era irrealisticamente piccolo, sia aggiungere un modo per le persone di impostare il proprio progetto predefinito nel file di configurazione git .

core.abbrev

Impostare la lunghezza a cui sono abbreviati i nomi degli oggetti.
Se non specificato, molti comandi abbreviano in 7 cifre esadecimali, il che potrebbe non essere sufficiente affinché i nomi degli oggetti abbreviati rimangano univoci per un tempo sufficientemente lungo.

environment.c:

int minimum_abbrev = 4, default_abbrev = 7;

Nota: come commentato di seguito da marco.m , è core.abbrevLengthstato rinominato core.abbrevin quello stesso Git 1.7.4.4 in commit a71f09f

Rinomina core.abbrevlengthincore.abbrev

Dopotutto corrisponde --abbrev=$nall'opzione della riga di comando.


Più di recente, Linus ha aggiunto a commettere e6c587c (per Git 2.11, Q4 2016):
(come indicato nel Matthieu Moy 's risposta )

In tempi abbastanza precoci abbiamo in qualche modo deciso di abbreviare i nomi degli oggetti fino a 7 cifre esadecimali, ma man mano che i progetti crescono, sta diventando sempre più probabile vedere nomi di oggetti così brevi realizzati in giorni precedenti e registrati nei messaggi di registro non più unici.

Attualmente il progetto del kernel Linux richiede da 11 a 12 cifre esadecimali, mentre Git stesso ha bisogno di 10 cifre esadecimali per identificare in modo univoco gli oggetti che hanno, mentre molti progetti più piccoli potrebbero comunque andare bene con il valore predefinito di 7 cifre esadecimali. La taglia unica non si adatta a tutti i progetti.

Introdurre un meccanismo, in cui stimiamo il numero di oggetti nel repository alla prima richiesta per abbreviare un nome di oggetto con l'impostazione predefinita e creare un valore predefinito sano per il repository. Sulla base dell'aspettativa che si verifichino collisioni in un repository con 2^(2N)oggetti quando si utilizzano nomi di oggetti abbreviati in primi N bit, utilizzare un numero sufficiente di cifre esadecimali per coprire il numero di oggetti nel repository.
Ogni hexdigit (4 bit) che aggiungiamo al nome abbreviato ci consente di avere quattro volte (2 bit) quanti più oggetti nel repository.

Vedi commit e6c587c (01 ott 2016) di Linus Torvalds ( torvalds) .
Vedi commit 7b5b772 , commit 65acfea (01 ott 2016) di Junio ​​C Hamano ( gitster) .
(Unito da Junio ​​C Hamano - gitster- in commit bb188d0 , 03 ott 2016)

Quella nuova proprietà (indovinando un valore predefinito ragionevole per il valore abbreviato SHA1) ha un effetto diretto su come Git calcola il proprio numero di versione per il rilascio .


3
Questa risposta fornisce un modo per verificare quale sia l'hash "abbreviato" più lungo in un singolo repository: stackoverflow.com/a/32406103/1858225
Kyle Strand,

1
Si noti che core.abbrevLengthè stato rinominato in core.abbrev.
marco.m,

@ marco.m Grazie. Ho modificato la risposta di conseguenza. E mi sono collegato al commit Git per il quale registra quel nuovo nome core.abbrev.
VonC,

Aggiungerò solo a questo che puoi eseguire git rev-parse --short=10 --verify HEADper generare 10 caratteri. Stavamo usandogit log -1 --format=%h , ma questo ha generato solo 7 caratteri e abbiamo avuto una collisione.
grayaii,

Grazie per la spiegazione, i documenti ( git-scm.com/docs/git-rev-parse ) sono obsoleti .
André Werlang,

36

Questo è noto come problema del compleanno.

Per probabilità inferiori a 1/2 la probabilità di una collisione può essere approssimata come

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

Dove n è il numero di elementi e m è il numero di possibilità per ciascun oggetto.

Il numero di possibilità per una stringa esadecimale è 16 c dove c è il numero di caratteri.

Quindi per 8 personaggi e 30K si impegna

30K ~ = 2 15

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

Aumentandolo a 12 caratteri

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


Esattamente la domanda che stavo cercando di risolvere, grazie! Anche la tabella delle probabilità collegata nella risposta di @ Messa è utile.
Kyle Chadha,

eccellente, non abbiamo bisogno di nient'altro ma più di questo,
spiegalo

13

A questa domanda è stata data una risposta, ma per chiunque cerchi la matematica dietro - si chiama problema di compleanno ( Wikipedia ).

Si tratta della probabilità di avere 2 (o più) persone di un gruppo di N persone per avere un compleanno lo stesso giorno dell'anno. Il che è analogo alla probabilità di 2 (o più) commit git dal repository con N commit in totale con lo stesso prefisso hash di lunghezza X.

Guarda la tabella delle probabilità . Ad esempio, per la stringa esadecimale hash di lunghezza 8 la probabilità di avere una collisione raggiunge l'1% quando il repository ha solo circa 9300 elementi (commit git). Per 110.000 commit la probabilità è del 75%. Ma se hai una stringa esadecimale con hash di lunghezza 12, la probabilità di collisione in 100.000 commit è inferiore allo 0,1%.


2

La versione 2.11 di Git (o forse 2.12?) Conterrà una funzione che adatta il numero di caratteri usati negli identificatori brevi (ad es. git log --oneline) Alle dimensioni del progetto. Una volta che usi questa versione di Git, la risposta alla tua domanda può essere "scegli la lunghezza che ti dà Git git log --oneline, è abbastanza sicuro".

Per maggiori dettagli, vedi Modifica del valore predefinito per “core.abbrev”? discussione in Git Rev News edition 20 e impegno bb188d00f7 .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.