Ist das halbgeheime leere Baumobjekt von git zuverlässig und warum gibt es keinen symbolischen Namen dafür?

Lesezeit: 10 Minuten

Ist das halbgeheime leere Baumobjekt von git zuverlassig und warum
Torek

Git hat einen bekannten, oder zumindest irgendwie bekannten, leeren Baum, dessen SHA1 ist:

4b825dc642cb6eb9a060e54bf8d69288fbee4904

(Sie können dies in jedem Repo sehen, sogar in einem neu erstellten, mit git cat-file -t und git cat-file -p). [Edit made in 2020: the SHA-256 empty tree hash ID is:

6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321

as VonC mentions in his answer. My question was apparently about 8 years early. 😀]

Wenn Sie hart arbeiten und sehr vorsichtig sind, können Sie diesen leeren Baum verwenden, um ein Verzeichnis zu speichern, das keine Dateien enthält (siehe Antwort auf Wie füge ich einem Git-Repository ein leeres Verzeichnis hinzu), obwohl dies keine wirklich gute Idee ist.

Es ist nützlicher als ein Argument zu git diff-treewas einer der Sample-Hooks tut.

Was ich mich frage ist,

  1. wie zuverlässig ist das – dh wird eine zukünftige Version von git kein nummeriertes git-Objekt haben? 4b825dc642cb6eb9a060e54bf8d69288fbee4904?
  2. Warum gibt es keinen symbolischen Namen für den leeren Baum (oder gibt es einen?).

(Eine schnelle und schmutzige Möglichkeit, einen symbolischen Namen zu erstellen, besteht darin, den SHA1 einzufügen, z. .git/Nulltree. Leider müssen Sie dies für jedes Repo tun. Es scheint besser zu sein, die magische Zahl einfach in Skripte usw. einzufügen. Ich habe nur eine allgemeine Abneigung gegen magische Zahlen.)

  • nur um sich an den Hash zu erinnern 😉 use SHA1(“tree 0\0”) = 4b825dc642cb6eb9a060e54bf8d69288fbee4904 (\0 ist NUL-Zeichen)

    – Thomas

    3. Februar 2016 um 23:20 Uhr


  • @Thomas: die git hash-object -t tree /dev/null -Methode (aus der Antwort von VonC unten) hat den Vorteil, dass SHA-1 nicht fest codiert ist, falls eine zukünftige Version von Git beispielsweise auf SHA-2 umschaltet. (Ich werde nicht versuchen vorherzusagen, wann das passieren könnte. 🙂 Es wäre einfacher, Mercurial auf SHA-2 umzustellen, da sie dafür Platz gelassen haben.)

    – Torek

    3. Februar 2016 um 23:53 Uhr

  • da hast du natürlich recht aber es ist ein gutes stück “nutzloses wissen” und vielleicht hilft es auf jeden fall noch jemandem weiter?!

    – Thomas

    4. Februar 2016 um 16:40 Uhr


  • @Thomas: sieht so aus, als ob die Umstellung des Hash-Algorithmus stattfinden könnte früher als erwartet. 🙂

    – Torek

    26. März 2017 um 4:53 Uhr

  • In acht nehmen: 6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321 wird bald neu sein 4b825dc642cb6eb9a060e54bf8d69288fbee4904 leerer Baumhasch. Siehe meine bearbeitete Antwort unten.

    – VonC

    23. Januar 2020 um 8:20 Uhr

Ist das halbgeheime leere Baumobjekt von git zuverlassig und warum
VonC

Dieser Faden erwähnt:

Wenn Sie sich nicht an den leeren Baum sha1 erinnern, können Sie ihn jederzeit ableiten mit:

git hash-object -t tree /dev/null

Oder, wie Ciro Santilli in den Kommentaren vorschlägt:

printf '' | git hash-object --stdin -t tree

Oder als hier gesehenvon Colin Schimmelfing:

git hash-object -t tree --stdin < /dev/null

Daher denke ich, dass es sicherer ist, eine Variable mit dem Ergebnis dieses Befehls als Ihren leeren sha1-Baum zu definieren (anstatt sich auf einen “bekannten Wert” zu verlassen).

