Inhaltsverzeichnis

Versionsgeschichte und Zeitmaschine

Die Abfolge der Commits betrachten

Nachdem wir einige Commits gemacht haben, können wir unser Repository untersuchen:

max@pc:~/tagebuch$ git log
commit d7aaac47e7e68c5dcbacb4f1b8fa5a1ba4377348 (HEAD -> main)
Author: Max Mustermann <max@example.org>
Date:   Wed Oct 2 09:12:06 2024 +0200
 
    Mittagessen hinzugefügt
 
commit adc15c234c635a79a1cf90d10199ed6e42b47954
Author: Max Mustermann <max@example.org>
Date:   Wed Oct 2 09:11:12 2024 +0200
 
    fruehstueck.txt geändert
 
commit f9353d6278296bd173d3760e3b95e743208650e7
Author: Max Mustermann <max@example.org>
Date:   Wed Oct 2 08:58:45 2024 +0200
 
    Frühstück in Datei 'fruehstueck.txt' hinzugefügt
 
commit 28ec5a71bc2bce75bbbbfe5f2d336fe49b3642fa
Author: Max Mustermann <max@example.org>
Date:   Wed Oct 2 08:35:53 2024 +0200
 
    Erster Commit: aufstehen.txt angelegt

Man sieht – recht ausführlich – einige Informationen zu jedem Zeitpunkt, an dem ein Snapshot der unter Versionskontrolle stehenden Dateien in unserem Arbeitsverzeichnis erstellt wurde:

Das ganz benötigt recht viel Platz, man kann die Ausgabe des Logs umfangreich anpassen, zum Beispiel so:

max@pc:~/tagebuch$ git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%ci) %Creset' --abbrev-commit
* d7aaac4 - (HEAD -> main) Mittagessen hinzugefügt (2024-10-02 09:12:06 +0200) 
* adc15c2 - fruehstueck.txt geändert (2024-10-02 09:11:12 +0200) 
* f9353d6 - Frühstück in Datei 'fruehstueck.txt' hinzugefügt (2024-10-02 08:58:45 +0200) 
* 28ec5a7 - Erster Commit: aufstehen.txt angelegt (2024-10-02 08:35:53 +0200)

Das sieht zwar nett aus, es ist aber ein wenig schwer, sich all die Optionen zu merken. git ermöglicht es darum, für solche individuellen Befehle sogenannte Aliase anzulegen – auf die folgende Weise kann man einen eigenen "git-Befehl" anlegen, der die Versionsgeschichte hübsch ausgibt.

max@pc:~/tagebuch$ git config alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %Creset' --abbrev-commit"
max@pc:~/tagebuch$ git lg
* d7aaac4 - (HEAD -> main) Mittagessen hinzugefügt (vor 6 Minuten) 
* adc15c2 - fruehstueck.txt geändert (vor 7 Minuten) 
* f9353d6 - Frühstück in Datei 'fruehstueck.txt' hinzugefügt (vor 19 Minuten) 
* 28ec5a7 - Erster Commit: aufstehen.txt angelegt (vor 42 Minuten) 

(A1)

Zeitmaschine

Go Back in Time - es gibt offene Fragen...

Wichtig

Zunächst ist es sehr empfehlenswert, dass man nur dann zu einem älteren Stand der Dateien zurückkehrt, wenn das Arbeitsverzeichnis keine nicht committeten Änderungen beinhaltet. ("Sauberes Arbeitsverzeichnis")

Wir befinden uns aktuell also in einem sauberen Arbeitsverzeichnis, git status zeigt also keine unbearbeiteten Änderungen:

max@pc:~/tagebuch$ git status
Auf Branch main
nichts zu committen, Arbeitsverzeichnis unverändert

Jetzt können wir mit unserem neuen Alias git lg die Versionsgeschichte ansehen:

max@pc:~/tagebuch$ git lg
* d7aaac4 - (HEAD -> main) Mittagessen hinzugefügt (vor 6 Minuten) 
* adc15c2 - fruehstueck.txt geändert (vor 7 Minuten) 
* f9353d6 - Frühstück in Datei 'fruehstueck.txt' hinzugefügt (vor 19 Minuten) 
* 28ec5a7 - Erster Commit: aufstehen.txt angelegt (vor 42 Minuten) 

Man kann den Zustand des Arbeitsverzeichnisses aus den Commits wieder herstellen. Es ist also möglich, das Arbeitsverzeichnis in genau den Zustand zurückzuversetzen, in dem es beim Commit f9353d6 - Frühstück in Datei 'fruehstueck.txt' hinzugefügt vor 19 Minuten war – oder eben zu jedem anderen Zeitpunkt, an dem ich zuvor den Zustand des Arbeitsverzeichnisses als Snapshot commitet habe. Der Befehl dazu ist git checkout <Commit-Hash>:

