Git-Tutorial, Teil 2 – Ein Arbeitsalltag Ein typischer, simpler Git-Workflow

Autor / Redakteur: Mirco Lang / Stephan Augsten |

In diesem Teil des Git-Tutorials gehen wir einen vereinfachten, aber praktischen Arbeitstag mit entferntem Git-Repository, Teamarbeit und Dateikonflikten durch. Denn der Reiz der verteilten Versionsverwaltung liegt nun einmal in den Collaboration-Funktionen.

Anbieter zum Thema

Die verteilte Versionsverwaltung von Git vereinfacht die Teamarbeit ungemein.
Die verteilte Versionsverwaltung von Git vereinfacht die Teamarbeit ungemein.
(© bakhtiarzein - stock.adobe.com)

Im ersten Teil des Git-Tutorials haben Sie gelesen, wie Sie ein Repository anlegen, Dateien hinzufügen, Änderungen committen und Logs durchgehen. Bis hierhin ging es also nur um einen einzelnen, lokalen Nutzer.

Natürlich tauchen im Rahmen der Zusammenarbeit mit Kollegen auch einige bekannte, lokale Operationen wieder auf, die noch ein wenig mehr Detail verdient haben. Allerdings mussten Sie sich noch keinerlei Gedanken machen, wie die Synchronisierung läuft oder was passiert, wenn Sie und ein Kollege dieselbe Datei bearbeitet haben. Möglicherweise sogar dieselbe Textstelle.

Hier noch einmal der Workflow in Kürze: Änderungen/Commits zum entfernten Server hochladen (push), lokales Repository mit entferntem abgleichen (pull), Logs ausführlich anschauen (log), Änderungen verfolgen (show), Dateiversionen verfolgen (gitk), Umgang mit Konflikten, Änderungen committen, Commits nachträglich ändern (ammend) und abschließend wird wieder gepushed.

Vorbereitung

Zunächst mal zum Setup: Statt eines echten entfernten Servers/Repositories können Sie einfach ein lokales Verzeichnis nutzen – das Verhalten ist exakt dasselbe. Angenommen, Sie haben ein Git-Arbeitsverzeichnis „git”, erstellen Sie darin drei Ordner: „meinprojekt_lokal”, „meinprojekt_lokal_2” und „meinprojekt_server”.

Wechseln Sie in den Server-Ordner und initialisieren Sie das Repository mit dem bekannten „init”, aber mit einem kleinen Twist:

git init --bare

… erstellt ein Repository, welches komplett ohne die eigentlichen Arbeitsdateien auskommt. Es dient ausschließlich zum Teilen eines Projekts mit anderen Teilnehmern.

Wechseln Sie nun in den Lokal-Ordner und klonen Sie das eben erstellte Bare-Repository mittels:

git clone ../meinprojekt_server

Den Klonbefehl kennen Sie vielleicht auch von Github. Viele Projekte verzichten auf ausführbare Dateien und liefern nur den Quellcode, der dann lokal vom Anwender kompiliert werden muss. In solchen Fällen kann man den Quelltext als Archiv herunterladen oder eben direkt mit git klonen, dann wahlweise über einen SSH- oder HTTPS-Link. Führen Sie den Befehl nochmals im Lokal_2-Ordner aus – dieser dient zur Simulation eines Kollegen.

Den Server-Ordner können Sie nun vergessen, Sie arbeiten nur noch in Ihrem Arbeitsverzeichnis unter „meinprojekt_lokal/meinprojekt_server”. Bei einem echten entfernten Server können Sie natürlich auf diese Ordnerverschachtelung verzichten, dann heißen entfernter und lokaler Ordner identisch. Legen Sie hier zunächst wie in Teil 1 beschrieben einige Dateien an, fügen Sie sie dem Repo hinzu und committen Sie alles. Für den weiteren Ablauf im Beispiel benötigen Sie eine leere Datei „test”.