Hinweis: Git 2.25.1 (Feb. 2020) schlägt vor begehen 9c8a294:

empty_tree=$(git mktree </dev/null)
# Windows:
git mktree <NUL

Und ergänzt:

Als historische Anmerkung ist die Funktion jetzt bekannt als repo_read_object_file() wurde der leere Baum eingelernt 346245a1bb (“Das leere Baumobjekt fest codieren”, 13.02.2008, Git v1.5.5-rc0 — verschmelzen) und die Funktion, die jetzt bekannt ist als oid_object_info() wurde der leere Baum eingelernt c4d9986f5f (“sha1_object_info: untersuchen cached_object store too”, 07.02.2011, Git v1.7.4.1).


Beachten Sie, dass SHA1 auf einigen GitHub-Repositorys auftaucht, wenn der Autor möchte, dass sein erster Commit leer ist (siehe Blogbeitrag „Wie ich meine Git-Repositorys initialisiere“):

$ GIT_AUTHOR_DATE="Thu, 01 Jan 1970 00:00:00 +0000" GIT_COMMITTER_DATE="Thu, 01 Jan 1970 00:00:00 +0000" git commit --allow-empty -m 'Initial commit'

Werde dir geben:

Leerer Baum SHA1

(Siehe den Baum SHA1?)

Du kannst sogar deinen bestehenden Verlauf auf diesen leeren Commit umbasieren (siehe „git: wie fügt man einen Commit als ersten ein und verschiebt alle anderen?“)

In beiden Fällen verlassen Sie sich nicht auf den genauen SHA1-Wert dieses leeren Baums.
Sie folgen einfach a bewährte Methode, Ihr Repo mit einem ersten leeren Commit zu initialisieren.


Das zu tun:

git init my_new_repo
cd my_new_repo
git config user.name username
git config user.email email@com

git commit --allow-empty -m "initial empty commit"

Dadurch wird ein Commit mit einem SHA1 generiert, der für Ihr Repo, Ihren Benutzernamen, Ihre E-Mail-Adresse und Ihr Erstellungsdatum spezifisch ist (was bedeutet, dass der SHA1 des Commit selbst jedes Mal anders ist).
Aber der Baum, auf den dieser Commit verweist, wird es sein 4b825dc642cb6eb9a060e54bf8d69288fbee4904der leere Baum SHA1.

git log --pretty=raw

commit 9ed4ff9ac204f20f826ddacc3f85ef7186d6cc14
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904      <====
author VonC <[email protected]> 1381232247 +0200
committer VonC <[email protected]> 1381232247 +0200

    initial empty commit

So zeigen Sie nur den Baum eines Commits an (zeigen Sie den Commit-Baum SHA1 an):

git show --pretty=format:%T 9ed4ff9ac204f20f826ddacc3f85ef7186d6cc14
4b825dc642cb6eb9a060e54bf8d69288fbee4904

Wenn dieses Commit, das auf einen leeren Baum verweist, tatsächlich von Ihnen stammt Erste commit, können Sie diesen leeren Baum SHA1 anzeigen mit:

git log --pretty=format:%h --reverse | head -1 | xargs git show --pretty=format:%T
4b825dc642cb6eb9a060e54bf8d69288fbee4904

(und das funktioniert sogar unter Windows, mit Gnu unter Windows Befehle)


Wie unten kommentiert, mit git diff <commit> HEADdies zeigt alle Ihre Dateien im aktuellen Zweig HEAD:

git diff --name-only 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD

Hinweis: Dieser leere Baumwert ist formal definiert in cache.h.

#define EMPTY_TREE_SHA1_HEX \
    "4b825dc642cb6eb9a060e54bf8d69288fbee4904"

Seit Git 2.16 (Q1 2018) wird es in einer Struktur verwendet, die nicht mehr (nur) an SHA1 gebunden ist, wie in zu sehen ist eb0ccfd übergeben:

Schalten Sie leere Baum- und Blob-Lookups um, um Hash-Abstraktion zu verwenden

Wechseln Sie die Verwendung von empty_tree_oid und empty_blob_oid die zu verwenden current_hash Abstraktion, die den aktuell verwendeten Hash-Algorithmus darstellt.

