Arbeiten mehrere Personen zusammen an Quelltexten oder Dokumenten, artet das schnell in Gewurstel aus. Hier schafft Git schnell Abhilfe: Die verteilte Versionsverwaltung sorgt mit minimalem Aufwand zuverlässig für die Integrität und Konsistenz der Daten.
Dokumente oder Quelltexte, beispielsweise Entwürfe für Broschüren oder Arbeitspläne, werden oft von mehreren Benutzern genutzt und bearbeitet. Oft liegen sie dazu auf einem zentralen Fileserver, und die einzelnen Nutzer arbeiten mit lokalen Kopien. Unterschiede zwischen einzelnen Dokumenten gilt es manuell zu suchen, und oft bleibt unklar, ob es bereits neuere Versionen eines Dokuments gibt oder wer welche Änderungen vorgenommen hat. Eine Versionsverwaltung, wie man sie in vielen Software-Projekten antrifft, hilft dem Gewurstel ab. Ein besonders leistungsfähiger Vertreter dieser Gattung ist Git [1].
Git wurde 2005 von Linus Torvalds entwickelt, um damit den Quellcode des Kernels zu verwalten. Dazu musste es einer ganzen Reihe von Anforderungen genügen: Es sollte schnell sein, mehrere parallele Entwicklungszweige unterstützen und Daten zwischen verschiedenen Repositories austauschen. Die Datenintegrität musste sich überprüfen lassen, und einmal im Repository abgelegte Datenobjekte durften sich nicht im Nachhinein verändern lassen. Gegenüber anderen Versionsverwaltungen zeichnet sich Git durch leichte Erlernbarkeit, Datenredundanz über lokale Repositories, geringen Speicherverbrauch und kostenlose Services wie Github oder Gitorious aus.
Installation
Bei Git handelt es sich um ein Kommandozeilenprogramm, das es für Linux, Mac OS X, Solaris und MS Windows gibt. Mittlerweile existieren jedoch auch verschiedene grafische Benutzeroberflächen, darunter Gitk, Git-cola [2], Smartgit [3], Giggle [4] oder Gitg [5] sowie Weboberflächen wie Gitweb, Cgit [6] oder Gitlab [7].
Sie finden Git in den Repositories der meisten Distributionen und könne es bequem über die entsprechenden Paketwerkzeuge installieren. Legen Sie Wert auf eine tagesaktuelle Version, greifen Sie zu den Quelltexten des Git Source Repository auf Github [8] und installieren die Versionsverwaltung als Root mit dem Dreischritt aus Listing 1.
Listing 1
# ./configure # make all doc # make install install-doc install-html
Konfigurieren
Git bietet reichhaltige Möglichkeiten zur systemweiten sowie nutzer- und projektspezifischen Konfiguration. Systemweite Einstellungen liegen in /etc/gitconfig, Nutzereinstellungen in der Datei ~/.gitconfig im Home-Verzeichnis des jeweiligen Anwenders. Konfigurationen, die nur ein einzelnes Projekt betreffen, lagert Git in der Datei .git/config des jeweiligen Repositories.
Dieser Artikel geht nur auf die wichtigsten Einstellungen ein. Möchten Sie darüber hinaus Farben, den Editor für Commit- und Tag-Nachrichten, Commit-Vorlagen, Diff- und Merge-Konfigurationen und Ähnliches an Ihre Vorlieben anpassen, empfiehlt sich die Lektüre der Manpage und der Dokumentation [9] zu Git.
Zu den wohl wichtigsten Einstellungen gehört es, Git mit Ihrem Namen und Ihrer E-Mail-Adresse bekannt zu machen (Listing 2, Zeile 1 und 2). Die beiden Informationen nutzt Git später, um Schnappschüsse (“Commits”) einem Nutzer zuzuordnen. Die Option --global bedeutet, dass die Einstellungen standardmäßig für alle Git-Repositories eines Nutzers gelten. Sollen Name oder E-Mail-Adresse für ein spezielles Projekt anders lauten, müssen Sie git config im jeweiligen Repository nur ohne --global ausführen.
Listing 2
# git config --global user.name "Vorname Nachname" # git config --global user.email meine@email.tld # git config --global core.editor Wunscheditor
Setzen Anwender ein Commit ab, ruft Git in der Regel den Standard-Editor des Systems auf und greift auf Vi zurück, falls kein Standard-Editor eingerichtet wurde. Da Vi einerseits oft auch als Standard-Editor dient und es andererseits viele Anwender gibt, die Vi nicht mögen, bietet Git die Möglichkeit, den Editor frei zu wählen (Listing 2, Zeile 3).
Git im Einsatz
Git lässt sich im Alltag recht einfach anwenden. Um ein Projekt, egal ob Quelltext oder Bürodokument, mit der Versionsverwaltung bekannt zu machen, initialisieren Sie Git im entsprechenden Verzeichnis mittels des Aufrufs git init. Git legt daraufhin ein verstecktes Verzeichnis ./git an, dass es von nun an nutzt, um das Projekt und seine Entwicklung zu verfolgen (Abbildung 1).Beim Initialisieren muss das Verzeichnis noch keine Dateien enthalten.

