Wie viel von einem Git sha wird * im Allgemeinen * als notwendig angesehen, um eine Änderung in einer bestimmten Codebasis eindeutig zu identifizieren?

211

Wenn Sie beispielsweise eine Verzeichnisstruktur erstellen möchten, in der ein Verzeichnis für ein Commit in einem Git-Repository benannt ist, und Sie möchten, dass es kurz genug ist, damit Ihre Augen nicht bluten, aber lang genug, dass die Wahrscheinlichkeit einer Kollision besteht wäre vernachlässigbar, wie viel von der SHA-Teilzeichenfolge wird im Allgemeinen benötigt?

Angenommen, ich möchte diese Änderung eindeutig identifizieren: https://github.com/wycats/handlebars.js/commit/e62999f9ece7d9218b9768a908f8df9c11d7e920

Ich kann nur die ersten vier Zeichen verwenden: https://github.com/wycats/handlebars.js/commit/e629

Aber ich denke, das wäre riskant. Wenn Sie jedoch eine Codebasis annehmen, die über ein paar Jahre beispielsweise 30.000 Änderungen aufweisen könnte, wie hoch ist die Wahrscheinlichkeit einer Kollision, wenn ich 8 Zeichen verwende? 12? Gibt es eine Zahl, die für solche Dinge allgemein als akzeptabel angesehen wird?

Jun-Dai Bates-Kobashigawa
quelle
Siehe auch
jub0bs

Antworten:

230

Diese Frage wird tatsächlich in Kapitel 7 des Pro Git-Buches beantwortet :

Im Allgemeinen sind acht bis zehn Zeichen mehr als genug, um innerhalb eines Projekts eindeutig zu sein. Eines der größten Git-Projekte, der Linux-Kernel, benötigt 12 von 40 möglichen Zeichen, um einzigartig zu bleiben.

7 Stellen ist die Git-Standardeinstellung für eine kurze SHA, daher ist dies für die meisten Projekte in Ordnung. Das Kernel-Team hat, wie bereits erwähnt, seine Anzahl mehrmals erhöht, da es mehrere hunderttausend Commits hat. Für Ihre ~ 30.000 Commits sollten also 8 oder 10 Ziffern vollkommen in Ordnung sein.

Nevik Rehnel
quelle
37
Beachten Sie auch, dass dies gitziemlich klug ist. Sie können die Abkürzung kurz setzen, z. B. 4, und git4 Ziffern für so viele Hashes wie möglich verwenden.
Wechseln
31
Beachten Sie jedoch auch, dass dies natürlich nur für den Moment gilt, in dem Git den SHA druckt. Wenn Sie abgekürzte SHAs "speichern" (z. B. in Protokollen, E-Mails, IMs usw.) und sie später verwenden, um auf Commits zu verweisen, sind sie möglicherweise nicht mehr eindeutig! Während es für normale Längen wie 7-12 Zeichen sicherlich unwahrscheinlich ist, wenn Sie auf 4 oder 5 heruntergehen und ein paar zehntausend neue Objekte (oder Commits, je nach Kontext) erhalten, könnte dies tatsächlich zurückkommen, um Sie zu beißen.
Nevik Rehnel
140

Hinweis: Sie können git rev-parse --shortnach dem kürzesten und dennoch einzigartigen SHA1 fragen .
Siehe " Git Get Short Hash von regulärem Hash "

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

Wie Sie in meinem Beispiel sehen können, hat der SHA1 eine Länge von 5, auch wenn ich eine Länge von 4 angegeben habe.


Für große Repos reicht 7 seit 2010 nicht mehr aus und Commit dce9648 von Linus Torvalds selbst (git 1.7.4.4, Okt 2010):

Der Standardwert von 7 stammt aus einer ziemlich frühen Phase der Git-Entwicklung, als sieben Hex-Ziffern viel waren (er deckt mehr als 250 Millionen Hash-Werte ab).
Damals dachte ich, dass 65.000 Revisionen eine Menge waren (es war das, was wir in BK treffen wollten), und jede Revision besteht aus ungefähr 5-10 neuen Objekten, also war eine Million Objekte eine große Zahl.