max@pc:~/tagebuch$ git checkout f9353d6 
Hinweis: Wechsle zu 'f9353d6'.
 
Sie befinden sich im Zustand eines 'losgelösten HEAD'. Sie können sich
umschauen, experimentelle Änderungen vornehmen und diese committen, und
Sie können alle möglichen Commits, die Sie in diesem Zustand machen,
ohne Auswirkungen auf irgendeinen Branch verwerfen, indem Sie zu einem
anderen Branch wechseln.
 
Wenn Sie einen neuen Branch erstellen möchten, um Ihre erstellten Commits
zu behalten, können Sie das (jetzt oder später) durch Nutzung von
'switch' mit der Option -c tun. Beispiel:
 
  git switch -c <neuer-Branchname>
 
Oder um diese Operation rückgängig zu machen:
  git switch -
 
Sie können diesen Hinweis ausschalten, indem Sie die Konfigurationsvariable
'advice.detachedHead' auf 'false' setzen.
 
HEAD ist jetzt bei f9353d6 Frühstück in Datei 'fruehstueck.txt' hinzugefügt

Was ist denn jetzt passiert? Was bedeutet diese komische Meldung? Was ist ein lösgelöster HEAD1)?

(1) Zunächst einmal befinden sich die Dateien im Verzeichnis jetzt in dem Zustand, in dem sie waren, als der Commit f9353d6 erstellt wurde. Überprüfe das!

Lösung

(2) Untersuche die Versionsgeschichte – wie sieht diese jetzt aus? Was fällt auf?

Lösung

Git zeigt mit git log standardmäßg die Versionsgeschichte an, die zu dem Commit geführt hat den man im Arbeitsverzeichnis gerade angezeigt bekommt. Um git zu veranlassen, die gesamte Versionsgeschichte anzuzeigen, muss man dem Befehl git log die Option --all mitgeben.

max@pc:~/tagebuch$ git lg --all
* d7aaac4 - (main) Mittagessen hinzugefügt (vor 10 Stunden) 
* adc15c2 - fruehstueck.txt geändert (vor 10 Stunden) 
* f9353d6 - (HEAD) Frühstück in Datei 'fruehstueck.txt' hinzugefügt (vor 11 Stunden) 
* 28ec5a7 - Erster Commit: aufstehen.txt angelegt (vor 11 Stunden) 

Was ist HEAD?

Man muss sich die Versionsgeschichte als (verzweigte) Abfolge von Commits vorstellen, die jeweils durch ihre Commit-ID identifiziert werden. Manche Commit-IDs bekommen Namen: Diese benannten Commits sind "Branches" und "Tags". Man spricht von "Referenzen auf Commits".

Eine besondere Referenz ist HEAD. HEAD springt in gewisser Weise in der Versionsgeschichte herum, und zeigt immer auf denjenigen Commit, der im Arbeitsverzeichniss gerade "ausgecheckt" ist.

Der Zustand in unserem Beispiel ist "in bunt" folgender:

Es gibt insgesamt also 4 Commits, das Arbeitsverzeichnis ist im Zustand von Commit f9353d6 darum zeigt HEAD auf diesem Commit. Außerdem gibt es den Branch main, das ist eine benannte Referenz auf den neuesten Commit mit der ID d7aaac4

Um die Situation des "Lösgelösten HEAD" zu verstehen, muss man sich nun klar machen, dass der Commit adc15c2 auf dem Commit f9353d6 (auf den derzeit HEAD zeigt) basiert. Wenn man im derzeitigen Zustand des Arbeitsverzeichnisses etwas ändert, bekommt man ein Problem, da diese Beziehung adc15c2 basiert auf f9353d6 nicht mehr eindeutig interpretierbar ist: Wo sortiert sich der ausgehend von f9353d6 veränderte Zustand des Arbeitsverzeichnisses in die Versionsgeschichte ein wenn man einen neuen Commit erzeugt?

Diese Situation wird als "detached HEAD" oder losgelöster HEAD bezeichnet. Man kann sich umsehen und Dinge ändern, wenn man anschließend jedoch wieder in der Versiongeschichte "springt" gehen diese Änderungen verloren oder landen in einem Commit der "losgelöst" ist, also nicht in einem Branch innerhalb der Versionsgeschichte enthalten ist - und das sollte man vermeiden, da man solche Commits später nur schwer wiederfinden kann.


(A2)

Demonstration der Aufgabenstellung

Mit dem letzten Befehl git branch blaubeerfruehstueck f98e6d1 im Video wurde ein neuer Branch angelegt. In der Ausgabe von git log --all kann man das erkennen - es gibt im Zeitverlauf jetzt eine Verzweigung.

1)
Auf Englisch detached HEAD