Abbildung 1: Git interessiert beim Initialisieren nicht, ob ein Verzeichnis leer ist oder bereits Dateien enthält.
Um den Status eines Repositories einzusehen nutzen Sie den Befehl git status. Er listet auf, welche Dateien Git noch nicht beobachtet, welche sich seit dem letzten Commit geändert haben und welche Dateien in der “Staging Area” liegen. Abbildung 2 zeigt ein frisch initialisiertes Projekt, in dem Git noch keine Dateien verfolgt.
Die Staging Area stellen Sie sich am besten als Bereich vor, in dem sich diejenigen Dateien aufhalten, die mit dem nächsten Commit ihren Weg in den Git-Schnappschuss finden sollen. Ausgewählte Dateien, Verzeichnisse oder das ganze Projekt befördern Sie mit git add Datei oder git add . in die Staging Area. Der Status wechselt darauf von untracked zu new file (Abbildung 3).
Commits
Möchte ein Autor seinen aktuellen Arbeitsstand in einem Schnappschuss festhalten, kann er das mit git commit erledigen, nachdem er alle betroffenen Dateien in die Staging Area verschoben hat. Neben den Dateien und Änderungen hält Git bei einem Commit auch die Namen und E-Mail-Adressen von Autor und Committer sowie Erstellungs- und Commit-Datum fest.
Nach dem Absetzen des Befehls öffnet Git einen (vorher eingestellten) Editor und erlaubt es, eine Commit-Nachricht einzugeben. Dazu übernehmen Sie entweder den Git-Vorschlag, der alle Änderungen seit dem letzten Commit enthält – dazu müssen sie lediglich die Rautezeichen an den Zeilenanfängen entfernen – oder Sie geben eine eigene Nachricht ein (Abbildung 4).
Aus der Commit-Nachricht sollte hervorgehen, was verändert wurde. Da Git die Commits bei einer Log-Abfrage kurz und knackig präsentiert, sollte die erste Zeile stets eine Zusammenfassung enthalten. Das gilt vor allem, wenn die Commit-Nachricht länger ausfällt. Vor allem, wenn mehreren Personen zusammenarbeiten, helfen kurze Anmerkungen, warum etwas geändert wurde und ob an irgendeiner Stelle Probleme oder Fehler auftraten beziehungsweise zu erwarten sind.
Den ersten Commit nennt man gewöhnlich den initialen Commit, alle weiteren sollten Sie so benennen, dass am Projekt Beteiligte sofort sehen, was der Commit bewirkt. Nachrichten wie “kleine Bugs gefixt” sagen nichts Sinnvolles aus – aussagekräftiger wäre beispielsweise “Speicherzugriffsfehler in bitshift.cpp behoben”. Oftmals – gerade beim verteilten Arbeiten, wo möglichst alle Projektmitglieder den aktuellen Stand ohne Verzögerungen erhalten sollten – enthält ein Commit nur kleine Änderungen. Genügt eine solche kurze Commit-Nachricht, können Sie diese direkt im Aufruf mit angegeben, ohne dazu erst den Editor aufzurufen (Listing 3).
Listing 3
$ git commit -m "MPI_Type_create_struct für LineHistogram hinzugefügt"
Branches
Erweitert man eine bestehende Anwendung um neue Funktionen, dann besteht immer die Gefahr, dass funktionierende Teile in Mitleidenschaft gezogen werden. Git raubt dem Worst-Case-Szenario den Schrecken, denn es erlaubt verschiedene Zweige (“Branches”) eines Projekts. Ein solcher Zweig lässt sich mit einem Spielplatz vergleichen, auf dem sich neue Funktionen ausprobieren lassen, ohne schon bestehende Teile einer Anwendung zu gefährden.
Einen neuen Branch legen Sie mit dem Befehl git branch Name an. Es dürfen beliebig viele parallele Zweige bestehen, zwischen denen Sie mit git checkout Name wechseln. Der Befehl git branch ohne Angabe eines Namens zeigt alle existierenden Zweige an. Den aktuellen “Spielplatz” markiert Git mit einem Sternchen (Abbildung 5) – hier erfolgende Commits betreffen nur diesen Branch.