(BK = BitKeeper)

Heutzutage ist der Kernel nicht einmal das größte Git-Projekt, und selbst der Kernel hat ungefähr 220.000 Revisionen ( viel größer als der BK-Baum jemals war) und wir nähern uns zwei Millionen Objekten.
Zu diesem Zeitpunkt sind sieben hexadezimale Ziffern für viele von ihnen immer noch eindeutig. Wenn es sich jedoch um einen Unterschied von nur zwei Größenordnungen zwischen der Anzahl der Objekte und der Hash-Größe handelt, kommt es zu Kollisionen bei abgeschnittenen Hash-Werten.
Es ist nicht mehr annähernd unrealistisch - es passiert die ganze Zeit.

Wir sollten sowohl die unrealistisch kleine Standardabkürzung erhöhen als auch eine Möglichkeit für Benutzer hinzufügen, ihre eigenen Standardabkürzungen pro Projekt in der Git-Konfigurationsdatei festzulegen .

core.abbrev

Legen Sie die Länge fest, mit der Objektnamen abgekürzt werden.
Wenn nicht angegeben, werden viele Befehle auf 7 Hexdigits abgekürzt, was möglicherweise nicht ausreicht, damit abgekürzte Objektnamen ausreichend lange eindeutig bleiben.

environment.c::

int minimum_abbrev = 4, default_abbrev = 7;

Hinweis: Wie unten von marco.m kommentiert , core.abbrevLengthwurde in umbenanntcore.abbrev demselben Git 1.7.4.4 in Commit a71f09f umbenannt

Umbenennen core.abbrevlengthzurück incore.abbrev

Es entspricht --abbrev=$n Befehlszeilenoption.


In neuerer Zeit hinzugefügt Linus in e6c587c begehen (für Git 2.11, Q4 2016):
(wie in erwähnt Matthieu Moy ‚s Antwort )

In relativ frühen Tagen haben wir uns irgendwie dazu entschlossen, Objektnamen auf 7 Hexadezimalzahlen abzukürzen, aber mit dem Wachstum von Projekten wird es immer wahrscheinlicher, dass so kurze Objektnamen, die in früheren Tagen erstellt und in den Protokollnachrichten aufgezeichnet wurden, nicht mehr eindeutig sind.

Derzeit benötigt das Linux-Kernel-Projekt 11 bis 12 Hexdigits, während Git selbst 10 Hexdigits benötigt, um die Objekte eindeutig zu identifizieren, während viele kleinere Projekte mit dem ursprünglichen 7-Hexdigit-Standard möglicherweise noch in Ordnung sind. Einheitsgröße passt nicht für alle Projekte.

Führen Sie einen Mechanismus ein, bei dem wir die Anzahl der Objekte im Repository bei der ersten Anforderung schätzen, einen Objektnamen mit der Standardeinstellung abzukürzen und einen vernünftigen Standard für das Repository zu erstellen. 2^(2N)Verwenden Sie basierend auf der Erwartung, dass bei Verwendung von Objektnamen, die auf die ersten N Bits verkürzt sind, eine Kollision in einem Repository mit Objekten sehen, eine ausreichende Anzahl von Hexdigits, um die Anzahl der Objekte im Repository abzudecken.
Jedes Hexdigit (4 Bit), das wir dem verkürzten Namen hinzufügen, ermöglicht es uns, viermal (2 Bit) so viele Objekte im Repository zu haben.

Siehe Commit e6c587c (01. Oktober 2016) von Linus Torvalds ( torvalds) .
Siehe Commit 7b5b772 , Commit 65acfea (01. Oktober 2016) von Junio ​​C Hamano ( gitster) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit bb188d0 , 03. Oktober 2016)