Die einzelnen Schritte

Dateien hochladen

Bislang liegen Dateien und Änderungen nur im Lokal-Verzeichnis. Um zum Server-Repository hochzuladen, führen Sie ein simples …

git push

… aus. Damit befindet sich der lokale Snapshot/Commit eben auch auf dem „Server”. Die Dateien selbst finden Sie dort wie erwähnt nicht, da das Bare-Repository nur zum Teilen gedacht ist, nicht als Arbeitsverzeichnis.

Repository synchronisieren

Wechseln Sie nun in den Lokal_2-Ordner, um als anderer „Nutzer” zu agieren. Das leere Bare-Repository haben Sie ja bereits geklont, Sie müssen also nur noch den aktuellen Stand mit dem Gegenstück von „push” besorgen, also:

git pull

Sie müssen dabei keine weiteren Angaben machen, das Quell-Repository wird beim Klonen festgelegt. Tipp: Wenn Sie dieses Quell-Repository auslesen wollen, hilft:

git remote show origin

Führen Sie wieder ein …

git status

… aus und Sie bekommen die Meldung, dass Sie Up-to-Date sind. Machen Sie nun einige Änderungen, committen Sie und rufen Sie wieder den Status auf: Jetzt sagt Ihnen Git, dass Ihr „branch” ein Commit weiter als „origin/master” ist. Mit Branch ist hier schlicht Ihr aktueller Arbeitsbereich/Status gemeint und mit „origin/master” der Stand des Server-Repositories zum letzten Pull-Aufruf.

Wie versprochen verzichten wir hier auf die Hintergründe, wenn Sie aber produktiv werden wollen, sollten Sie vorher Begriffe wie Branch, Master, Head und so weiter klären. Damit andere nicht hinterherhinken, veröffentlichen Sie Ihre Änderungen wieder per „git push”.

Fremde Änderungen prüfen

Wechseln Sie wieder in den Lokal-Ordner, also Ihre eigentliche Nutzerumgebung. Der simulierte Kollege hat ja nun einige Änderungen gemacht und am Beginn eines Arbeitstags in Git steht folglich das Update mit „git pull”, gefolgt von den ebenfalls bekannten Befehlen „log” und „show” zum Aufzeigen einzelner Commits.

Hier darf es aber etwas mehr sein, als noch in Teil 1. Versuchen Sie es mit:

git log --stat –abbrev-commit

Der Parameter „stat” liefert zusätzliche Informationen: Wie viele Dateien haben sich pro Commit geändert, wie viele Additionen und Subtraktionen gab es pro Datei pro Commit. So sehen Sie auf einen Blick nicht nur die Commit-Nachrichten, sondern auch, was die Kollegen überhaupt getan haben. Über „abbrev-commit” werden die Hashes der Commits schlicht abgekürzt – auch mit nur 10 Stellen sind sie hier noch eindeutig genug.

Eine weitere Variante für die Log-Ausgabe wäre:

git log -p -2 --pretty=fuller

Über „-p 2” werden direkt im Log auch die Änderungen der letzten beiden Commits angezeigt und über die „pretty”-Option lassen sich unterschiedlich ausführliche, hübsche Ausgaben erzwingen. Welche das sind, entnehmen Sie der Git-Referenz.

Für „show” bieten sich ähnliche Optionen an, beispielsweise …

git show --pretty=oneline Hash-Wert

…, um Commits als Einzeiler auszugeben, oder …

git show --pretty=fuller --abbrev-commit Hash-Wert

…, um Commits umfangreich, aber mit abgekürztem Hash-Wert anzuzeigen.

Dateiversionen einsehen

Mit gitk lassen sich Versionen einer Datei gut durchstöbern.
Mit gitk lassen sich Versionen einer Datei gut durchstöbern.
(Bild: Lang / Git)

Manchmal ist es nützlich, nicht Commits einzusehen, sondern vielmehr den Versionsverlauf einzelner Dateien. Hier hilft das Kommando:

