Git it on!

Einführung in den Git- und Mercurial-Client SmartGit/Hg

Thomas Singer, Marc Strapetz
©Shutterstock/Kostsov

SmartGit/Hg ist ein Git- und Mercurial-Client, der unter Windows, Mac OS X und Linux läuft. Für nicht kommerzielle Nutzung ist SmartGit/Hg kostenfrei, kommerzielle Nutzer müssen eine Lizenz pro Nutzer erwerben, mit der man alle neuen Versionen nutzen kann, die innerhalb eines Jahres nach dem Kaufzeitpunkt releast wurden (inkl. aller, auch später veröffentlichter Bugfix-Releases).

Die Windows- und Mac-Downloadpakete beinhalten bereits die notwendigen Git-Kommandozeilentools, unter Linux müssen sie (wie auch das Java Runtime Environment) vom Nutzer, z. B. mithilfe des jeweiligen Paketmanagers, installiert werden. Beim ersten Programmstart durchsucht SmartGit/Hg den Pfad nach den Git- und Mercurial-Kommandozeilentools und greift nur dann auf die beiliegenden zurück, wenn keine entsprechenden auf dem System gefunden wurden. Im Folgenden gehen wir nur auf Git ein, wobei viele Aussagen dazu in ähnlicher Weise auch auf Mercurial zutreffen.

Exklusiv für Sie!

Bis zum 30.09.2013 haben Sie die Möglichkeit, SmartGit/Hg-Lizenzen mit 25 Prozent Rabatt zu erwerben. Dazu besuchen Sie bitte www.syntevo.com/smartgithg/purchase.html und geben im unteren Teil der Shareit-Bestellseite den Couponcode JavaMagazin72013 ein.

Set-up Repository, öffnen Repository, Clone

Um lokal mit Git zu arbeiten, gibt es grundsätzlich drei Möglichkeiten: man kann ein neues Repository anlegen, ein schon lokal vorhandenes öffnen oder ein anderes Repository klonen.

Zum Anlegen eines neuen oder Öffnen eines schon lokal vorhandenen Repositorys wählt man Open an existing local or create a new repository im Welcome-Dialog oder den Menüpunkt Project | Open Repository und gibt den Pfad an, wo das Repository auf der Festplatte zu finden ist oder angelegt werden soll. Wenn SmartGit/Hg kein bestehendes Repository findet, fragt es nach, ob es ein solches anlegen soll. Repositories werden in so genannten „Projekten“ verwaltet. Ein Projekt kann mehrere Repositories enthalten, hat einen optionalen Namen und beinhaltet diverse Einstellungen, die SmartGit/Hg zusätzlich zu den bereits bestehenden Konfigurationsmöglichkeiten von Git bietet.

Zum Klonen wählt man Clone existing repository im Welcome-Dialog oder den Menüpunkt Project | Clone. Je nachdem, ob man von einem lokalen oder auf einem Server befindlichen Repository klonen möchte, wählt man die entsprechende Option aus und gibt entweder den lokalen Pfad oder den Git-Repository-URL ein. Sollte das Repository auf einer bekannten Plattform wie Assembla oder GitHub gehostet sein, kann man nach Eingabe der jeweiligen Accountdaten direkt das gewünschte Repository auswählen. Im nächsten Schritt wird festgelegt, ob evtl. vorhandene Submodules (verschachtelte Repositories) ebenfalls gleich geklont und ob nur eine bestimmte Branch geklont werden soll. Abschließend gibt man den lokalen Pfad, wo das Repository auf der Festplatte abgelegt werden soll, und den Namen des neu erzeugten Projekts an.

SmartGit/Hg fragt bei Zugriffen auf das auf einem Server befindliche Repository nach erforderlichem Nutzernamen, Passwort oder Private Key und kann diese abspeichern.

Abb. 1: Das Projektfenster gibt einen Überblick über die lokalen Änderungen, den Branch-Zustand und lokale (zu pushende) Commits, es erlaubt auch, Änderungen zeilenweise zu committen

Lokale Änderungen

Nachdem lokale Änderungen vorgenommen wurden, kann man diese entweder Git-typisch erst mit „Stage“ im Index speichern, um danach alle im Index gespeicherten Änderungen zu committen, oder man wählt die jeweiligen geänderten Dateien aus und committet sie direkt ohne Nutzung des Index.