Weitere Informationen finden Sie unter „Warum verwendet Git kein moderneres SHA?“: Das ist es SHA-2seit Git 2.19 (Q3 2018)


Mit Git 2.25 (Q1 2020) bereiten sich Tests auf a SHA-2-Übergangund betrifft den leeren Baum.

Sehen fa26d5e übergeben, Commit cf02be8, Commit 38ee26b, Commit 37ab8eb, 0370b35 begehen, Commit 0253e12, Commit 45e2ef2, übertrage 79b0edc, Commit 840624f, Commit 32a6707, 440bf91 begehen, 0b408ca übernehmen, Commit 2eabd38 (28. Okt. 2019) und übertrage 1bcef51, ecde49b begehen (05.10.2019) von Brian m. Carlson (bk2204).
(Zusammengeführt von Junio ​​C. Hamano — gitster in Commit 28014c110.11.2019)

t/oid-info: Leeren Baum und leere Blob-Werte hinzufügen

Unterzeichnet von: Brian M. Carlson

Die Testsuite wird schließlich lernen, wie sie mit einem anderen Algorithmus als SHA-1 ausgeführt wird. Bereiten Sie sich darauf vor test_oid Funktionsfamilie, wie man die leeren Blob- und leeren Baumwerte nachschlägt, damit sie verwendet werden können.

Damit t/oid-info/hash-info beinhaltet jetzt:

rawsz sha1:20
rawsz sha256:32

hexsz sha1:40
hexsz sha256:64

zero sha1:0000000000000000000000000000000000000000
zero sha256:0000000000000000000000000000000000000000000000000000000000000000

algo sha1:sha1
algo sha256:sha256

empty_blob sha1:e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
empty_blob sha256:473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813

empty_tree sha1:4b825dc642cb6eb9a060e54bf8d69288fbee4904
empty_tree sha256:6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321

Der SHA2 “6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321” ist das neue SHA1 “4b825dc642cb6eb9a060e54bf8d69288fbee4904„Leerer Baum.

  • @torek: Ich habe einige Beispiele rund um die erste Best Practice für leere Commit hinzugefügt, um diesen leeren Baum SHA1 zu veranschaulichen.

    – VonC

    19. März 2012 um 7:53 Uhr

  • Nun, eines der Ziele ist es, den Hash des “leeren Baums” als Argument zu verwenden git diff-tree in einigen Skripten, die ich schreibe. Es gibt keine Garantie dafür, dass das Repo einen anfänglich leeren Commit enthält. Ich frage mich also nur, ob diese Skripte eines Tages kaputt gehen könnten.

    – Torek

    19. März 2012 um 20:57 Uhr

  • Wenn Sie bestehen -w zu git hash-objecterstellt es das Objekt in dem Repository, für das es ausgeführt wird, und das würde den leeren Baum in dem Repository, für das Sie ausgeführt werden, neu erstellen, falls es in Zukunft jemals verschwinden würde.

    – Java-Assistent

    3. Januar 2014 um 7:49 Uhr

  • Wenn Sie vor dem ersten Commit mit rebase vorgehen möchten, können Sie git rebase –root verwenden

    – GergelyPolonkai

    11. November 2014 um 10:37 Uhr

  • Oder wenn Sie die Magie von Pfeifen der Magie von Pfeifen vorziehen /dev/null: printf '' | git hash-object --stdin -t tree 🙂

    – Ciro Santilli Путлер Капут 六四事

    14. Dezember 2014 um 8:17 Uhr

Ist das halbgeheime leere Baumobjekt von git zuverlassig und warum
Oleg

Hier ist die Antwort, wie man einen leeren Baum-Commit erstellt, auch wenn das Repository noch nicht leer ist. https://stackoverflow.com/a/14623458/9361507

Aber ich ziehe es vor, dass “leer” ein Tag ist, aber kein Zweig. Einfacher Weg ist:

git tag empty $(git hash-object -t tree /dev/null)

Denn Tag kann ohne Commit direkt auf Tree-ish verweisen. Um nun alle Dateien im Arbeitsbaum zu erhalten:

git diff --name-only empty

Oder das gleiche mit stat:

git diff --stat empty

Alle Dateien als Diff:

git diff empty

Überprüfen Sie Leerzeichen in allen Dateien:

