Es geht weiter mit dem Projekt git. Dieses mal will ich vorhandene Subversion-Repositories nach git umziehen. Es gibt dazu bereits ein paar Anleitungen, aber nochmal für mich das Ganze zusammen zu schreiben kann sicherlich nicht schaden. Außerdem muss ich zugeben, dass ich das wirklich erst mehrere Male ausprobieren musste, bis ich einen Weg hatte, der dann auch sicher funktioniert hat. Das ist nebenbei auch eine gute Übung, um ein bisschen den Umgang mit git zu lernen und ein bisschen zu Testen.

Zuerst benötigen wir eine Erweiterung für git, damit git auf Subversion zugreifen kann. Diese kann man einfach über den Paketmanager installieren:

sudo apt-get update
sudo apt-get install git-svn

Dann gibt es einen kleinen Unterschied zwischen Subversion und git, den man berücksichtigen muss. Die Benutzerinformationen von git sind nämlich ausführlicher als die von Subversion. Man muss also erst einmal die Benutzerinformationen von Subversion entsprechend erweitern, so dass git was damit anfangen kann.
In Subversion wird lediglich ein Benutzername gespeichert. Dagegen wird in Git neben dem Bentzernamen auch noch der vollständige Name und die Emailadresse hinterlegt.
Man extrahiert also die Benutzernamen aus subversion und konvertiert sie in das für git notwendige Format. Dazu geht man in die lokal ausgecheckte WorkingCopy und verwendet folgenden Befehl:

svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors.txt

In der Datei authors.txt stehen dann alle Benutzernamen in folgender Form:

name = name <name>

Korrekt wäre jetzt eine vollständige Angabe in der Form:

name = Max Mustermann <max.mustermann@domain.de>

Man kommt also leider nicht darum rum, dass man diese erstellte Textdatei mit einem Texteditor überarbeitet und entsprechend vervollständigt.
Die Datei speichern wir dann am besten in den Ordner /tmp.

Jetzt geht’s los, dass wir das Subversion-Repository in ein lokales Git-Repository clonen:

git svn clone svn://subversion.server.de/sample --no-metadata -A /tmp/authors.txt -R head \
    --trunk=/CURRENT --branches=/BRANCHES /tmp/sample

Hier noch eine kleine Erklärung zu den Parametern:
Mit dem Parameter -A können wir die vorher erstellte Benutzerdatei heranziehen, damit die einzelnen Commits eine vernünftige Benutzer-Information erhalten.
Der Parameter -R head gibt an, dass man die HEAD-Revision haben will. Man kann damit auch auf bestimmte Revisions eingrenzen, so dass man nicht das gesamte Repository konvertiert, sondern nur einen Teil.
Interessant sind die Parameter –trunk, –branches und –tags (den ich hier nicht angegeben habe). Damit kann man seine eigene Projekt-Struktur angeben. Eine andere Möglichkeit ist der Parameter –stdlayout.
Mit Standard-Layout wird das von Subversion empfohlene Layout gemeint. Dieses sieht vor, dass man die Ordner trunk, branches und tags verwendet. Jetzt kann man die Ordner aber bei Subversion benennen wie man will und genau das kann man mit den von mir verwendeten Parameters dann darstellen.
Ich persönlich verwende zum Beispiel in der Regel nur die Ordner CURRENT und BRANCHES.

Jetzt haben wir im Ordner /tmp/sample ein lokales git-Repository mit den entsprechenden Daten. In dieses Verzeichnis navigieren wir jetzt mal und schauen, was für Branches die Konvertierung gefunden hat.

cd /tmp/sample
git branch -a

Ausgabe:

* master
remotes/origin/1
remotes/origin/trunk

Dann legen wir mal ein leeres Repository auf unserem gitolite-Server an. Das heißt, wir checken erst einmal die Administration aus und tragen das neue Repository in die Config-Datei ein:

git clone gitadmin:gitolite-admin /tmp/gitolite-admin
cd /tmp/gitolite-admin
nano conf/gitolite.conf

Der Eintrag sieht so aus:

repo svnsample
    RW+     =   jon_dow

Das Ganze dann wieder zum Server pushen

git add --all
git commit -m 'new reporitory svnsample'
git push

Jetzt gibt es ein kleines Problem, dass man direkt am git-Server lösen muss. git verwendet als HEAD-Revision in der Regel den Branch mit dem Namen master, während bei Subversion die HEAD-Revision trunk heißt. Damit die Daten korrekt zugeordnet werden, muss man git sagen, dass HEAD auf refs/heads/trunk zeigen soll.
Dazu melden wir uns per ssh am gitolite-Server an und navigieren in das Verzeichnis des Repositories:

sudo su -u git
cd repositories/svnsample.git
git symbolic-ref HEAD refs/heads/trunk

Ein kleiner Hinweis dabei: Wenn man den letzten Parameter (refs/heads/trunk) bei diesem Kommando weglässt, wird ausgegeben, worauf HEAD aktuell zeigt. So kann man also auch prüfen, ob alles passt.

Jetzt geht’s wieder weiter am Client im Verzeichnis unseres konvertierten Repositories. Wir bauen jetzt die Verbindung zum Server auf und pushen das Repository auf den Server:

git remote add bare git@<server>:svnsample
git config remote.bare.push 'refs/remotes/origin/*:refs/heads/*'
git push bare

Das war’s und wir haben jetzt unser erstes Repository inklusiv Branches auf unserem gitolite-Server.
Es gibt noch eine Kleinigkeit, die man anpassen sollte. Bei einem Standard-Repository wird das HEAD-Repository master genannt. Wenn man sich jetzt die Branches aber ausgeben lässt, sieht man, dass es kein master gibt. Stattdessen gibt es trunk.
Damit das einheitlich aussieht und auch langfristig keine Probleme gibt, sollte man diesen Branch noch umbenennen. Dazu verbinden wir uns nochmal per ssh mit unserem gitolite-Server und navigieren in das Repository samplesvn.git und geben dann dort folgenden Befehl ein:

git branch -m trunk master

Jetzt sind wir aber endgültig fertig. Man kann jetzt das Repository wie gewohnt auschecken und kann zwischen den verschiedenen Branches hin- und herwechseln.