Sollen nur einzelne Teile geänderter Textdateien committet werden, kann man diese im Changes-Bereich durch Klick auf [<<] oder mithilfe des Kontextmenüs im Index speichern („stagen“). Sind noch kleinere Überarbeitungen der zu stagenden Änderungen notwendig, kann man diese im Indexeditor vornehmen. Dieser bietet eine Repository-(HEAD), Index- und Working-Tree-Ansicht, wobei die letzteren beiden frei editierbar sind. Zum Committen von Indexänderungen kann man entweder im Directories-Bereich den Repository-Knoten oder eine Datei mit Indexänderungen anwählen und Commit aufrufen. Hat man für ein bereits erfolgtes Commit die eine oder andere Änderung übersehen, kann man diese mit der Amend-Option des Commit-Dialogs zum letzten Commit hinzufügen.

Noch nicht gepushte Commits werden im Pushable-Commits-Bereich angezeigt. Man kann deren Reihenfolge einfach durch Drag and Drop ändern, Commit Messages korrigieren oder benachbarte Commits zusammenfassen. Durch Kombination dieser Aktionen lassen sie sich neu arrangieren, was dem „interactive rebase“ der Git-Kommandozeile entspricht. Damit können aus einer Menge von „vorläufigen“ Commits abschließend „saubere“ Commits erstellt werden und eigene Fehler lassen sich so nachträglich bereinigen. Einschränkungen gibt es nur für Merge Commits und in jenen Fällen, wo das Umordnen zu Konflikten führen würde.

Zum Verwerfen von lokalen Änderungen kann man Discard aufrufen und entweder auf den Index- oder Repository-(HEAD-)Zustand zurücksetzen.

Umbenannte oder verschobene Dateien werden mit dem Untracked- bzw. Missing-Status angezeigt. Findet sowohl die Löschung als auch die Hinzufügung beider Dateien im gleichen Commit statt, erkennt Git die Ähnlichkeit der Dateien und im Log werden sie mit verbundener Geschichte angezeigt.

Log

Zum Ansehen der Commit-Geschichte des Repositorys wählt man im Directories-Bereich den Repository-Knoten und dann Log. Wenn man dies nur für eine bestimmte Datei sehen will, kann man diese mit Edit | Filter Files durch Eingabe ihres Namens schnell finden und auswählen (auch wenn sie aufgrund ihres Änderungszustands nicht den im View-Menü eingestellten Filtern entspricht und folglich ohne Suche nicht angezeigt werden würde), bevor man Log aufruft.

Im Log kann man im Branches-Bereich festlegen, für welche Branches die Versionsgeschichte angezeigt werden soll. Bei großen Repositories kann das Ausblenden von aktuell uninteressanten Branches helfen, sich auf das Wesentliche zu konzentrieren (und „den Wald vor lauter Bäumen wiederzuerkennen“). Durch Auswahl eines Commits sieht man im Details- und Filesbereich die entsprechenden Detailinformationen sowie betroffenen Dateien. Zum Vergleich zweier Repository-Zustände wählt man einfach diese zwei Commits gleichzeitig aus. Nach Auswahl einer Datei werden im Changes-Bereich die Unterschiede zwischen beiden Commits angezeigt. Über das Kontextmenü kann man einen alten Dateizustand wiederherstellen oder diesen mit dem Working Tree vergleichen.

Verschiedene Kommandos kann man direkt im Log ausführen, was besonders für das Arbeiten mit Branches (z. B. Merge, Rebase) sinnvoll ist.

Commits gehen im Repository nicht verloren, selbst wenn man die zugehörige Branch gelöscht oder gerebast hat. Im Branches-Bereich des Logs gibt es dazu die Option „Lost Heads“, die dabei hilft, scheinbar verlorene Commits wiederzufinden: hier greift SmartGit/Hg auf die so genannten „ref-logs“ von Git zurück und es scheinen alle Commits auf, die jemals von einer Branch (oder irgendeiner anderen „Ref“) referenziert wurden.

Abb. 2: Das Logfenster zeigt die Versionsgeschichte des Repositorys, Branches und Tags können zur besseren Übersicht ein-/ausgeblendet, lose Branch-Enden („lost heads“) angezeigt oder verschiedene Kommandos ausgeführt werden

Pull + Push

