Als Entwickler gehört das Verwenden einer Versionsverwaltung zur täglichen Arbeit. In meinem Umfeld kommt dabei häufig (“noch”) Subversion (kurz “SVN”) zum Einsatz. Dabei handelt es sich um ein sogenanntes Zentrales Versionsverwaltungssystem, wo das Repository durch einen zentralen Server verwaltet wird. Viele Aktionen (wie z.B. die History-Funktion und Commit) benötigen somit Zugriff auf diesen Server.
Anders verhält es sich da bei den sogenannten “Verteilten Versionsverwaltungssystemen”. Hier wird auf dem eigenen Rechner eine Kopie des Repositories abgelegt (oder von einem Teil des Repositories). In dieser lokalen Kopie kann man jederzeit Branches erstellen, Commits durchführen oder die Historie einsehen. Also egal wo man sich gerade aufhält, ob unterwegs, ob mit oder ohne Netzzugang, man kann an seiner eigenen Entwicklung weiterarbeiten. Zusätzlich schließen diese verteilten Versionsverwaltungssysteme den Einsatz einer zentralen Repository-Kopie nicht aus. Man kann weiterhin ein zentralen Repository mit Zugang für jeden Entwickler bereitstellen.
Da in letzter Zeit eins meiner zentralen SVNs hin und wieder nicht übers Netz erreichbar war, habe ich nach einer Alternative gesucht, wie sich die Vorteile von einer verteilten Versionsverwaltung mit einer zentralen SVN-Verwaltung kombinieren lassen. Und kurzem Suchen im Netz bin ich auf git-svn gestoßen. Dieses Tool ermöglich das Erstellen eines Git-Repositories auf Basis eines SVN-Repositories. An dem so erstellten Repo können Änderung vorgenommen werden und später wieder an das zentrale SVN übertragen werden. Klasse, genau was ich brauchte. Zusätzlich gibt es für Windows noch die TortoiseGit-Explorer-Erweiterung, die auch git-svn unterstützt. Aber dazu später noch mehr.
Lesematerial
Wer aus der “SVN-Welt” kommt und auf ein verteiltes System wie Git wechselt, muss erstmal verstehen, wie ein solches System funktioniert. Auch gibt es neue Begrifflichkeiten, die man zumindest ansatzweise verstanden haben sollte. Eine relativ guten Einstieg habe ich im Online-Buch “Pro Git” gefunden. Eine Gegenüberstellung zwischen SVN- und Git-Befehlen kann man hier nachlesen.
Installation
Nun ging es an einen ersten Test. Dafür habe ich die Git-Version 1.7.4 von http://git-scm.com heruntergeladen und installiert. Die Installation von Git ist weitestgehend selbsterklärend. Nur die Einstellung “Line Ending Conversion” ist nicht ganz selbsterklärend. Wenn man vorhat, mittels Git auf ein SVN-Repository zuzugreifen, dann sollte man hier “Checkout as-is, commit as-is” wählen.
Testen
Nach der Installation findet man im Windows-Startmenü die “Git Bash”, also die Kommandozeile für Git. Dabei handelt es sich um eine Unix-like Shell für Windows. Die Navigation im Dateisystem läuft hier etwas anders als normalerweise unter Windows. So wechselt man mit “cd /d” auf das Laufwerk D:\, und mittels “ls” kann man sich den Inhalt des aktuellen Verzeichnisses auflisten.
Mit folgender Zeile kann man mittels “git svn” eine Kopie eines SVN-Repositories erstellen:
$ git svn clone http://localhost/svn/arxml -s Initialized empty Git repository in d:/git_test/arxml/.git/ r1 = 79ac10e9eacb0d38a1466fd2c834903afe81c2f8 (refs/remotes/trunk) A api.h A stdafx.h ... r18 = d28954ccd89dad6eedf1331a1f8609c01cf1ce7b (refs/remotes/trunk) Checked out HEAD: http://localhost/svn/arxml/trunk r18
Die Option “-s” am Ende des Befehls gibt an, dass es sich um eine Standard-SVN-Sturktur mit Unterverzeichnissen “branches”, “tags” und “trunk” handelt. Wenn man das nicht getan hat, sollte man die Option weglassen oder falls man andere Name gewählt hat kann man das über folgenden Befehl anpassen (wobei hier auch wieder die Standard-Namen eingesetzt wurden):
$ git svn clone http://localhost/svn/arxml -T trunk -b branches -t tags
Also gut. Mit dem Befehl haben wir ein Git-Repository erstellt und dieses mit dem Inhalt eines SVN-Repository gefüllt. Mittels cd wechseln wir nun in den neu erstellten Ordner. Nach dem “git svn clone” Befehl, wird normalerweise der master-Branch gewählt, welcher dem “trunk” entspricht (oder falls man die Option -s weggelassen hat, die oberste Ebene).
Wenn man also die Historie einsehen möchte:
$ git log
Hat man Änderungen an Dateien vorgenommen, kann man diese auch in das Repository übertragen.
$ git commit -am "added new usage instructions"
Da wir aber nun mit zwei Repositories arbeiten (lokal:Git und remote:SVN), hat der “git commit” Befehl lediglich die Änderung in das lokale Git-Repository geschrieben. Um auch das SVN-Repo zu aktualisieren, nutzt man “git svn dcommit”:
$ git svn dcommit Committing to http://localhost/svn/arxml ... M Main.cpp Committed r19 M Main.cpp r19 = 854e82f4860d474a9a5db7bca6746d101448e100 (trunk) No changes between current HEAD and refs/remotes/trunk Resetting to the latest refs/remotes/trunk
Unsere Änderung sind jetzt im SVN und die Revisionsnummer (r19) wurde im Git-Repository vermerkt. Jetzt kann es natürlich vorkommen, dass in der Zwischenzeit ein anderer Entwickler Änderungen in das SVN-Repo übertragen hat. In diesem Fall müssen die Änderungen vor dem “dcommit” in das Git-Repository geholt werden und das geht mit dem rebase-Befehl.
$ git svn rebase M notes.txt r20 = c373de5f458c76f3b0e2e5027cd92eebeaa0e55d (trunk) First, rewinding head to replay your work on top of it... Fast-forwarded master to refs/remotes/trunk.
Nun, das soll für’s erste reichen. Mehr Informationen zu den Befehlen findet man im git-svn-Manual.
Problem mit Zeilenenden
Etwas Schwierigkeiten hat mir später das automatische Konvertieren von Zeilenumbrüchen durch Git bereitet. Hier hat mir msysGit Issue 21 etwas weitergeholfen, wenn auch keine definitive Empfehlung gegeben. SVN kümmert sich normalerweise nicht um die Inhalte von Dateien (siehe svnredbook). D.h. wenn eine Datei unter Windows ins SVN übertragen wird, enthält die Datei im Normalfall CRLF Umbrüche. Installiert man jedoch Git mit den Standardeinstellungen (core.autocrlf = true), dann wird jede Textdatei im Repository ins Unix-Style-LineEnding-Format (also LF) konvertiert. Bei der ausschließlichen Nutzung von Git ist das sicherlich die beste Wahl. Wenn man jedoch mittels Git auf SVN zugreift, führt das automatische Umwandel zu Problemen (zumindest war es bei mir der Fall). Hat man wie weiter oben geschrieben ein SVN-Repo mittels “git svn” geklont und überträgt Änderungen (bei core.autocrlf=true) in das Git-Repository, dann enthält die Datei im Git-Repo lediglich LF-Umbrüche. Überträgt man diese Datei ins SVN, kann es dazu führen, dass jede Zeile als geändert markiert wird. Es ist also wichtig zu wissen, welche Zeilenumbrüche in den Dateien des SVN-Repo’s normalerweise verwendet werden.
Viele Texteditor können mittlerweile mit den verschiedenen Zeilenumbrüchen umgehen. Deswegen könnte man schnell annehmen, dass es doch egal ist in, welche Umbrüche in der Datei verwendet werden. Fakt ist jedoch, das viele andere Tools (wie z.B. Compiler, Parser) häufig erwarten, dass in den Eingabedateien Zeilenumbrüche des jeweiligen Betriebssystems verwendet werden. Aus diesem Grund ist auch die autocrlf-Variable durchaus sinnvoll. Jedoch kann aus dem gleichen Grund keine allgemeine Festlegung für die Standardeinstellung von core.autocrlf gegeben werden. Je nach Projekt, eingesetzten Betriebssystemen und SVN-Konfiguration kann eine andere Wahl sinnvoll sein. Für meine spezifischen Fall (SVN-Clients = Windows), muss autocrlf auf “false” gesetzt werden.
Jetzt nochmal, nur einfacher
Das ganze Arbeiten in der “Git-Bash” ist ja schön und gut. Hilft auf jeden Fall dabei, die Arbeitsweise von Git besser zu verstehen. Aber wer TotoiseSVN kennen und lieben gelernt hat, wird nur ungern darauf verzichten wollen. Zum Glück haben das ein paar Entwickler frühzeitig erkannt. TortoiseGit für Klicki-Bunties.
Installationsreihenfolge
- Git für Windows installieren
(hier sollte man während der Installation die Explorer-Context-Menü Erweiterungen deaktivieren) - TortoiseGit installieren
Testen, die zweite
Nach der Installation wollen wir nochmal das SVN-Repo klonen. Nur um die Möglichkeit mittels TortoiseGit zu testen. Notwendig ist es eigentlich nicht. Man kann mit dem über Git-Bash erstellten Repo auch einfach weiterarbeiten. Ich habe daher zunächst das Verzeichnis “D:\git_test” wieder geleert. Im leeren Ordner öffnet man das Kontext-Menü und wählt dort “Git Clone”.
Im folgenden Dialog gibt man das SVN-Repository an und achtet darauf im unteren Bereich die Option “From SVN Repository” zu aktivieren.
Wichtig: Wenn auf ein SVN-Repo zugegriffen wird, das beim Commit eine Authentifizierung erwartet, dann sollte man den Usernamen schon beim Clonen mit angeben (im Dialog unten rechts). Später erscheint nur noch eine Passwortabfrage und wenn vorher kein Nutzer angegeben wurde, dann verwendet das System den Usernamen vom OS-Login. In der Version 1.7.3 von TortoiseGit habe ich keine Möglichkeit gefunden, den Usernamen nachträglich anzupassen. Der Benutzername und das Passwort werden von git-svn in einer Datei unter “%USERPROFILE%\.subversion\auth\svn.simple” gespeichert. Aber manuell anlegen sollte man diese Datei nicht, und selbst bei Änderungen sollte man wissen was man tut.
Ok, zurück zum Test. Das Clonen startet direkt nach dem Klick auf “Ok”. Wenn dieser Vorgang abgeschlossen ist, stehen über das Kontextmenü im Explorer weitere Funktionen zur Verfügung. So kann man sich z.B. die Historie in einer grafischen Oberfläche anschauen und vorgenommene Änderungen einsehen. Auch werden die Dateien mit einem kleinen Symbol überlagert, so dass man direkt im Explorer geänderte oder hinzugekommene Dateien erkennen kann. Wer TortoiseSVN kennt, wird sich recht schnell zurechfinden.
Im Menü finden sich alle Aktionen wieder, die wir vorher auch schon in das Git-Bash ausgeführt haben. Das sind:
Git Commit
Änderungen ins Git-Repo speichern
SVN DCommit
Änderungen aus dem Git-Repo in das SVN-Repo übertragen
SVN Rebase
Änderungen aus dem SVN-Repo ins lokale Git-Repo holen
Switch/Checkout
Zu einen anderen Branch/Trunk/Tag wechseln
Fazit
Immer wieder schreckt man vor Neuem zurück. Zum einen aus Gewohnheit und zum anderen weil es einem eine Menge Zeit kosten kann. Doch mit Git und dessen Subversion-Unterstützung sollte man auf keine Fall zögern. Die Tools sind weitestgehend ausgereift und arbeiten problemlos mit Subversion zusammen. Gedanken sollte man sich kurz um die Zeilenumbrüche machen, um nicht später Schwierigkeiten mit anderen Nutzern zu bekommen. Auch ist das Thema SVN-Authentifizierung in TortoiseGit noch verbesserungswürdig. Mit der Arbeitsweise von Git sollte man sich auf jeden Fall vertraut machen. Irgendwann wechselt man mit Sicherheit komplett von SVN zu einem verteilten Versionsverwaltungssystem.
Es gibt natürlich eine Reihe von Editoren und Tools, die eine direkte SVN-Integration unterstützen. Für die Größeren und Bekannteren gibt es auch Git-Integrationen. In manchen Bereichen sind die SVN-Integrationen jedoch im Funktionsumfang etwas voraus. Aber das kann sich ja noch Ändern und soll auch nicht Gegenstand dieses Artikels sein.
Links
Git-SCM
TortoiseGit
ProGit Book
git Manual
git svn Manual