Git
Chapters ▾ 2nd Edition

10.7 Git Interna - Wartung und Datenwiederherstellung

Wartung und Datenwiederherstellung

Möglicherweise musst du hin und wieder Bereinigungen durchführen. Bspw. musst du ein Repository komprimieren, ein importiertes Repository bereinigen oder verlorene Arbeit wiederherstellen. In diesem Abschnitt werden einige dieser Szenarien behandelt.

Wartung

Gelegentlich führt Git automatisch einen Befehl namens „auto gc“ aus. Meistens macht dieser Befehl gar nichts. Wenn sich jedoch zu viele lose Objekte (Objekte, die nicht in einem Packfile enthalten sind) oder zu viele Packfiles gibt, startet Git einen vollständigen git gc Befehl. Das „gc“ steht für Garbage Collect und der Befehl führt eine Reihe von Aktionen aus: Er sammelt alle losen Objekte und legt sie in Packfiles ab. Er fasst Packfiles zu einem großen Packfile zusammen. Außerdem entfernt er Objekte, die nicht von einem Commit erreichbar und ein paar Monate alt sind.

Du kannst auto gc folgendermaßen manuell ausführen:

$ git gc --auto

Auch dies tut im Allgemeinen nichts. Du musst ungefähr 7.000 lose Objekte oder mehr als 50 Packfiles haben, damit Git einen echten gc-Befehl ausführt. Du kannst diese Grenzwerte mit den Konfigurationseinstellungen gc.auto und gc.autopacklimit ändern.

Die andere Aktion, die gc durchführt, ist deine Referenzen in eine einzige Datei zu packen. Angenommen, dein Repository enthält die folgenden Branches und Tags:

$ find .git/refs -type f
.git/refs/heads/experiment
.git/refs/heads/master
.git/refs/tags/v1.0
.git/refs/tags/v1.1

Wenn du git gc ausführst, befinden sich diese Dateien nicht mehr im Verzeichnis refs. Git verschiebt sie aus Gründen der Effizienz in eine Datei mit dem Namen .git/packed-refs, die so aussieht:

$ cat .git/packed-refs
# pack-refs with: peeled fully-peeled
cac0cab538b970a37ea1e769cbbde608743bc96d refs/heads/experiment
ab1afef80fac8e34258ff41fc1b867c702daa24b refs/heads/master
cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0
9585191f37f7b0fb9444f35a9bf50de191beadc2 refs/tags/v1.1
^1a410efbd13591db07496601ebc7a059dd55cfe9

Wenn du eine Referenz aktualisierst, bearbeitet Git diese Datei nicht, sondern schreibt eine neue Datei in refs/heads. Um das passende SHA-1 für eine angegebene Referenz zu erhalten, prüft Git diese Referenz im refs Verzeichnis und prüft dann die packed-refs Datei als Fallback. Wenn du jedoch keine Referenz im refs Verzeichnis finden kannst, befindet sich diese wahrscheinlich in deiner packed-refs Datei.

Beachte die letzte Zeile der Datei, die mit einem ^ beginnt. Dies bedeutet, dass das darüber liegende Tag ein annotiertes Tag ist und dass diese Zeile das Commit ist, auf das das annotierte Tag verweist.

Datenwiederherstellung

Es wird der Punkt auf deiner Git-Reise kommen, an dem du versehentlich einen oder mehrere Commits verlierst. Im Allgemeinen geschieht dies, weil du einen Branch mittels force Option löschst und es sich herausstellt, dass du den Branch doch noch benötigt hast. Oder aber es passiert, dass du einen Branch hart zurückgesetzt hast und noch benötigte Commits verworfen hast. Was kannst du tun, um deine Commits zurückzuerhalten?

In diesem Beispiel wird der master Branch in deinem Test-Repository auf einen älteren Commit zurückgesetzt und die verlorenen Commits wiederhergestellt. Lass uns zunächst überprüfen, wo sich dein Repository zu diesem Zeitpunkt befindet:

$ git log --pretty=oneline
ab1afef80fac8e34258ff41fc1b867c702daa24b Modify repo.rb a bit
484a59275031909e19aadb7c92262719cfcdf19a Create repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit

Verschiebe nun den 'master'-Branch zurück zum mittleren Commit:

$ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9
HEAD is now at 1a410ef Third commit
$ git log --pretty=oneline
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit

Du hast die beiden obersten Commits verloren. Du hast jetzt keinen Branch, von dem aus diese Commits erreichbar ist. Du musst das letzte Commit-SHA-1 finden und anschließend einen Branch hinzufügen, der darauf verweist. Der Trick ist, das letzte Commit SHA-1 zu finden. Leider ist es nicht so, als hättest du es auswendig gelernt, oder?

Oft ist der schnellste Weg die Nutzung eines Tools namens git reflog. Während du arbeitest, zeichnet Git lautlos im Hintergrund auf, was dein HEAD ist und worauf es zeigt. Jedes Mal, wenn du Branches commitest oder änderst, wird das Reflog aktualisiert. Das reflog wird auch durch den Befehl git update-ref aktualisiert. Dies ist ein weiterer Grund, warum du diesen Befehl verwenden solltest, anstatt nur den SHA-1-Wert in deine ref-Dateien zu schreiben, wie in Git Referenzen beschrieben. Du kannst jederzeit sehen, wo du warst, indem du git reflog ausführst:

$ git reflog
1a410ef HEAD@{0}: reset: moving to 1a410ef
ab1afef HEAD@{1}: commit: Modify repo.rb a bit
484a592 HEAD@{2}: commit: Create repo.rb

Hier sehen wir die beiden Commits, die wir ausgecheckt haben, jedoch gibt es hier nicht viele Informationen. Um die gleichen Informationen auf eine viel nützlichere Weise anzuzeigen, können wir git log -g ausführen, wodurch du eine normale Logausgabe für dein Reflog erhältst.

$ git log -g
commit 1a410efbd13591db07496601ebc7a059dd55cfe9
Reflog: HEAD@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri May 22 18:22:37 2009 -0700

		Third commit

commit ab1afef80fac8e34258ff41fc1b867c702daa24b
Reflog: HEAD@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri May 22 18:15:24 2009 -0700

       Modify repo.rb a bit

Es sieht so aus, als ob du das unterste Commit verloren hast. Du kannst es also wiederherstellen, indem du bei diesem Commit einen neuen Branch erstellst. Beispielsweise kannst du einen Branch mit dem Namen recover-branch bei diesem Commit (ab1afef) starten:

$ git branch recover-branch ab1afef
$ git log --pretty=oneline recover-branch
ab1afef80fac8e34258ff41fc1b867c702daa24b Modify repo.rb a bit
484a59275031909e19aadb7c92262719cfcdf19a Create repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit

Sehr gut - jetzt hast du einen Branch namens recover-branch, in dem sich früher dein master Branch befand, wodurch die ersten beiden Commits wieder erreichbar sind. Angenommen, dein Verlust war aus irgendeinem Grund nicht im Reflog - du kannst dies simulieren, indem du recover-branch entfernst und das Reflog löschst. Jetzt sind die ersten beiden Commits nicht mehr erreichbar:

$ git branch -D recover-branch
$ rm -Rf .git/logs/

Da sich die Reflog-Daten im Verzeichnis .git/logs/ befinden, hast du praktisch kein Reflog. Wie kannst du dieses Commit zu diesem Zeitpunkt wiederherstellen? Eine Möglichkeit ist die Verwendung des Hilfsprogramms git fsck, mit dem deine Datenbank auf Integrität überprüft wird. Wenn du es mit der Option --full ausführst, werden alle Objekte angezeigt, auf die kein anderes Objekt zeigt:

$ git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (18/18), done.
dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4
dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b
dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9
dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293

In diesem Fall kannst du deinen fehlenden Commit nach dem String „Dangling Commit“ sehen. Du kannst es auf die gleiche Weise wiederherstellen, indem du einen Branch hinzufügst, der auf diesen SHA-1 verweist.

Objekte löschen

Es gibt viele großartige Dinge an Git. Eine Funktion, die jedoch Probleme verursachen kann, ist die Tatsache, dass ein Git-Klon den gesamten Verlauf des Projekts herunterlädt, einschließlich jeder Version jeder Datei. Dies ist in Ordnung, wenn das Ganze Quellcode ist. Git ist stark darin, diese Daten effizient zu komprimieren. Wenn jedoch zu einem beliebigen Zeitpunkt im Verlauf deines Projekts eine einzelne große Datei hinzugefügt wird, muss jeder Klon für alle Zeiten diese große Datei herunterladen, auch wenn sie beim nächsten Commit aus dem Projekt entfernt wurde. Weil sie von der Historie aus erreichbar ist, wird sie immer da sein.

Dies kann ein großes Problem sein, wenn du Subversion- oder Perforce-Repositorys nach Git konvertierst. Da du in diesen Systemen nicht den gesamten Verlauf herunterlädst, hat dieses Model des Hinzufügens nur wenige Konsequenzen. Wenn du einen Import von einem anderen System durchgeführt hast oder auf andere Weise feststellst, dass dein Repository viel größer ist, als es sein sollte, kannst du große Objekte folgendermaßen finden und entfernen.

Seie gewarnt: Diese Technik wirkt sich zerstörerisch auf deinen Commit-Verlauf aus. Es schreibt jedes Commitobjekt neu, seit dem frühesten Baum, den du ändern musst, um einen Verweis auf eine große Datei zu entfernen. Wenn du dies unmittelbar nach einem Import tust, bevor jemand damit begonnen hat, sich aufs Committen zu stützen, ist alles in Ordnung. Andernfalls musst du alle Mitwirkenden benachrichtigen, dass sie ihre Arbeit auf deinen neuen Commits rebasen müssen.

Zur Veranschaulichung füge deinem Test-Repository eine große Datei hinzu und entferne sie beim nächsten Commit. Anschließend suchst du sie und entfernst sie dauerhaft aus dem Repository. Füge deiner Historie zunächst ein großes Objekt hinzu:

$ curl -L https://www.kernel.org/pub/software/scm/git/git-2.1.0.tar.gz > git.tgz
$ git add git.tgz
$ git commit -m 'Add git tarball'
[master 7b30847] Add git tarball
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 git.tgz

Hoppla - du wolltest deinem Projekt keinen riesigen Tarball hinzufügen. Besser wäre, es loszuwerden:

$ git rm git.tgz
rm 'git.tgz'
$ git commit -m 'Oops - remove large tarball'
[master dadf725] Oops - remove large tarball
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 git.tgz

Wende nun gc auf deine Datenbank an und prüfe, wie viel Speicherplatz du verwendest:

$ git gc
Counting objects: 17, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (13/13), done.
Writing objects: 100% (17/17), done.
Total 17 (delta 1), reused 10 (delta 0)

Du kannst den Befehl count-objects ausführen, um schnell zu sehen, wie viel Speicherplatz du verwendest:

$ git count-objects -v
count: 7
size: 32
in-pack: 17
packs: 1
size-pack: 4868
prune-packable: 0
garbage: 0
size-garbage: 0

Der size-pack Eintrag gibt die Größe deiner Packdateien in Kilobyte an. Somit verwendest du fast 5 MB an Speicherplatz. Vor dem letzten Commit hast du einen Wert von ungefähr 2 KB belegt. Wenn du die Datei aus dem vorherigen Commit entfernst, wird sie offensichtlich nicht aus deinem Verlauf entfernt. Jedes Mal, wenn jemand dieses Repository klont, muss er 5 MB klonen, um dieses winzige Projekt zu erhalten, da du versehentlich eine große Datei hinzugefügt hast. Besser wir werden sie los.

Als erstes müssen wir sie finden. In diesem Fall weißt du bereits, um welche Datei es sich handelt. Angenommen, du weißt es nicht. Wie würdest du feststellen, welche Datei oder welche Dateien so viel Speicherplatz beanspruchen? Wenn du git gc ausführst, befinden sich alle Objekte in einer Packdatei. Du kannst die großen Objekte identifizieren, indem du einen anderen Installationsbefehl namens git verify-pack ausführst und die Ausgabe nach dem dritte Feld sortierst, das die Dateigröße ist. Du kannst es auch über den Befehl tail pipen, da du nur an den letzten, großen Dateien interessiert bist:

$ git verify-pack -v .git/objects/pack/pack-29…69.idx \
  | sort -k 3 -n \
  | tail -3
dadf7258d699da2c8d89b09ef6670edb7d5f91b4 commit 229 159 12
033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5 blob   22044 5792 4977696
82c99a3e86bb1267b236a4b6eff7868d97489af1 blob   4975916 4976258 1438

Das große Objekt befindet sich unten: 5 MB. Um herauszufinden, um welche Datei es sich handelt, verwende den Befehl rev-list, den du schonmal in Ein bestimmtes Commit-Message-Format erzwingen verwendet hast. Wenn du --objects an rev-list übergibst, werden alle festgeschriebenen SHA-1s und auch die BLOB-SHA-1s mit den ihnen zugeordneten Dateipfaden aufgelistet. Du kannst dies verwenden, um den Namen deines Blobs zu finden:

$ git rev-list --objects --all | grep 82c99a3
82c99a3e86bb1267b236a4b6eff7868d97489af1 git.tgz

Jetzt musst du diese Datei von allen Bäumen in deiner Historie entfernen. Du kannst leicht sehen, welche Commits diese Datei geändert haben:

$ git log --oneline --branches -- git.tgz
dadf725 Oops - remove large tarball
7b30847 Add git tarball

Du musst alle Commits hinter 7b30847 neu schreiben, um diese Datei vollständig aus deinem Git-Verlauf zu entfernen. Verwende dazu filter-branch, den du in Den Verlauf umschreiben verwendet hast:

$ git filter-branch --index-filter \
  'git rm --ignore-unmatch --cached git.tgz' -- 7b30847^..
Rewrite 7b30847d080183a1ab7d18fb202473b3096e9f34 (1/2)rm 'git.tgz'
Rewrite dadf7258d699da2c8d89b09ef6670edb7d5f91b4 (2/2)
Ref 'refs/heads/master' was rewritten

Die Option --index-filter ähnelt der Option --tree-filter, die in Den Verlauf umschreiben verwendet wurde. Jedoch ändern sie jedes Mal deinen Staging-Bereich oder Index anstatt daß sie einen Befehl zum Modifizieren von ausgecheckten Dateien auf deine Platte übergibt.

Anstatt eine bestimmte Datei mit etwas wie rm file zu entfernen, musst du sie mit git rm --cached entfernen - du musst sie aus dem Index entfernen, nicht von der Festplatte. Der Grund dafür ist die Geschwindigkeit - da Git nicht jede Revision auf der Festplatte auschecken muss, bevor der Filter ausgeführt wird, kann der Prozess sehr viel schneller sein. Du kannst die gleiche Aufgabe mit --tree-filter ausführen, wenn du möchtest. Die Option --ignore-unmatch für git rm weist an, dass keine Fehler auftreten, wenn das zu entfernende Muster nicht vorhanden ist. Schließlich forderst du filter-branch auf, deine Historie erst ab dem Commit 7b30847 neu zu schreiben, da du weißt, wo dieses Problem begann. Andernfalls wird es von vorne beginnen und unnötig länger dauern.

Dein Verlauf enthält nun keinen Verweis mehr auf diese Datei. Dein Reflog und eine neue Gruppe von Refs, die Git hinzugefügt hat, als du den filter-branch unter .git/refs/original ausgeführt hast, enthält jedoch weiterhin Verweise, sodass du sie entfernen und die Datenbank neu packen musst. Du musst alles loswerden, das einen Zeiger auf diese alten Commits enthält, bevor du neu packst:

$ rm -Rf .git/refs/original
$ rm -Rf .git/logs/
$ git gc
Counting objects: 15, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (15/15), done.
Total 15 (delta 1), reused 12 (delta 0)

Mal sehen, wie viel Platz du gespart hast.

$ git count-objects -v
count: 11
size: 4904
in-pack: 15
packs: 1
size-pack: 8
prune-packable: 0
garbage: 0
size-garbage: 0

Die Größe des gepackten Repositorys beträgt nur noch 8 KB, was viel besser als 5 MB ist. Du kannst anhand der Größe erkennen, dass sich das große Objekt noch in deinem losen Objekten befindet, sodass es nicht verschwunden ist. Es wird jedoch nicht auf einen Push oder nachfolgenden Klon übertragen, was wichtig ist. Wenn du es wirklich willst, kannst du das Objekt vollständig entfernen, indem du git prune mit der Option --expire ausführst:

$ git prune --expire now
$ git count-objects -v
count: 0
size: 0
in-pack: 15
packs: 1
size-pack: 8
prune-packable: 0
garbage: 0
size-garbage: 0