Falls man ein bestehendes Repository geklont hat, kann man die lokalen Commits mit Push in das ursprüngliche Repository zurückspielen. Sollte jemand anderes bereits seine Änderungen dorthin gepusht haben, wird Git das eigene Pushen verweigern. Dann muss man die fremden Änderungen mit Pull holen und in die eigenen integrieren. Git bietet dafür zwei Möglichkeiten: Merge und Rebase. Merge erzeugt einen Merge Commit aus den eigenen und den fremden Commits, während Rebase die eigenen Commits auf die fremden Commits „draufsetzt“ (ähnlich zu einem Cherry Pick). Da Rebase keine Merge Commits erzeugt, bleibt die Geschichte linear und optisch sauberer.

Mehr zum Thema Rebase (unabhängig von SmartGit/Hg) finden Sie übrigens auch im beiliegenden Poster, im Profitipp von Martin Dilger [Anm. d. Red.].

Merge + Rebase

Beim Mergen hat man die Wahl, ob Git automatisch ein Merge Commit anlegen soll oder man die Änderungen erst im Working Tree anschauen will. Hat man sich für Letzteres entschieden, wird das Merge Commit erst beim folgenden Commit erzeugt. Will man dagegen zwar die Änderungen übernehmen, aber kein Merge Commit anlegen („squash merge“), wählt man die entsprechende Option im Commit-Dialog.

Sollten bei dem Merge oder Rebase Konflikte auftreten, kann man für die konfliktbehafteten Dateien durch Doppelklick den Conflict Solver öffnen. Dieser zeigt die beiden individuellen Änderungen links und rechts an, während der teil-gemergte Zustand in der Mitte editierbar ist. Man kann nun manuell die Konflikte beheben und beim Schließen des Conflict Solvers wird man nach dem Speichern gefragt, ob man die Änderungen „stagen“ will. Falls der Konflikt komplizierter ist, kann man auf der konfliktbehafteten Datei das Log aufrufen und sich die Commits, die zu dem Konflikt geführt haben, mit ihren jeweiligen Änderungen ansehen. Nach dem Beheben aller Konflikte und dem Stagen der jeweils notwendigen Änderungen, kann man mit Commit den Merge Commit erzeugen oder das Rebase fortsetzen. Sollte man unglücklicherweise den roten Faden verloren haben, kann man mithilfe von Discard das Merge bzw. das Rebase abbrechen, um es danach erneut zu starten.

Mit Branches arbeiten

Git ist prädestiniert für die Arbeit mit mehreren Branches. Man kann sie einfach erzeugen und später wieder löschen und so ist es empfehlenswert, diese auch schon für kleinere Änderungen zu verwenden. Beginnt man beispielsweise im „master“ mit der Arbeit an einem Feature und die Implementierung stellt sich doch als aufwendiger heraus, kann man mit Add Branch rasch eine neue Branch erzeugen und seine Änderungen in diese committen. Diese lokale Branch kann bei Bedarf auf den Server gepusht werden, z. B. damit ein Kollege die Änderungen begutachten oder fortsetzen kann. Zum schnellen Umschalten zwischen Branches klickt man doppelt auf den jeweiligen Eintrag im Branches-Bereich. So lässt sich die Arbeit an einem Feature unterbrechen und zu einem anderen Arbeitspaket wechseln. Sollte die Ziel-Branch hinter ihrer Remote Branch liegen, fragt SmartGit/Hg, ob man diese gleich aktualisieren möchte („fast-forward merge“). Später kann man auf dieselbe Weise zu der Branch mit dem begonnenen Feature zurückwechseln, das Feature fertigstellen und die Änderungen zurück in den „master“ oder eine beliebige andere Branch mergen. Üblicherweise verwendet man hier beim Commit die „Squash“-Option, um ein einfaches Commit zu erzeugen und die einzelnen Änderungen aus der Feature-Branch nicht als Merge Source miteinzubinden. Abschließend wird die Branch wieder entfernt.

Stash

Um vorübergehend einen sauberen Working Tree zu erhalten, z. B. um mal schnell einen soeben entdeckten Fehler zu beheben, kann man Save Stash nutzen und später die lokalen Änderungen mit Apply Stash wieder herstellen. SmartGit/Hg verwendet Stashes bei Bedarf auch selbstständig, wenn beispielsweise beim Pullen aus dem Remote Repository (oder beim Wechsel zu einer anderen Branch oder einem anderen Commit) lokale Änderungen im Working Tree das erfolgreiche Ausführen des Kommandos verhindern.

