Inhaltsverzeichnis
Versionskontrolle auf sächsisch
Ich gloobe fest daran, dass e Pfund Rindfleesch eene gute Briehe giebt.— Uwe Steimle
Versionskontrolle ist ein wichtiges Werkzeug für Programmierer. Für Open-Source-Projekte dominiert heute die Versionskontrolle mit Git und Github als externem Quellcodespeicher. Mit GitExtensions ist der Einstieg auf Windows-Systemen leichter. Hat man das Prinzip verstanden, ist es leicht zu merken. Das soll hier gezeigt werden. Dabei werden Begriffe wie Repository, Clone, Commit und Merge erklärt.
Vorbereitung
Benötigte Software
Git for Windows bildet die Grundlage. Die Versionskontrolle ist damit sowohl per Konsole als über Rechtsklick im Explorer (Git-Bash) nutzbar.
Auf der grafischen Oberfläche von GitExtensions findet man sich schnell zurecht, wenn man das Konzept verstanden hat. Statt "klicke hier" oder "klicke da" werde ich daher die Befehle in der Kommandozeilenversion präsentieren. Auch das ist einfach erlernbar. Dabei setze ich voraus, dass Programmierer wissen, wie man eine Konsole öffnet und damit in Verzeichnissen navigiert. Das ist nach 30 Jahren Windows nicht mehr selbstverständlich. Wer damit nicht zurecht kommt, kann sich an den beigefügten Bildchen orientieren, die auf Rechtsklicks im Explorer erscheinen.
Beteiligte
Für das entstehende Beispielprojekt genügen drei Verzeichnisse, die evtl. auf verschiedenen Rechnern liegen und drei Mitwirkenden zugeordnet werden. Nennen wir sie Anton, Bernd und Charlie. Zunächst muss jeder Git-Nutzer einige Dinge einstellen, die später wichtig sind: (Charlie hat schon einen Github-Account und möchte die eigene Mailadresse nicht dort veröffentlicht sehen.)
git config --global user.name charlies-username git config --global user.email CharliesPrivateNoReplyGithubAddress
Einzelplatzsystem
Projekt anlegen und versionieren
Charlie heißt eigentlich Charlotte, wird aber (für Nicht-Sachsen unverständlich) von ihren Freunden Ingrid gerufen. Charlie plant ein Projekt für ein Kochbuch mit sächsischen Gerichten. Sie legt einen neuen Ordner für das Projekt an:
md kochbuch cd kochbuch
Als erfahrene Programmiererin richtet sie sofort Versionskontrolle ein:
git init
Dadurch entsteht eine Ablage (engl. Repository = Lager, Depot)
im versteckten Unterverzeichnis .git
des Ordners kochbuch.
Die Ablage speichert alle entstehenden Versionen des Projektes.
Konsolenprogramme verunsichern manchen Anfänger, weil sie keine geschwätzigen Rückmeldungen "Repository angelegt" liefern. Die Programme beschweren sich nur, wenn ein Fehler aufgetreten ist. No news are good news. Es ist in Ordnung, dass man den Ablageordner auf der graphischen Oberfläche nicht sieht: Zutritt für Unbefugte verboten. Wenn du ihn sehen solltest, fummel bloß nicht dran rum! Es besteht sonst die Gefahr, das Repository zu ruinieren. Auf der Konsole kann Charlie sich davon überzeugen, dass es angelegt wurde:
dir
Sie interessiert sich aber bewusst nicht für den Inhalt. Charlie kann nun Dateien erstellen, ändern, hinzufügen und die Änderungen ins Repository übernehmen. Sie legt eine Datei
mit dem Namen index.html
an und stellt die Datei mit
git add index.html
unter Versionskontrolle. Mit
git status
kann sie nachsehen, welche Änderungen an der Versionierung vorgenommen wurden, und legt die Änderungen mit dem Befehl
git commit
in die Ablage (commit = engl. bekennen). Ein Editor öffnet sich. Darin muss eine kurze Beschreibung der Änderungen abgelegt werden:
Projekt Kochbuch angelegt
Zumindest sollte dies geschehen.
Charlie hat die Datei index.html
zu einer minimalen HTML-Datei
- charlie/kochbuch/index.html
<html> <body> Rezepte: </body> </html>
ausgebaut. Nach einem weiteren
git add index.html
der den jetzigen Arbeitsstand zwischenspeichert, in Git "staging" genannt, und
git commit -m "Inhaltsverzeichnis geändert"
liegen die ersten beiden Versionen im Repository, wovon man sich mit Befehlen wie
git show git status git log --pretty=oneline
überzeugen kann. Jede Version bekommt eine ziemlich lange Nummer (Hashwert):
723872d7480b99cc5cd015901d6b758a6fcbb340 (HEAD -> master) Inhaltsverzeichnis angelegt bd0e0a1562f2e069706562bf796b82e7739c7180 Projekt Kochbuch angelegt
Das grafische Werkzeug GitExtensions liefert diese Informationen sogar auf einen Mausklick:
So einfach ist Versionskontrolle. Aber wozu ist sie gut?
Zeitmaschine
Die Versionskontrolle ist für Charlie eine Zeitmaschine, mit der sie in der Historie des Projektes zu allen vorhergehenden Ständen springen kann. Sprünge zu künftigen Versionen wie "Projektabschluss" sind leider nicht möglich. (Warum eigentlich nicht?)
Charlie muss noch mal eine frühere Version ihres Projektes testen. Dazu setzt sie die Arbeitskopien unter Angabe des Hashwertes
git checkout bd0e0a1562f2e069706562bf796b82e7739c7180
auf einen früheren Stand zurück. Kein Jonglieren mit Datenträgern, nicht existierenden Backups oder ähnlichem. Sie kann sofort ihren Test durchführen und
git checkout master
bringt das Arbeitsverzeichnis wieder auf den aktuellen Stand.
Hat Charlie seit dem letzten Commit Änderungen an den Arbeitskopien vorgenommen, die sich nicht bewährt haben, oder Dateien gelöscht, kann sie diese Änderungen mit
git checkout index.html
einfach rückgängig machen.
Im Grunde läuft die Arbeit unter Versionskontrolle immer in diesen Schritten:
- Verändere dein Projekt.
- Teste, ob es funktioniert.
- Falls ja, sichere die Änderung durch Commit.
- Falls nein, mache die Änderung rückgängig.
- Weiter mit Schritt 1.
Wer Versionskontrolle nur als Einzelplatzsystem nutzen möchte, kann hier aufhören zu lesen. Mehr gibt es dazu nicht zu erklären.
Projekte klonen
Charlie hat eine ganz verrückte Idee zu ihrem Projekt, die sie ausprobieren will. Sie ahnt, dass dieses Experiment etwas längere Zeit in Anspruch nimmt und vermutlich auch mehrere Versionierungsschritte braucht. Sie möchte aber das aktuelle Projekt nicht in Mitleidenschaft ziehen, falls ihr Experiment scheitert. Dazu erzeugt sie eine Kopie (einen Klon) des aktuellen Projekt-Repositories:
cd .. git clone kochbuch experimental
Die Versionskontrolle legt dafür das angegebene Verzeichnis an. Der Klon kann nun unabhängig vom Hauptzweig verändert werden. Durch diesen "code fork" entstehen verschiedene Entwicklungslinien (engl. branches). Ist Charlies Idee nicht durchführbar, kann sie das experimental-Verzeichnis bedenkenlos löschen.
Warum nicht einfach das Verzeichnis kopieren, das geht doch auch? Das Problem liegt nicht beim Kopieren, sondern im Zusammenführen verschiedener Entwicklungslinien. Ohne Versionskontrolle wird es zum Alptraum.
Der Klon speichert die Information, aus welchem Repository er entstanden ist. Ist das Experiment erfolgreich, kann Charlie die Experimentalversionen ins übergeordnete Repository übergeben ("push" = engl. drücken). In umgekehrter Richtung können Änderungen aus dem übergeordneten Repository in den Experimental-Klon eingespielt werden ("pull" = engl. ziehen). Die Abläufe dieses Abgleichs mit mehreren, verteilten Repositories ähneln denen in der Teamarbeit.
Charlie stellt das Projekt ihren Mitarbeitern zur Verfügung, zumeist über einen Repository-Server im Web, nehmen wir z.B. an über Github. Sie legt ein neues Repository auf Github an und befolgt die dort angegebenen Hinweise für ein existierendes Projekt:
git remote add origin https://github.com/<charlies-username>/kochbuch.git git push -u origin master
Teamarbeit
Verteiltes Arbeiten
Anton erstellt eine Kopie des Projektes
git clone https://github.com/<charlies-username>/kochbuch.git cd kochbuch
auf seinem Rechner.
In seinem Verzeichnis kochbuch
stehen nun alle Dateien des Projektes.
Im Unterverzeichnis .git
liegt sein lokales Repository.
Anton erstellt ein Rezept
Abernmauke ---------- 1 Topf voll Kartoffeln waschen, schälen in Salzwasser kochen, bis sie weich sind, dann abgießen unter Zugabe von Milch zerstampfen mit geriebenem Muskat und etwas Salz abschmecken
und speichert die Version in seinem Repository:
git add abern.txt git commit
Ähnliches vollzieht Bernd:
git clone https://github.com/<charlies-username>/kochbuch.git cd kochbuch
Wieso steht in seinem Verzeichnis kochbuch
nur die Datei index.html
von Charlie?
Anton hat das "Abern"-Rezept in seinem lokalen Repository abgelegt,
nicht in dem von Charlie.
Git ist ein verteiltes Versionskontrollsystem.
Anton und Bernd können nach dem Klonen auch ohne ständige Netzverbindung an ihren lokalen Repositories arbeiten.
Der Datenverkehr mit der lokalen Festplatte ist wesentlich schneller als über die Netzwerkverbindung.
Bernd erstellt das Rezept
- bernd/kochbuch/blinsen.txt
Blinsen ------- 1 Liter Milch (frisch oder sauer) 3 Eier + 3 EL Zucker unter Zugabe von Mehl verrühren, bis ein dünnflüssiger Teig entsteht dünne Teigschicht in gut geölter Pfanne verteilen wenden, sobald Unterseite goldbraun ist
und legt ebenfalls seine Version ab:
git add blinsen.txt git commit
Habe ich erwähnt, dass auch Anton und Bernd ihre Nutzernamen für Git konfiguriert haben?
Ohne Versionskontrolle ist die jetzige Situation ein Alptraum. Wir haben (zum Glück nur) drei Entwickler und drei völlig verschiedene Projektstände. Wer soll den Überblick behalten und das wieder zusammenführen? Unter verteilter Versionskontrolle übernehmen dies die Entwickler selbst.
Lokale Änderungen veröffentlichen
Anton will seine Änderungen ins Charlies Repository zurückgeben. Zuvor fragt er aber Änderungen im übergeordneten Repository ab:
git fetch
Weil das Github-Repository unverändert ist, kann Anton seine Änderungen sofort mit
git push
übertragen.
Eingehende Änderungen einpflegen
Bernd sieht bei git fetch
Antons Änderung.
Mit
git merge
werden beide Entwicklungszweige im Arbeitsverzeichnis verschmolzen.
Da nur neue Dateien (abern.txt
) hinzu kommen,
gibt es dabei keine Konflikte.
Die Verschmelzung beider Revisionen kann Bernd nun mit
git push
ans übergeordnete Repository schicken. Anton übernimmt diese Version mit
git pull
(das ist git fetch & git merge
in einem) wiederum in sein lokales Repository.
Nun verfügt auch Anton über den aktuellen Stand in seinem Arbeitsverzeichnis.
Konflikte
Anton und Bernd ändern nun beide die Index-Datei des Kochbuchs:
- anton/kochbuch/index.html
<html> <body> Rezepte: <a href="abern.txt">Kartoffelbrei</a> </body> </html>
allerdings in unterschiedlicher Weise:
- bernd/kochbuch/index.html
<html> <body> Rezepte: <a href="blinsen.txt">Eierkuchen</a> </body> </html>
Beide übernehmen die Änderungen in ihr lokales Repository (commit). Anton legt seine Änderung zuerst im Zentralrepository:
git push
Bernd findet die Änderungen und übernimmt sie in sein Repository:
git pull
Da dieselbe Datei bearbeitet wurde, liegt ein Versionskonflikt vor:
Veränderungen in unterschiedlichen Abschnitten der Textdatei kann das Versionskontrollsystem ohne Zutun automatisch im Arbeitsverzeichnis zusammenführen. Da beide Autoren die selbe Zeile, aber mit unterschiedlichem Inhalt eingefügt haben, lässt sich der Konflikt nur manuell im Editor auflösen (Klick auf das rote Feld rechts unten: Resolve…). Ein Vergleichswerkzeug wie kdiff3, das sich (nach Installation und Konfiguration) über die grafische Oberfläche von GitExtensions aufrufen lässt, erleichtert das.
Bernd muss entscheiden, ob
- nur Antons Änderungen,
- nur seine eigenen,
- beide, wenn ja, in welcher Reihenfolge,
- oder etwas ganz anderes
übernommen wird.
Nach dem Speichern und Beenden gilt der Konflikt als gelöst.
Evtl. muss noch index.html.orig
gelöscht werden.
Die zusammengeführte Version wird von Bernd abgelegt und
vom lokalen ins übergeordnete Repository überführt:
git add . git commit git push
Anton holt sich die Änderungen wiederum mit git pull
in sein Verzeichnis.
Als Charlie vom Außeneinsatz zurückkommt,
aktualisiert ihr Arbeitsverzeichnis mit git pull
und betrachtet ihr Repository.
Sie bemerkt, dass Anton und Bernd während ihrer Abwesenheit zwei Rezepte,
abern.txt
und blinsen.txt
,
und das Inhaltsverzeichnis ergänzt haben:
- charlie/kochbuch/index.html
<html> <body> Rezepte: <a href="abern.txt">Kartoffelbrei</a> <a href="blinsen.txt">Eierkuchen</a> </body> </html>
So macht Teamarbeit Spaß!
Repository-Server
Repository-Server mit hohen Sicherheitsansprüchen aufzusetzen erfordert Administrator-Kenntnisse, die den Rahmen dieses Textes sprengen würden. Github bietet seit 2019 auch private Repositories. Anmelden, Einrichten von Repositories und Freigabe erfolgen über den Webbrowser. Je Projekt können Wiki und Issue-Tracking genutzt werden. Nur einladene Nutzer ("Freunde") sehen private Repositories und dürfen evtl. dort ändern.
Für öffentliche Repositories sind keine Schreibrechte notwendig. Jeder Nutzer kann Projekte anderer klonen, von anderen "Pull-Requests" in sein lokales Repository einpflegen und die Zusammenführung dann wieder unter seinem eigenen Account veröffentlichen. Diese "pull-only"-Versionskontrolle wird von großen Open-Source-Projekten praktiziert.
Installation
Der hier beschriebene Ablauf basiert auf folgender Software:
- http://kdiff3.sourceforge.net/ : kdiff3 (o.ä.) als MergeTool für
- http://gitextensions.github.io/ (Windows) und
- registriere Dich als Nutzer auf https://github.com.
Installiere Git, konfiguriere user.name
und user.email
.
Optional installiere ein mergetool, gib das mergetool / difftool in GitExtensions an.
Nie wieder geht ein Quelltext verloren…