Abbildung 5: Git erlaubt viele gleichzeitige Branches. Ein Asterisk zeigt den aktuellen “Spielplatz” an.
Alle Änderungen, die in einem Zweig erfolgen, beeinflussen die anderen Branches in keiner Weise. Haben Sie das neu zu implementierende Feature fertiggestellt und hinreichend getestet, führen Sie den betreffenden Zweig über git merge Name mit dem Master zusammen.
Branches, die Sie nicht mehr brauchen, entfernen Sie mittels git branch -d Name. Möchten Sie einen Zweig umbenennen, erledigen Sie das mit dem Kommando git branch -m NeuerName.
Was gibt’s Neues?
Mit git diff lassen sich Unterschiede zwischen Branches (Branch1..Branch2, Commits (CommitID) oder Dateien (Dateiname) anzeigen und so Unterschiede schnell aufspüren. Das erweist sich vor allem dann als hilfreich, wenn beim Bugfixing nur wenige und auf den ersten Blick schwer zu findende Änderungen vorgenommen wurden.
Projekthistorien
Ein Projekt wächst, die Commits reihen sich aneinander, ein Meilenstein ist erreicht – jetzt muss ein Changelog her. Statt im Gedächtnis zu kramen, was seit dem letzten Meilenstein erreicht wurde, fragen Sie dazu einfach Git – vorausgesetzt, Sie haben auch immer aussagekräftige Commit-Nachrichten erstellt.
So plaudert git log aus, was bei jedem Commit passierte, wer dafür verantwortlich war und wann eine Änderung ins Projekt gespielt wurde. Die Ausgabe des Log fällt je nach Wunsch kurz und knackig oder auch sehr ausführlich aus. Rufen Sie den Befehl ohne weitere Parameter auf, gibt Git den eindeutigen Hash eines Commits, Autor, Datum und die Commit-Message aus. Die Option --graph visualisiert einzelne Branches (Abbildung 6). Der Parameter --oneline beschränkt die Ausgabe auf den Beginn des Commit-Hashes und die Commit-Nachricht, wobei er nicht mehr als eine Zeile verwendet.
Schäden begrenzen
Ein kleines Szenario: Sie finden sich plötzlich nach mehreren Tagen Entwicklung unter Zeitdruck und akutem Schlafmangel in “dreckigem”, zurechtgefrickelten Code wieder, der nicht wie gedacht funktioniert. Beim Wegtragen des Müll durchzuckt Sie plötzlich die viel versprechende Idee, die alle Probleme lösen könnte. Die erfolglosen Ansätze von Hand wieder aus dem Code zu fischen,ist wohl aussichtslos. Entweder fangen Sie also nochmal ganz von vorne an – oder nutzen die Vorteile der Versionsverwaltung und machen ein Rollback auf die letzte gut funktionierende Revision.
Sind Sie absolut sicher, dass die letzten Stunden für die Katz waren, stoßen Sie nun mit git reset --hard CommitID ein “hartes” Rollback an. Die Commit-ID bezeichnet den 40-stelligen Hash-Wert des gewünschten Schnappschusses. Die Hashes unterscheiden sich in der Regel so weit, dass Git meist die ersten sieben Stellen genügen, um einen Commit eindeutig zu identifizieren. Mit einem harten Reset setzen Sie alle Dateien im Arbeitsverzeichnis und in der Staging Area zurück.
Ersetzen Sie --hard durch --soft, setzt Git den angegebenen Commit auf die Version “HEAD”, was bedeutet, dass er als der letzte Commit gilt. Dabei bleiben alle Änderungen im Arbeitsverzeichnis und in der Staging Area erhalten. Ob ein Soft-Reset bei wirren Code-Verstrickungen sinnvoll und hilfreich ist, muss jeder für sich entscheiden.
Eine andere Möglichkeit eines Rollbacks bietet git checkout, das Sie schon vom Wechseln der Branches kennen. Für einen Rollback benennen Sie den Master-Branch um, holen mit git checkout CommitID den letzten brauchbaren Schnappschuss und machen diesen mittels git checkout -b master zum neuen Master. Bei git checkout -b Name handelt es sich um eine Kurzform für git branch Name und git checkout Name (Abbildung 7). Der Vorteil bei dieser Art des Rollbacks: Alle Änderungen und eventuell verwendbaren Ideen bleiben zunächst erhalten – Sie können sie später immer noch löschen.

Abbildung 7: Gits Checkout-Befehl eignet sich nicht nur für das Wechseln von Branches, sondern auch für Rollbacks.
Mit git checkout lassen sich nicht nur komplette Commits zurücksetzen, sondern auch einzelne Dateien. Dazu geben Sie lediglich zusätzlich den Dateinamen an. So stellt das Kommando git checkout af4673fa6 main.cpp den Zustand der Revision af4673fa6 der Datei main.cpp wieder her.
Verteilte Versionen
Git wurde von Beginn an als verteilte Versionsverwaltung entworfen, was bedeutet, dass mehrere Beteiligte gleichzeitig an einem Projekt arbeiten können. Im Unterschied zu einer zentralen Versionsverwaltung, die für Logs und Commits eine Verbindung zum Repository auf dem Server braucht, laufen Git-Repositories lokal und lassen sich mit einem Server abgleichen, sobald eine Netzwerkverbindung besteht.
Da der Server nur die Änderungen verteilen soll, genügt es, wenn dort ein sogenanntes Bare-Repository läuft. Dieses enthält lediglich die Dateien des Git-Verzeichnis .git eines Projekts und unterstützt die Projektmitglieder dabei, ihre Daten zu synchronisieren. Ein solches Bare-Repository legen Sie auf dem Server mittels des folgenden Befehls an:
$ git init --bare Repository.git
Dabei gelten für die Zugriffsrechte die Rechte der voreingestellten Umask des Nutzers, der das Repository anlegt (Abbildung 8). Auf dem lokalen Rechner klonen Sie das entfernte Repository mittels:
$ git clone ssh://Server/Pfad/Repository.git

.git eines Projekts, jedoch keine Arbeitsdateien.” width=”300″ height=”54″ />
Abbildung 8: Ein Bare-Repository enthält nur das Verzeichnis.git eines Projekts, jedoch keine Arbeitsdateien.Git unterstützt zum Synchronisieren der Repositories die Protokolle GIT, SSH und HTTP(S). Git unterstützt selbst keine Authentifizierung und greift stattdessen auf SSH zurück, um Anwender zu identifizieren, die einen Commit hochladen. Um zu vermeiden, dass alle am Projekt Beteiligten einen vollwertiges Benutzerkonto benötigen, um sich authentifizieren zu können, bieten sich Hilfsanwendungen wie Gitolite [10] an.
Ein frisches geklontes Bare-Repository gilt es erst einmal zu befüllen. Dazu erstellen Sie im lokalen Repository Projektdateien, nehmen dann einen Commit vor und gleichen diesen dann mit dem Remote-Repository ab. Letzteres erfolgt mit dem Befehl
$ git push Bare Local:Remote
Bei Bare handelt es sich um das entfernte Repository, Local bezieht sich auf den lokalen Zweig, Remote auf den entfernten Branch. Nach dem initialen Commit erkennt Git selbst, ob es für lokale Branches entfernte Pendants gibt, sodass meist ein schlichtes git push ausreicht (Abbildung 9).

push und pull synchronisieren Sie lokale und entfernte Git-Repositories.” width=”300″ height=”119″ />
push und pull synchronisieren Sie lokale und entfernte Git-Repositories. Das Gegenstück zu git push heißt git pull und kombiniert die Kommandos git fetch und git merge, um das lokale Repository mit dem entfernten zu synchronisieren. Die Kommandos fetch und merge fallen im Zusammenspiel mit entfernten Repositories oft recht komplex aus, hier lohnt ein Blick in die Git-Dokumentation.
Als Alternative zum eigenen Projekt-Server bieten sich öffentliche Dienste wie Github [11], Gitorious [12] oder Google Code [13] an. Für frei zugängliche Projekte fallen hier keine Kosten an. Projekte, die Sie nicht mit der Öffentlichkeit teilen wollen, hosten Github und Gitorious gegen Gebühr auch als private Repositories.
Einfach ignorieren
Gerade bei größeren Software-Projekten kommt es vor, dass Entwickler verschiedene Verzeichnisstrukturen nutzen oder unterschiedliche Konfigurationen bevorzugen. Passt jeder Entwickler Dateien, die Pfadangaben oder Konfigurationen beinhalten, immer wieder an eigene Gegebenheiten an und bucht sie so ein, führt das bei den Mitstreitern schnell zu Frust. Dazu kommt, dass Konfigurationsdateien oft Nutzernamen und Passwörter enthalten, die man nicht unbedingt verteilen will.
Erfreulicherweise ermöglicht es Git, einzelne Dateien bei einem Commit außen vor zu lassen. Dazu legen Sie im jeweiligen Arbeitsverzeichnis die Datei .gitignore an und tragen in diese alle Dateien ein, die Git bei einem Commit ignorieren soll. Dabei geben Sie pro Zeile eine Datei an.
Erfahrungswerte
Bei Software-Projekten, an denen mehrere Entwickler über eine Versionsverwaltung arbeiten, haben sich einige Vorgehensweisen als vorteilhaft erwiesen. Beispielsweise sollten Sie nach Möglichkeiten auch die Änderungen durch andere Entwickler verfolgen. So sehen Sie schnell, ob deren Code mit bestehenden eigenen Komponenten zusammenspielt, und finden etwaige Notizen zu noch bestehenden Fehlern. Repositories sollten immer nur ein Projekt enthalten, auch wenn Entwickler möglicherweise an mehreren Projekten gleichzeitig zusammenarbeiten.
Mit einem Commit schließen Sie idealerweise immer genau eine Aufgabe ab, beispielsweise ein neues Feature oder einen Bugfix. Die Commit-Nachrichten sollten aussagekräftig ausfallen und komplizierte Sachverhalte erklären, sofern das nicht in Kommentaren im Code erfolgt. Ein Repository enthält nach Möglichkeit nur Dateien, welche die Entwickler erstellt haben. Automatsch generierte Files oder frei zugängliche externe Bibliotheken und Hilfsprogramme haben darin nichts zu suchen: Sie blähen das Repository nur unnötig auf.
Der bei einem Commit veröffentlichte Code muss funktionieren, sodass die Projektmitglieder mit der Arbeit fortfahren können und nicht anfangen müssen, überraschend auftauchende Fehler zu beheben. Entfernen Sie trotzdem niemals ohne Rückfrage Code aus dem Projekt, nur weil er Ihnen nicht gefällt oder Sie ihn nicht auf Anhieb verstehen.
Fazit
Als leistungsfähige verteilte Versionsverwaltung kann Git noch deutlich mehr, als nur die in diesem Artikel vorgestellten Grundlagen. Zu den weitere Fähigkeiten zählen Tagging, Rebase, ein Git-Daemon für anonymen lesenden Zugriff auf Git-Repositories, Filter, Hooks sowie die Möglichkeit, im Nachhinein schutzwürdige Informationen oder Bibliotheken aus einem Repository zu entfernen. Für mehr Komfort bei der Bedienung sorgen bei Bedarf diverse grafische Oberflächen und Webfrontends.
Git-Praxisbuch zu gewinnen
Das in der Professional-Reference-Reihe von Open Source Press erschienene Git-Praxisbuch von Valentin Hänel und Julius Plenz (ISBN: 978-3-941841-42-0) führt Sie fundiert und mit zahlreichen Beispielen in die Funktionen von Git ein. Dabei stellt es alle relevanten Techniken vor, die im täglichen Umgang mit der verteilten Versionsverwaltung zum Einsatz kommen. Dabei bleiben auch fortgeschrittene Konzepte wie verschieden Merge-Strategien und automatisierte Fehlersuche nicht außen vor. Für Anwender, die bereits eine andere Versionsverwaltung wie Subversion nutzen, zeigt das Buch zudem passende Umstiegsszenarien auf. Sie erhalten das Buch im Buchhandel oder über http://www.opensourcepress.de zum Preis von 29,90 Euro.
Open Source Press hat uns freundlicherweise fünf Exemplare des Git-Buchs für eine Verlosung zur Verfügung gestellt. Um eines davon zu gewinnen, besuchen Sie uns bis zum 31.10.2012 auf unserer Facebook-Seite unter http://www.facebook.com/linuxuser.de und liken Sie den Eintrag zur Verlosung.
Infos
[1] Git: http://git-scm.com
[2] Git-cola: http://git-cola.github.com/
[3] Smartgit: http://www.syntevo.com/smartgit/index.html
[4] Giggle:https://live.gnome.org/giggle
[5] Gitg: https://live.gnome.org/Gitg
[6] Cgit: http://hjemli.net/git/cgit/
[7] Gitlab: http://gitlabhq.com
[8] Git (auf Github): https://github.com/git/git
[9] Git-Dokumentation: http://git-scm.com/doc
[10] Gitolite: https://github.com/sitaramc/gitolite
[11] Github: https://github.com/
[12] Gitorious: http://gitorious.org/
[13] Google Code: http://code.google.com