Blame

Um herauszufinden, in welchem Commit eine bestimmte Codezeile einer Datei eingefügt wurde, ruft man auf dieser Datei Blame auf. Das Blame-Fenster zeigt im Document-Bereich den Inhalt der Datei zum Zeitpunkt des aktuell gewählten Commits. Man kann nun über direkte Auswahl des Commits oder durch Navigation über die Hyperlinks zu vorherigen Inhalten der Datei wechseln, um so Änderungen in einem bestimmten Bereich zu erkennen und zu verstehen.

Für die aktuell gewählte Zeile zeigt der History-Bereich alle jemals existenten Versionen dieser Zeile an. Dies ist hilfreich, um sich bei der Suche von komplexeren Fehlern möglichst rasch einen Eindruck über jene Änderungen zu verschaffen, die mit dem Problem in Zusammenhang stehen könnten.

Abb. 3: Das Blame-Fenster zeigt die Entstehungsgeschichte einer Datei auf Zeilenebene, um zu beantworten, wann ein bestimmter Codeblock eingebaut oder entfernt wurde, es erlaubt die Navigation zwischen verschiedenen Versionen einer Datei

SVN

SmartGit/Hg kann auch als interessante Alternative zu einem klassischen SVN-Client genutzt werden. Statt ein SVN Repository in eine lokale SVN Working Copy auszuchecken, wird es als lokales Git Repository geklont. SmartGit/Hg holt zuerst nur die neueste SVN-Revision (wie ein svn checkout), sodass man schon nach kurzer Zeit mit dem Git Repository arbeiten kann. Alle älteren Revisions werden danach im Hintergrund heruntergeladen und später in das lokale Git Repository integriert.

SmartGit/Hg bildet die Tag- und Branch-Struktur des SVN Repositorys im lokalen Git Repository ab. Im Gegensatz zum Kommandozeilentool „git-svn“ werden alle SVN Properties auf entsprechende Git-Pendants abgebildet, dies gilt insbesondere auch für die Abbildung von SVN Externals auf SVN Submodules im Git Repository.

Wie bei Git üblich, kann man in dem erzeugten Git-Klon nun lokal seine Commits erstellen, eine Verbindung zum SVN Repository ist dabei nicht erforderlich. Wenn man mit seinen lokalen Commits zufrieden ist und sie anderen Nutzern des SVN Repositorys zur Verfügung stellen möchte, pusht man sie zum SVN Repository zurück. Erst jetzt wird eine Verbindung zum Server aufgebaut und die erzeugten SVN Revisions werden für die anderen Nutzer sichtbar. Auch beim Push findet eine Abbildung aller Git-Attribute auf entsprechende SVN-Pendants statt. Insbesondere werden Merge Commits bzw. Cherry Picks in der svn:mergeinfo Property vermerkt und auch die svn:externals Property wird angepasst, sollten sich die SVN Submodules im Git Repository geändert haben. Neu erzeugte, lokale Git Branches werden auf Nachfrage entsprechend im branches/-Verzeichnis des SVN Repositories erzeugt. Sinngemäßes gilt für lokal erzeugte Tags, die entweder direkt bei deren Erzeugung gepusht oder später über das Kontextmenü im Branches-Bereich gepusht werden.

Aufmacherbild: Molecular structure von Shutterstock / Urheberrecht: Kostsov

Geschrieben von
Thomas Singer
Thomas Singer und Marc Strapetz sind Geschäftsführer der syntevo GmbH mit Sitz in Freilassing (Nähe Salzburg). Unter ihrer Leitung entstanden im Laufe der Jahre die erfolgreichen VCS-Clients SmartGit/Hg, SmartCVS und SmartSVN. Letzteres wurde im September 2012 von WANdisco International Ltd. übernommen.
Marc Strapetz
Marc Strapetz und Thomas Singer sind Geschäftsführer der syntevo GmbH mit Sitz in Freilassing (Nähe Salzburg). Unter ihrer Leitung entstanden im Laufe der Jahre die erfolgreichen VCS-Clients SmartGit/Hg, SmartCVS und SmartSVN. Letzteres wurde im September 2012 von WANdisco International Ltd. übernommen.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.