git diff --check empty

  • …aber die Verwendung der magischen Zahl in Ihrer Tag-Erstellung ist nur, die Frage unter den Teppich zu kehren (nicht mit der magischen Zahl SHA-1)

    – Romain Waleri

    1. März 2019 um 13:46 Uhr

  • Nicht wahr. Ich habe Tag verwendet, um auf das baumartige Objekt zu verweisen. Mittlerweile ist dieser Tree-ish durch SHA-1 definiert, in Zukunft kann er beispielsweise auf SHA-256 geändert werden und so weiter (mit Repository-Migration). Aber Tag wird das gleiche sein. 🙂 Das Hauptmerkmal eines Tags ist es, auf das Objekt zu zeigen. Ein Tag kann intern SHA-1 oder etwas anderes verwenden, es handelt sich nur um Git-Interna.

    – Oleg

    1. März 2019 um 15:41 Uhr


  • Ich verstehe das. Aber wenn Sie (oder jemand, der dies liest) (oder a Skriptnoch schlimmer) versucht, es (Ihre erste Zeile) zu einem späteren Zeitpunkt anzuwenden, könnte dies bei einem neuen Hash-Algorithmus fehlschlagen, bei dem das Ersetzen Ihrer ersten Zeile durch einen ausgeführten Ausdruck (der diesen Hash erzeugt) weiterhin erfolgreich wäre.

    – Romain Waleri

    1. März 2019 um 15:49 Uhr


  • Wenn Sie dies mit einer der Methoden zum automatischen Generieren des leeren Baumhashs kombinieren, können Sie dies zukunftssicher machen (wie @RomainValeri vorschlägt). Wenn es aber nach mir ginge, git rev-parse würde neue Flags oder Schlüsselwörter oder etwas in dieser Richtung haben, um (a) den leeren Baum-Hash und (b) den Null-Commit-Hash zu erzeugen. Beides wäre in Skripten nützlich und würde vor den vorgeschlagenen SHA-256-Änderungen schützen.

    – Torek

    1. März 2019 um 16:24 Uhr

  • Okay, geändert. Aber das wird nicht “ein einfachster Weg” sein. 🙂

    – Oleg

    1. März 2019 um 16:49 Uhr

Ich habe einen Blogbeitrag mit zwei verschiedenen Möglichkeiten geschrieben, den Hash zu finden: http://colinschimmelfing.com/blog/gits-empty-tree/

Wenn es sich aus irgendeinem Grund jemals ändern sollte, können Sie die beiden folgenden Methoden verwenden, um es zu finden. Aber, Ich würde mich ziemlich sicher fühlen, wenn ich den Hash in .bashrc-Aliassen usw. verwenden würde, und ich glaube nicht, dass sich das in absehbarer Zeit ändern wird. Zumindest wäre es wahrscheinlich eine Hauptversion von Git.

Die zwei Wege sind:

  1. Die Antwort oben: git hash-object -t tree --stdin < /dev/null
  2. Einfach ein leeres Repo initiieren und dann ausführen git write-tree in diesem neuen Repo – der Hash wird von git write-tree ausgegeben.

  • Führen Sie den Befehl mit aus –-stdin gibt mir fatal: Cannot open '–-stdin': No such file or directory mit Git 2.7.2. Läuft aber ohne --stdin wie in der Antwort von VonC gibt den Hash-Wert

    – sig

    13. Juni 2016 um 10:26 Uhr

  • Diese Antwort ist nicht sehr nützlich, da der Blog-Post tot ist. Daher stimmen wir diesen Antworten auf SO im Allgemeinen nicht zu.

    – Philip Weißhaus

    23. August 2017 um 12:57 Uhr

  • @PhilipWhitehouse, der Blog-Beitrag ist nicht tot, aber auf jeden Fall habe ich die beiden Möglichkeiten in meine Antwort aufgenommen – ich stimme zu, dass es ohne die Einbeziehung dieser beiden Möglichkeiten keine gute Antwort wäre.

    – schimm

    8. September 2017 um 16:42 Uhr

986390cookie-checkIst das halbgeheime leere Baumobjekt von git zuverlässig und warum gibt es keinen symbolischen Namen dafür?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy