Sollten die Grafiken nicht funktionieren, kannst du die SVG-freie Version dieser Seite auswählen.
Die Grafiken sind derzeit nicht im SVG-Format. (zur SVG-Version)
Diese Seite ist eine kurze grafische Referenz der am häufigsten verwendeten Git-Kommandos. Wenn du schon einige Git-Grundlagen kennst, kannst du mit dieser Seite dein Verständnis vertiefen. Wenn du an der Erstellung dieser Seite interessiert bist, sieh dir mein GitHub-Repository dazu an.
Ebenfalls empfohlen: Visualizing Git Concepts with D3 (englisch).
Die vier oben in der Grafik erwähnten Kommandos kopieren Dateien zwischen dem Arbeitsverzeichnis, dem Index (stage) und dem Projektarchiv (history).
git add Dateien
 kopiert die Dateien aus dem Arbeitsverzeichnis in ihrem
 aktuellen Zustand in den Index.
 git commit
 speichert einen Schnappschuss des Indexes als Commit im Projektarchiv.
 git reset -- Dateien
 entfernt geänderte Dateien aus dem Index; dazu werden die Dateien
 des letzten Commits in den Index kopiert. Damit kannst du ein git
 add Dateien rückgängig machen. Mit git reset
 kannst du alle geänderten Dateien aus dem Index entfernen.
 git checkout -- Dateien
 kopiert Dateien aus dem Index in das Arbeitsverzeichnis. Damit
 kannst du die Änderungen im Arbeitsverzeichnis verwerfen.
 Du kannst mit git reset -p, git checkout -p oder
 git add -p interaktiv entscheiden, welche Blöcke (hunks) von
 Änderungen (in allen oder den angegebenen Dateien) verwendet werden
 sollen.
Es ist auch möglich, den Index zu überspringen und Dateien direkt aus dem Archiv (history) auszuchecken oder Änderungen im Arbeitsverzeichnis direkt zu committen:
git commit -a 
 ist gleichbedeutend mit git add auf allen im letzten Commit
 bekannten Dateien, gefolgt von einem git commit.
 git commit Dateien
 erzeugt einen neuen Commit mit dem Inhalt aller aufgeführten
 Dateien aus dem Arbeitsverzeichnis. Zusätzlich werden die
 Dateien in den Index kopiert.
 git checkout HEAD -- Dateien
 kopiert die Dateien vom letzten Commit sowohl in den Index als
 auch in das Arbeitsverzeichnis.
 Im weiteren Verlauf werden zur Darstellung Graphen der folgenden Art verwendet.
Commits werden in grün mit ihren Fünf-Zeichen-IDs dargestellt, sie verweisen auf ihre Eltern-Commits (parents). Branches werden in orange dargestellt, sie zeigen auf einen bestimmten Commit. Der aktuelle Branch wird mit der speziellen Referenz HEAD identifiziert. In diesem Bild sieht man die fünf letzten Commits, wobei ed489 der jüngste ist. main ("current branch", der aktuelle Branch) zeigt auf genau diesen Commit, wohingegen stable ("another branch", ein anderer Branch) auf einen der Vorfahren von main verweist.
(Zu allen Kommandos sind zum besseren Verständnis deutsche Übersetzungen angegeben. Da es sich dabei jedoch um Kommandos handelt, die nur im englischsprachigen Original zur Verfügung stehen, werden auch in den Erklärungen weitestgehend die Originalbegriffe verwendet.)
Es gibt verschiedene Möglichkeiten, die Unterschiede zwischen Commits anzuzeigen. Nachfolgend ein paar Beispiele. An jedes dieser Kommandos können ein oder mehrere Dateinamen als Argument angehängt werden, um die Darstellung auf diese Dateien einzuschränken.
Mit dem commit-Kommando erzeugt git ein neues Commit-Objekt
 mit den Dateien aus dem Index. Als Vorgänger wird der aktuelle Commit
 verwendet. Zusätzlich wird der aktuelle Branch auf den neuen Commit
 verschoben. Im folgenden Bild ist der aktuelle Branch main. Vor der
 Ausführung des Kommandos zeigte main auf ed489. Durch das
 Kommando wird ein neuer Commit f0cec mit dem Vorläufer ed489
 erstellt und der Branch main auf den neuen Commit verschoben.
Das gleiche geschieht auch, wenn der aktuelle Branch ein Vorgänger eines anderen ist. Im nachfolgenden Bild wird ein Commit auf dem Branch stable ausgeführt, der ein Vorgänger von main ist, was einen Commit 1800b erzeugt. Danach ist stable kein Vorgänger von main mehr. Um die beiden Branches wieder zusammenzuführen, ist ein merge oder rebase nötig.
Einen Fehler in einem Commit kannst Du mit git commit --amend
 korrigieren. Mit diesem Befehl erstellt git einen neuen Commit mit dem selben
 Vorgänger. Der ursprüngliche Commit wird irgendwann verworfen wenn nichts
 mehr auf ihn verweist.
Ein vierter Fall, ein Commit mit detached HEAD, wird weiter unten ausführlich erklärt.
Mit dem checkout-Kommando werden Dateien aus dem Projektarchiv
 oder dem Index in das Arbeitsverzeichnis kopiert. Optional wird damit auch der
 Branch gewechselt.
Wird ein Dateiname (und/oder -p) angegeben, so kopiert git
 diese Dateien aus dem gegebenen Commit in den Index und das
 Arbeitsverzeichnis. Zum Beispiel kopiert git checkout HEAD~ foo.c
 die Datei foo.c aus dem Commit mit dem Namen HEAD~ (der
 Vorgänger des aktuellen Commits) sowohl in das Arbeitsverzeichnis als auch in
 den Index. Wird kein Commit-Name angegeben, so werden die Dateien aus dem
 Index kopiert. Beachte: Der aktuelle Branch ändert sich nicht.
Wenn beim Checkout kein Dateiname sondern der Name eines (lokalen) Branches angegeben wird, so wird die Referenz HEAD auf diesen Branch verschoben, du "wechselst" also zu dem angegebenen Branch. Daraufhin werden die Dateien im Index und im Arbeitsverzeichnis denen aus dem Commit angepasst. Jede Datei, die im neuen Commit (a47c3 s.u.) existiert, wird kopiert; Jede Datei, die im alten Commit (ed489) existiert, aber nicht im neuen, wird gelöscht. Alle weiteren Dateien werden ignoriert.
Wenn kein Dateiname angegeben wird und die angegebene Referenz
 kein (lokaler) Branch ist (also z.B. ein Tag, ein Remote-Branch, eine
 SHA-1-ID oder etwas wie main~3), erhalten wir einen anonymen
 Branch, genannt detached HEAD. Das bietet sich besonders an, um in
 der Versionsgeschichte herumzuspringen. Sagen wir mal, du willst die Version
 1.6.6.1 von git kompilieren. Dann kannst du einfach mit dem Befehl git
 checkout v1.6.6.1 (welches ein Tag und kein Branch ist) den Quellcode
 von diesem Zeitpunkt auschecken und damit arbeiten. Später kannst Du zu einem
 anderen Branch zurückspringen, z. B. mit git checkout main. Ein
 Commit mit einem detached HEAD verhält sich jedoch etwas anders als
 wir es gewohnt sind. Dieser Fall wird unten
 behandelt.
Ist die Referenz HEAD detached (losgelöst), so funktionieren Commits beinahe wie gehabt, es wird nur kein benannter Branch aktualisiert. Dies kannst du dir als anonymen Branch vorstellen.
Sobald du etwas anderes auscheckst, etwa den Branch main, wird
 der Commit (vermutlich) von nichts mehr referenziert und geht verloren. In der
 Grafik gibt es nach dem git checkout main nichts mehr, das auf
 den Commit 2eecb zeigt.
Wenn du aber diesen Zustand speichern möchtest, kannst du einen neuen
 benannten Branch mit git checkout -b name erstellen.
Das reset-Kommando verschiebt den aktuellen Branch an eine
 andere Position. Optional aktualisiert es den Index und das
 Arbeitsverzeichnis. Er wird auch dazu benutzt, Dateien aus dem Projektarchiv
 in den Index zu kopieren ohne das Arbeitsverzeichnis zu verändern.
Wird ein Commit ohne Dateinamen angegeben, so wird der aktuelle Branch auf
 diesen Commit gesetzt und der Index mit dessen Inhalt überschrieben. Wird
 --hard benutzt, so wird auch das Arbeitsverzeichnis aktualisiert.
 Mit --soft wird weder der Index noch das Arbeitsverzeichnis
 verändert.
Wird kein Commit angegeben, so arbeitet reset mit
 HEAD. In diesem Falle wird der Branch nicht verschoben. Stattdessen
 wird der Index (und das Arbeitsverzeichnis mit --hard) mit dem
 Inhalt des letzten Commits überschrieben.
Wird ein Dateiname (und/oder die Option -p) angegeben, so
 funktioniert das Kommando ähnlich wie ein checkout
 mit einem Dateinamen, außer dass ausschließlich der Index (und nicht das
 Arbeitsverzeichnis) aktualisiert wird. (Du kannst auch anstatt von
 HEAD den Commit angeben, dessen Dateien verwendet werden sollen.)
Mit merge wird ein neuer Commit erstellt, der Änderungen
 anderer Commits mit dem aktuellen zusammenführt. Vor dem merge
 muss der Index dem aktuellen Commit entsprechen. Im einfachsten Fall ist der
 andere Commit ein Vorgänger des aktuellen, dann muss gar nichts getan werden.
 Im nächsteinfacheren Fall ist der aktuelle Commit ein Vorgänger des anderen
 Commits. Dann erzeugt das Kommando einen sogenannten
 fast-forward-Merge ("vorspulen"): Die aktuelle Referenz wird einfach
 auf den anderen Commit verschoben, danach wird dieser "ausgecheckt" (wie in
 checkout).
In den anderen Fällen muss ein "richtiger" Merge durchgeführt werden. Standardmäßig wird ein "rekursiver" Merge durchgeführt (du kannst aber auch andere Strategien angeben). Dieser nimmt den aktuellen Commit (unten ed489), den anderen Commit (33104) und ihren gemeinsamen Vorgänger (b325c) und führt einen Drei-Wege-Merge (Seite auf Englisch) durch. Das Ergebnis wird im Arbeitsverzeichnis und dem Index gespeichert. Dann wird ein Commit erzeugt, der zwei Eltern (33104 und ed489) hat.
Das cherry-pick-Kommando "kopiert" einen Commit. Es erzeugt
 einen neuen Commit auf dem aktuellen Branch mit der selben Bezeichnung und
 der selben Änderung wie im angegebenen Commit.
Ein Rebase ist eine Alternative zu einem Merge um mehrere Branches zusammenzuführen. Während ein Merge einen einzelnen neuen Commit mit zwei Eltern erzeugt und einen nicht-linearen Commit-Verlauf hinterlässt, spielt ein Rebase die Commits des aktuellen Branches auf das Ende des anderen Branch auf, wodurch der Commit-Verlauf linearisiert wird. Im Prinzip ist das ein automatisierter Weg, mehrere cherry-pick-Kommandos hintereinander auszuführen.
Der obige Befehl nimmt alle Commits, die im Branch topic, aber nicht im Branch main existieren (169a6 und 2c33a), spielt diese auf den Branch main auf und verschiebt dann den Branch sowie den HEAD auf den zuletzt angehängten Commit. Beachte, dass danach nichts mehr auf die alten Commits verweist und diese gegebenenfalls von der Garbage Collection gelöscht werden.
Mit der Option --onto läßt sich einschränken, wie weit
 rebase beim Neuaufspielen zurückgehen soll. Das folgende Kommando
 hängt an den main die letzten Commits aus dem aktuellen Branch
 nach dem Commit 169a6 an (nur 2c33a).
Durch Verwendung von git rebase --interactive können
 kompliziertere Aktionen mit den betroffenen Commits durchgeführt werden:
 drop (Verwerfen), reorder (Ändern der Reihenfolge),
 modify (Verändern eines Commits) und squash (Kombinieren
 mehrerer Commits). Zu diesen Aktionen gibt es keine naheliegende
 Visualisierung. Details können in der
 Dokumentation zu git-rebase(1)
 nachgelesen werden.
Der Inhalt von Dateien wird nicht wirklich im Index (.git/index) oder in Commit-Objekten gespeichert. Stattdessen wird jede Datei, identifiziert durch ihren SHA-1-Hash, in der Objektdatenbank (.git/objects) als blob gespeichert. Die Index-Datei enthält Dateinamen neben den Bezeichnern des assozierten Blobs sowie weitere Informationen. Für die Dateien von Commits existiert ein weiterer Datentyp, der tree (Baum), der ebenfalls durch seinen Hash identifiziert wird. Trees entsprechen Verzeichnissen im Arbeitsverzeichnis und enthalten, entsprechend ihres Inhalts von Dateien und weiteren Verzeichnissen, eine Liste von Blobs und Trees. Jeder Commit speichert den Bezeichner des zugehörigen "top-level"-Trees. Dieser Tree wiederum enthält alle Blobs und weitere Trees für Unterverzeichnisse, die zu diesem Commit gehören.
Führst du einen Comit mit einem detached HEAD durch, so wird der
 letzte Commit doch noch von etwas referenziert: Dem reflog von
 HEAD. Allerdings verfällt diese Referenz (je nach Konfiguration) nach
 einer Weile, so dass der Commit, ähnlich wie die verwaisten Commits aus
 git commit --amend oder git rebase, von der
 Garbage Collection (Müllabfuhr) gelöscht wird.
Im Folgenden werden wir den Effekt einiger Kommandos Schritt für Schritt nachvollziehen, ähnlich wie in Visualizing Git Concepts with D3 (englisch).
Wir beginnen damit, ein Projektarchiv zu erstellen:
$ git init foo
$ cd foo
$ echo 1 > myfile
$ git add myfile
$ git commit -m "version 1"
Mit Hilfe der folgenden Funktionen können wir den aktuellen Zustand des Projektarchivs einsehen:
show_status() {
 echo "HEAD: $(git cat-file -p HEAD:myfile)"
 echo "Stage: $(git cat-file -p :myfile)"
 echo "Worktree: $(cat myfile)"
}
initial_setup() {
 echo 3 > myfile
 git add myfile
 echo 4 > myfile
 show_status
}
Anfangs ist alles im Zustand "1".
$ show_status
HEAD: 1
Stage: 1
Worktree: 1
Hier können wir die Änderungen des Zustands von Index ("Stage") und Arbeitsverzeichnis ("Worktree") mit den Kommandos add und commit sehen.
$ echo 2 > myfile
$ show_status
HEAD: 1
Stage: 1
Worktree: 2
$ git add myfile
$ show_status
HEAD: 1
Stage: 2
Worktree: 2
$ git commit -m "version 2"
[main 4156116] version 2
 1 file changed, 1 insertion(+), 1 deletion(-)
$ show_status
HEAD: 2
Stage: 2
Worktree: 2
Wechseln wir nun zu einem initialen Zustand, in dem alle drei Stufen verschieden sind.
$ initial_setup
HEAD: 2
Stage: 3
Worktree: 4
Entsprechend der Diagramme oben sehen wir hier die Veränderungen durch verschiedene Kommandos.
git reset -- myfile kopiert vom HEAD in den Index:
$ initial_setup
HEAD: 2
Stage: 3
Worktree: 4
$ git reset -- myfile
Unstaged changes after reset:
M myfile
$ show_status
HEAD: 2
Stage: 2
Worktree: 4
git checkout -- myfile kopiert vom Index ins
 Arbeitsverzeichnis:
$ initial_setup
HEAD: 2
Stage: 3
Worktree: 4
$ git checkout -- myfile
$ show_status
HEAD: 2
Stage: 3
Worktree: 3
git checkout HEAD -- myfile kopiert vom HEAD sowohl in den
 Index, als auch ins Arbeitsverzeichnis:
$ initial_setup
HEAD: 2
Stage: 3
Worktree: 4
$ git checkout HEAD -- myfile
$ show_status
HEAD: 2
Stage: 2
Worktree: 2
git commit myfile kopiert vom Arbeitsverzeichnis in den Index
 und zum HEAD:
$ initial_setup
HEAD: 2
Stage: 3
Worktree: 4
$ git commit myfile -m "version 4"
[main 679ff51] version 4
 1 file changed, 1 insertion(+), 1 deletion(-)
$ show_status
HEAD: 4
Stage: 4
Worktree: 4
Copyright © 2010, Mark Lodato. German translation © 2012 Martin Funk, © 2017 Mirko Westermeier.
Dieses Werk ist lizensiert unter Creative Commons Namensnennung - Nicht-kommerziell - Weitergabe unter gleichen Bedingungen 3.0 Deutschland.