` === Umgebungsvariablen

Git läuft immer in einer bash Shell und verwendet eine Reihe von Shell-Umgebungsvariablen, über die man steuern kann, wie es sich verhält. Gelegentlich ist es hilfreich zu wissen, welche diese sind und wie du Git dazu bringen kannst, sich so zu verhalten, wie du es möchtest. Dies ist keine vollständige Liste aller Umgebungsvariablen auf die Git achtet, aber wir werden die nützlichsten behandeln.

Globales Verhalten

Einige der generellen Eigenschaften von Git als Computerprogramm hängen von Umgebungsvariablen ab.

GIT_EXEC_PATH bestimmt, wo Git nach seinen Unterprogrammen sucht (wie git-commit, git-diff und andere). Du kannst die aktuelle Einstellung überprüfen, indem du git --exec-path ausführst.

HOME wird normalerweise nicht als anpassbar angesehen (zu viele andere Dinge hängen davon ab), aber hier sucht Git nach der globalen Konfigurationsdatei. Wenn du eine wirklich portable Git-Installation mit globaler Konfiguration wünschst, kannst du HOME im portablen Git Shell-Profil überschreiben.

PREFIX ist ähnlich, jedoch für die systemweite Konfiguration. Git sucht nach dieser Datei unter $PREFIX/etc/gitconfig.

GIT_CONFIG_NOSYSTEM, falls gesetzt, deaktiviert die Verwendung der systemweiten Konfigurationsdatei. Dies ist nützlich, wenn deine Systemkonfiguration deine Befehle beeinträchtigt, du jedoch keinen Zugriff hast, um diese zu ändern oder zu entfernen.

GIT_PAGER steuert das Programm, mit dem mehrseitige Ausgaben in der Befehlszeile angezeigt werden. Ist dies nicht gesetzt, wird PAGER als Fallback verwendet.

GIT_EDITOR ist der Editor, den Git startet, wenn der Benutzer Text bearbeiten muss (z.B. eine Commit-Nachricht). Wenn nicht gesetzt, wird EDITOR verwendet.

Speicherort des Repositorys

Git verwendet mehrere Umgebungsvariablen, um die Verbindung zum aktuellen Repository herzustellen.

GIT_DIR ist der Speicherort des Ordners .git. Wenn dies nicht angegeben ist, geht Git nach oben durch den Verzeichnisbaum, bis es zu ~ oder / gelangt, und sucht bei jedem Schritt nach einem .git Verzeichnis.

GIT_CEILING_DIRECTORIES steuert das Verhalten bei der Suche nach einem .git Verzeichnis. Wenn du auf Verzeichnisse zugreifst, die nur langsam geladen werden können (z.B. auf einem Bandlaufwerk oder über eine langsame Netzwerkverbindung), möchtest du möglicherweise, dass Git den Versuch vorzeitig abbricht, insbesondere wenn Git in der Kommandozeile aufgerufen wird.

GIT_WORK_TREE ist der Speicherort des Stammverzeichnisses eines Arbeitsverzeichnisses für ein non-bare Repository. Wenn --git-dir oder GIT_DIR angegeben ist, jedoch nicht --work-tree, GIT_WORK_TREE oder core.worktree, wird das aktuelle Arbeitsverzeichnis als oberste Ebene deines Arbeitsbaums betrachtet.

GIT_INDEX_FILE ist der Pfad zur Indexdatei (nur für non-bare Repositorys).

GIT_OBJECT_DIRECTORY kann verwendet werden, um den Speicherort des Verzeichnisses anzugeben, das sich normalerweise in .git/objects befindet.

GIT_ALTERNATE_OBJECT_DIRECTORIES ist eine durch Doppelpunkte getrennte Liste (also im Format /dir/one:/dir/two:… `), die Git mitteilt, wo nach Objekten gesucht werden soll, wenn sie sich nicht in GIT_OBJECT_DIRECTORY` befinden. Wenn du viele Projekte mit großen Dateien hast, die genau den gleichen Inhalt haben, kannst du damit vermeiden, dass zu viele Kopien davon gespeichert werden.

Pfadspezifikation (engl. Pathspec)

„Pathspec“ bezieht sich darauf, wie du Pfade in Git angibst, einschließlich der Verwendung von Platzhaltern. Diese werden in der Datei .gitignore aber auch in der Befehlszeile (git add *.c) verwendet.

GIT_GLOB_PATHSPECS und GIT_NOGLOB_PATHSPECS steuern das Standardverhalten von Platzhaltern in Pfadangaben. Wenn GIT_GLOB_PATHSPECS auf 1 gesetzt ist, werden Platzhalterzeichen als Platzhalter verwendet (dies ist die Standardeinstellung). Wenn GIT_NOGLOB_PATHSPECS auf 1 gesetzt ist, stimmen Platzhalterzeichen nur mit sich selbst überein. Dies bedeutet, dass .c nur mit einer Datei namens „ .c“ übereinstimmt und nicht mit einer Datei, deren Name mit .c endet. Du kannst dies in Einzelfällen überschreiben, indem du die Pfadangabe mit :(glob) oder :(literal) beginnst, wie in :(glob)*.c.

GIT_LITERAL_PATHSPECS deaktiviert beide oben genannten Verhaltensweisen. Es können keine Platzhalterzeichen verwendet werden, und die Präfixe zum Überschreiben sind ebenfalls deaktiviert.

GIT_ICASE_PATHSPECS setzt alle Pfadangaben so, dass zwischen Groß- und Kleinschreibung nicht unterschieden wird.

Committen

Die endgültige Erstellung eines Git-Commit-Objekts erfolgt normalerweise über git-commit-tree, das diese Umgebungsvariablen als primäre Informationsquelle verwendet und nur dann auf Konfigurationswerte zurückgreift, wenn diese nicht vorhanden sind.

GIT_AUTHOR_NAME ist der für Menschen lesbare Name im Feld „author“.

GIT_AUTHOR_EMAIL ist die E-Mail-Adresse für das Feld „author“.

GIT_AUTHOR_DATE ist der Zeitstempel für das Feld „author“.

GIT_COMMITTER_NAME legt den für Menschen lesbaren Namen für das Feld „Committer“ fest.

GIT_COMMITTER_EMAIL ist die E-Mail-Adresse für das Feld „Committer“.

GIT_COMMITTER_DATE wird für den Zeitstempel im Feld „Committer“ verwendet.

EMAIL ist die Ersatz-E-Mail-Adresse für den Fall, dass der Konfigurationswert user.email nicht festgelegt ist. Wenn this nicht festgelegt ist, greift Git auf die Systembenutzer und Hostnamen zurück.

Netzwerk

Git verwendet die Bibliothek curl, um Netzwerkoperationen über HTTP durchzuführen. GIT_CURL_VERBOSE weist Git an, alle von dieser Bibliothek generierten Nachrichten auszugeben. Dies ähnelt dem Ausführen von curl -v in der Befehlszeile.

GIT_SSL_NO_VERIFY weist Git an, SSL-Zertifikate nicht zu verifizieren. Dies kann manchmal erforderlich sein, wenn du ein selbstsigniertes Zertifikat verwendest, um Git-Repositorys über HTTPS bereitzustellen, oder wenn du gerade einen Git-Server einrichtest, aber noch kein vollständiges Zertifikat installiert hast.

Wenn die Datenrate einer HTTP-Operation unter GIT_HTTP_LOW_SPEED_LIMIT Bytes pro Sekunde und länger als GIT_HTTP_LOW_SPEED_TIME Sekunden anhält, bricht Git diese Operation ab. Diese Werte überschreiben die Konfigurationswerte http.lowSpeedLimit und http.lowSpeedTime.

GIT_HTTP_USER_AGENT legt die User-Agent-Zeichenfolge fest, die von Git bei der Kommunikation über HTTP verwendet wird. Der Standardwert ist ein Wert wie git/2.0.0.

Vergleichen und Zusammenführen

GIT_DIFF_OPTS ist eigentlich ein unzutreffender Name. Die einzigen gültigen Werte sind -u<n> oder --unified=<n>, wodurch die Anzahl der in einem git diff Befehl angezeigten Kontextzeilen konfiguriert wird.

GIT_EXTERNAL_DIFF überschreibt den Konfigurationswert diff.external. Wenn diese Variable gesetzt ist, ruft Git dieses Programm auf, wenn git diff aufgerufen wird.

GIT_DIFF_PATH_COUNTER und GIT_DIFF_PATH_TOTAL sind innerhalb des durch GIT_EXTERNAL_DIFF oder diff.external angegebenen Programms nützlich. Ersteres gibt an, welche Datei in einer Reihe von Dateien verglichen wird (beginnend mit 1), und Letzteres gibt die Gesamtzahl der Dateien im Stapel an.

GIT_MERGE_VERBOSITY steuert die Ausgabe für die rekursive Merge-Strategie. Folgende Werte sind zulässig:

  • 0 gibt nichts aus, außer einer einzelnen Fehlermeldung (möglicherweise).

  • 1 zeigt nur Konflikte.

  • 2 zeigt auch Dateiänderungen an.

  • 3 zeigt an, wann Dateien übersprungen werden, weil sie sich nicht geändert haben.

  • 4 zeigt alle Pfade, während sie verarbeitet werden.

  • 5 und höher zeigen detaillierte Debugging-Informationen.

Der Standardwert ist 2.

Debugging

Möchtest du wirklich wissen, was in Git abgeht? In Git ist eine umfangreiche Sammlung von Traces eingebettet. Alles was du tun musst, ist sie einzuschalten. Die möglichen Werte dieser Variablen lauten wie folgt:

  • „true“, „1“ oder „2“ - die Trace-Kategorie wird nach stderr geschrieben.

  • Ein absoluter Pfad, der mit / beginnt - die Trace-Ausgabe wird in diese Datei geschrieben.

GIT_TRACE steuert allgemeine Traces, die keiner bestimmten Kategorie zugeordnet werden können. Dies umfasst die Erweiterung von Aliasen und die Delegierung an andere Unterprogramme.

$ GIT_TRACE=true git lga
20:12:49.877982 git.c:554               trace: exec: 'git-lga'
20:12:49.878369 run-command.c:341       trace: run_command: 'git-lga'
20:12:49.879529 git.c:282               trace: alias expansion: lga => 'log' '--graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all'
20:12:49.879885 git.c:349               trace: built-in: git 'log' '--graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all'
20:12:49.899217 run-command.c:341       trace: run_command: 'less'
20:12:49.899675 run-command.c:192       trace: exec: 'less'

GIT_TRACE_PACK_ACCESS steuert das Tracing der Packfile-Zugriffe. Das erste Feld ist die Packdatei, auf die zugegriffen wird, das zweite Feld ist der Offset in dieser Datei:

$ GIT_TRACE_PACK_ACCESS=true git status
20:10:12.081397 sha1_file.c:2088        .git/objects/pack/pack-c3fa...291e.pack 12
20:10:12.081886 sha1_file.c:2088        .git/objects/pack/pack-c3fa...291e.pack 34662
20:10:12.082115 sha1_file.c:2088        .git/objects/pack/pack-c3fa...291e.pack 35175
# […]
20:10:12.087398 sha1_file.c:2088        .git/objects/pack/pack-e80e...e3d2.pack 56914983
20:10:12.087419 sha1_file.c:2088        .git/objects/pack/pack-e80e...e3d2.pack 14303666
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

GIT_TRACE_PACKET aktiviert die Paketverfolgung für Netzwerkoperationen.

$ GIT_TRACE_PACKET=true git ls-remote origin
20:15:14.867043 pkt-line.c:46           packet:          git< # service=git-upload-pack
20:15:14.867071 pkt-line.c:46           packet:          git< 0000
20:15:14.867079 pkt-line.c:46           packet:          git< 97b8860c071898d9e162678ea1035a8ced2f8b1f HEAD\0multi_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress include-tag multi_ack_detailed no-done symref=HEAD:refs/heads/master agent=git/2.0.4
20:15:14.867088 pkt-line.c:46           packet:          git< 0f20ae29889d61f2e93ae00fd34f1cdb53285702 refs/heads/ab/add-interactive-show-diff-func-name
20:15:14.867094 pkt-line.c:46           packet:          git< 36dc827bc9d17f80ed4f326de21247a5d1341fbc refs/heads/ah/doc-gitk-config
# […]

GIT_TRACE_PERFORMANCE steuert die Protokollierung von Performancedaten. Die Ausgabe zeigt, wie lange jeder einzelne Aufruf von git dauert.

$ GIT_TRACE_PERFORMANCE=true git gc
20:18:19.499676 trace.c:414             performance: 0.374835000 s: git command: 'git' 'pack-refs' '--all' '--prune'
20:18:19.845585 trace.c:414             performance: 0.343020000 s: git command: 'git' 'reflog' 'expire' '--all'
Counting objects: 170994, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (43413/43413), done.
Writing objects: 100% (170994/170994), done.
Total 170994 (delta 126176), reused 170524 (delta 125706)
20:18:23.567927 trace.c:414             performance: 3.715349000 s: git command: 'git' 'pack-objects' '--keep-true-parents' '--honor-pack-keep' '--non-empty' '--all' '--reflog' '--unpack-unreachable=2.weeks.ago' '--local' '--delta-base-offset' '.git/objects/pack/.tmp-49190-pack'
20:18:23.584728 trace.c:414             performance: 0.000910000 s: git command: 'git' 'prune-packed'
20:18:23.605218 trace.c:414             performance: 0.017972000 s: git command: 'git' 'update-server-info'
20:18:23.606342 trace.c:414             performance: 3.756312000 s: git command: 'git' 'repack' '-d' '-l' '-A' '--unpack-unreachable=2.weeks.ago'
Checking connectivity: 170994, done.
20:18:25.225424 trace.c:414             performance: 1.616423000 s: git command: 'git' 'prune' '--expire' '2.weeks.ago'
20:18:25.232403 trace.c:414             performance: 0.001051000 s: git command: 'git' 'rerere' 'gc'
20:18:25.233159 trace.c:414             performance: 6.112217000 s: git command: 'git' 'gc'

GIT_TRACE_SETUP zeigt Informationen darüber an, was Git über das Repository und die Umgebung, mit denen es interagiert, herausfindet.

$ GIT_TRACE_SETUP=true git status
20:19:47.086765 trace.c:315             setup: git_dir: .git
20:19:47.087184 trace.c:316             setup: worktree: /Users/ben/src/git
20:19:47.087191 trace.c:317             setup: cwd: /Users/ben/src/git
20:19:47.087194 trace.c:318             setup: prefix: (null)
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

Sonstiges

GIT_SSH, falls angegeben, ist ein Programm, das anstelle von ssh aufgerufen wird, um eine Verbindung zu einem SSH-Host herzustellen. Es wird folgendermaßen aufgerufen: $GIT_SSH [username@]host [-p <port>] <befehl>. Beachte, dass dies nicht der einfachste Weg ist, um zu konfigurieren, wie ssh aufgerufen wird. Es werden keine zusätzlichen Befehlszeilenparameter unterstützt, daher musst du ein Wrapper-Skript schreiben und GIT_SSH so einstellen, dass es darauf verweist. Es ist wahrscheinlich einfacher, dafür einfach die Datei ~/.ssh/config zu verwenden.

GIT_ASKPASS dient zur Überschreibung des Konfigurationswertes core.askpass. Dies ist das Programm, das immer dann aufgerufen wird, wenn Git den Benutzer nach Anmeldeinformationen fragen muss, wobei eine Eingabeaufforderung als Befehlszeilenargument erwartet wird und die eine Antwort auf stdout zurückgeben soll. Weitere Informationen zu diesem Subsystem findest du unter Anmeldeinformationen speichern.

GIT_NAMESPACE steuert den Zugriff auf namenspaced refs und entspricht dem Flag --namespace. Dies ist vor allem auf der Serverseite nützlich, wo du möglicherweise mehrere Forks eines einzelnen Repositorys in einem Repository speichern möchtest, wobei nur die Refs getrennt bleiben.

GIT_FLUSH kann verwendet werden, um Git zu zwingen, nicht gepuffertes I/O zu verwenden, wenn inkrementell in stdout geschrieben wird. Ein Wert von 1 bewirkt, dass Gits Puffer öfter geleert wird. Ein Wert von 0 bewirkt, dass alle Ausgaben gepuffert werden. Der Standardwert (falls diese Variable nicht festgelegt ist) ist die Auswahl eines geeigneten Pufferschemas abhängig von Aktivität und Ausgabemodus.

Mit GIT_REFLOG_ACTION kannst du den beschreibenden Text angeben, der in das Reflog geschrieben wird. Hier ein Beispiel:

$ GIT_REFLOG_ACTION="my action" git commit --allow-empty -m 'My message'
[master 9e3d55a] My message
$ git reflog -1
9e3d55a HEAD@{0}: my action: My message
scroll-to-top