gitk test

An dieser Stelle wird der Terminal ausnahmsweise mal verlassen. Das gitk-Fenster listet alle Snapshots der Datei auf und Sie können bequem durch alte Versionen stöbern.

Konflikte beheben

Verursachen Sie zunächst einen Konflikt. Wechseln Sie zum Lokal_2-Ordner, schreiben Sie mittels …

echo textbeispiel > test

… etwas in die Datei „test”, committen und pushen Sie. Wechseln Sie wieder zum regulären Lokal-Ordner und schreiben Sie auch hier etwas in die Datei, etwa per …

echo foobar > test

… und committen Sie. Nun haben Sie also lokal eine andere Version der Datei als der Server, da der virtuelle Kollege im Lokal-2-Ordner seine Änderungen gepusht hat. Wenn Sie „git pull” ausführen kommt die Meldung, dass es einen Konflikt gibt.

Nicht automatisch lösbare Konflikte vermerkt Git direkt in der betroffenen Datei und setzt den Prompt auf „MERGING”.
Nicht automatisch lösbare Konflikte vermerkt Git direkt in der betroffenen Datei und setzt den Prompt auf „MERGING”.
(Bild: Lang / Git)

Hier bestehen es nun zwei Möglichkeiten: Wenn Ihre und die Änderungen des Kollegen sich nicht widersprechen, führt Git beide Versionen einfach in ein Dokument zusammen und Sie müssen gar nichts tun. In unserem Fall funktioniert das jedoch nicht, Sie müssen den Konflikt händisch lösen. Der Git-Prompt ändert sich auch derart, dass hier nun „(master|MERGING)” steht, um Sie auf den offenen Konflikt hinzuweisen.

Git hat die betroffene Datei „test” um Anmerkungen bezüglich des Konflikts ergänzt. Zum Lösen öffnen Sie die Datei „test” in einem Editor, führen die Änderungen zusammen und löschen die Git-Anmerkungen. Anschließend können Sie die Datei speichern und mit …

git add test

… hinzufügen und dann committen. Der Konflikt ist damit gelöst und der Prompt sieht wieder normal aus.

Commits korrigieren

Wenn Sie etwas Falsches committed haben, können Sie die Änderungen auch einfach rückgängig machen und neu committen. Aber der letzte Commit lässt sich, natürlich nur vor dem Pushen, noch korrigieren. Wenn nur die Commit-Nachricht geändert werden soll:

git commit --amend -m „Neue CommitNachricht”

… erledigt den Job. Häufig passiert es auch, dass Sie vergessen haben, eine Datei vor dem Committen hinzuzufügen.

Haben Sie also Änderungen an „test” und „test2” vorgenommen, „test2” aber nicht mit „git add test2“ hinzugefügt, und committen dann alles Offene mit …

git commit -am „test1 und test2 bearbeitet”

…, dann fehlt die „test2” im Commit. Holen Sie daher das …

git add test2

… nach und führen Sie dann …

git commit --amend --no-edit

… aus. Damit wird der letzte Commit komplett durch einen neuen Commit ersetzt, der aber beide geänderten und geaddeten Datein umfasst; die Commit-Nachricht wird dank „no-edit” einfach beibehalten.

Wenn Sie am Ende des Tages mit all Ihren Änderungen zufrieden sind, führen Sie zum Abschluss erneut einen Push aus. Wichtig: Dies gilt natürlich nur für die hier beschriebene Testumgebung mit einem zentralen Repo zum Teilen – git ist kein zentrales System und kann auch anders aufgezogen werden.

Wie schon der erste Teil des Tutorials schließt auch dieser zweite mit einem Befehl mit dem ominösen HEAD:

git reset HEAD^^^

… würde die letzten drei, noch nicht gepushten, Commits rückgängig machen – Auflösung folgt.

(ID:45337882)