Diese neue Eigenschaft (die einen vernünftigen Standard für den Abkürzungswert von SHA1 errät) hat direkten Einfluss darauf, wie Git seine eigene Versionsnummer für die Veröffentlichung berechnet .

VonC
quelle
3
Diese Antwort bietet eine Möglichkeit, den längsten "verkürzten" Hash in einem einzelnen Repository zu überprüfen: stackoverflow.com/a/32406103/1858225
Kyle Strand
1
Beachten Sie, dass core.abbrevLengthin umbenannt wurde core.abbrev.
marco.m
@ marco.m Danke. Ich habe die Antwort entsprechend geändert. Und ich habe auf das Git-Commit verlinkt, für das dieser neue Name aufgezeichnet wird core.abbrev.
VonC
Ich füge nur hinzu, dass Sie ausführen können git rev-parse --short=10 --verify HEAD, um 10 Zeichen zu generieren. Wir haben verwendet git log -1 --format=%h, aber das hat nur 7 Zeichen generiert und wir haben eine Kollision bekommen.
Grayaii
Vielen Dank für die Erklärung, die Dokumente ( git-scm.com/docs/git-rev-parse ) sind veraltet.
André Werlang
36

Dies ist als Geburtstagsproblem bekannt.

Für Wahrscheinlichkeiten von weniger als 1/2 kann die Wahrscheinlichkeit einer Kollision als angenähert werden

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

Dabei ist n die Anzahl der Elemente und m die Anzahl der Möglichkeiten für jedes Element.

Die Anzahl der Möglichkeiten für eine Hex-Zeichenfolge beträgt 16 c wobei c die Anzahl der Zeichen ist.

Also für 8 Zeichen und 30K Commits

30K ~ = 2 15

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

Erhöht es auf 12 Zeichen

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

Plugwash
quelle
Genau die Frage, die ich zu lösen versuchte, danke! Hilfreich ist auch die in der Antwort von @ Messa verknüpfte Wahrscheinlichkeitstabelle.
Kyle Chadha
ausgezeichnet, wir brauchen nichts anderes als mehr davon, erkläre es nicht nur was es ist, sondern auch wie es kommt ...
workplaylifecycle
13

Diese Frage wurde beantwortet, aber für alle, die nach der Mathematik dahinter suchen - sie heißt Geburtstagsproblem ( Wikipedia ).

Es geht um die Wahrscheinlichkeit, dass 2 (oder mehr) Personen aus einer Gruppe von N Personen am selben Tag im Jahr Geburtstag haben. Dies ist analog zu wahrscheinlich 2 (oder mehr) Git-Commits aus dem Repository mit insgesamt N Commits mit demselben Hash-Präfix der Länge X.

Schauen Sie sich die Wahrscheinlichkeitstabelle an . Beispielsweise erreicht für eine Hash-Hex-Zeichenfolge der Länge 8 die Wahrscheinlichkeit einer Kollision 1%, wenn das Repository nur etwa 9300 Elemente enthält (Git-Commits). Für 110 000 Commits beträgt die Wahrscheinlichkeit 75%. Wenn Sie jedoch eine Hash-Hex-Zeichenfolge der Länge 12 haben, liegt die Wahrscheinlichkeit einer Kollision bei 100 000 Commits unter 0,1%.

Messa
quelle
2

Git Version 2.11 (oder vielleicht 2.12?) Enthält eine Funktion, die die Anzahl der in kurzen Bezeichnern verwendeten Zeichen (z. B. git log --oneline) an die Größe des Projekts anpasst . Sobald Sie eine solche Version von Git verwenden, kann die Antwort auf Ihre Frage lauten: "Wählen Sie die Länge aus, mit der Git Ihnen zur Verfügung steht."git log --oneline , es ist sicher genug".

Weitere Informationen finden Sie unter Ändern der Standardeinstellung für "core.abbrev". Diskussion in Git Rev News Edition 20 und Commit bb188d00f7 .

Matthieu Moy
quelle