====== Migration von Subversion nach Git ====== * Urspruenglicher Autor: Dirk Deimeke * Urspruengliches Datum: 18.11.2011 Aus verschiedenen Gruenden wollte ich unsere [[https://secure.wikimedia.org/wikipedia/de/wiki/Apache_Subversion|Subversion]]-Repositories nach [[https://secure.wikimedia.org/wikipedia/de/wiki/Git|Git]] migrieren. Die Entscheidung dafuer war unabhaengig davon, dass zwei Projekte, naemlich [[http://michael-prokop.at/blog/2011/11/05/fai-switch-from-subversion-to-git/|FAI]] und [[http://blog.s9y.org/archives/236-Details-about-the-GitHub-migration-process,-developers-please-read!.html|Serendipity]], etwa zur gleichen Zeit migriert sind. Git ist ein [[https://secure.wikimedia.org/wikipedia/de/wiki/Verteiltes_Versionskontrollsystem#Verteilte_Versionsverwaltung|verteiltes Versionskontrollsystem]] (DVCS) - in der gleichen Liga spielen auch [[https://secure.wikimedia.org/wikipedia/de/wiki/Bazaar|Bazaar]] und [[https://secure.wikimedia.org/wikipedia/de/wiki/Mercurial|Mercurial]], wobei das "verteilt" nicht der Grund fuer den Wechsel war. Neben der komprimierten Speicherung und bandbreitenschonenden Uebertragung, spielen die neuen Systeme ihre Staerken vor allem im intelligenten Zusammenfuehren (merging) von unterschiedlichen Versionen aus. Weitere Vorteile sind (die Liste ist nicht komplett): * Es gibt kaum ein System, was besser dokumentiert waere. * Kleinerer Administrationsaufwand. * Sparen eines Apache-Moduls * Alle haben die komplette Historie lokal und koennen auch ohne Server arbeiten. * Alle koennen beliebig oft lokal committen und alle Aenderungen erst dann uebertragen, wenn der eigene Teil fertig ist. Einen sehr guten Einstieg in verteilte Versionskontrollsysteme und insbesondere Git bietet die [[http://chaosradio.ccc.de/cre130.html|Ausgabe 130 von Chaosradio Express]]. Subversion wurde bei uns ueber ''dav_svn'', ein Modul des Webservers, benutzt. Die Migration musste also in drei Schritten passieren, zuerst die Serverseite, um die Infrastruktur zur Verfügung zu stellen, danach die Migration der bestehenden Projekte und zum Schluss die Umstellung der Clients. Da Taskwarrior [[https://github.com/mzupan/gitosis|Gitosis]] einsetzt und ich so immer jemanden habe, den ich fragen kann, habe ich mich fuer Gitosis auf der Serverseite entschieden. Dafuer gibt es bereits eine [[http://netzaffe.de/git-gitosis-gitweb-the-debian-way.html|sehr gute Anleitung]], die ich leider ziemlich unuebersichtlich finde, daher fuehre ich hier noch einmal die einzelnen Schritte auf. Unsere Server laufen auf Ubuntu 10.04 LTS und ich bin strikt nach Anleitung vorgegangen. sudo aptitude install git-core gitosis Erzeugt einen User "gitosis" und die nötigen Verzeichnisse unter ''/srv/gitosis'' Danach muss ich den eigenen oeffentlichen SSH-Schluessel auf den Server kopieren und damit das Administrations-Repository initialisieren (darin wird die ganze Konfiguration gemacht). dirk@client$ scp .ssh/id_rsa.pub server:/tmp/dirk@client.pub dirk@server$ sudo -H -u gitosis gitosis-init < /tmp/dirk@client.pub Damit ist die serverseitige Einrichtung bereits abgeschlossen. Unglaublich aber wahr. Was nicht in der Anleitung steht, jetzt aber lokal erledigt werden sollte, da commits in Git immer Usernamen und E-Mail-Adresse enthalten: git config --global user.name "John Doe" git config --global user.email "john@doe.com" git config --global color.ui always Der letzte Befehl ist nicht wichtig, der macht es nur huebsch. Jetzt kann das gerade angelegte Adminrepository ausgechecked werden: git clone gitosis@server:gitosis-admin.git gitosis-admin-server.git Das letzte in der Kommandozeile ist der Name, wie das Verzeichnis lokal heissen soll. Ich habe ein "-server.git" hinzugefügt, da das Verzeichnis sonst nur "gitosis-admin" geheissen haette. Jetzt können der Admingruppe weitere User hinzugefügt werden. In ''gitosis.conf'' stand am Anfang nur ''dirk@client'': [group gitosis-admin] writable = gitosis-admin members = dirk@client dirk@workstation Im Verzeichnis ''keydir'' sind die ganzen Schluessel zu finden. ''dirk@client.pub'' war schon vorher enthalten. ls -l keydir/ total 12 -rw-r--r-- 1 dirk dirk 393 Nov 4 10:50 dirk@client.pub -rw-r--r-- 1 dirk dirk 395 Nov 4 10:54 dirk@workstation.pub Die Aenderungen werden jetzt an den Server uebertragen. git add keydir/dirk@workstation.pub git commit -a -m "User dirk@workstation hinzugefuegt" git push Git verhaelt sich ein bisschen anders als Subversion. * Bei einem "git commit" passiert gar nichts, auch wenn sich Dateien veraendert haben. * git add datei ; git commit -m "nachricht" oder git commit -a -m "nachricht" * letzterer nimmt alle Dateien in den Commit, die bereits unter Versionskontrolle stehen und sich veraendert haben * Der Commit ist lokal, erst "git push" uebertraegt die Änderungen zum Server * Analog dazu synchronisiert sich "git pull" mit dem Server Ein neues Repository auf dem Server legt man wie folgt an. Zuerst traegt man es in die gitosis.conf ein. [group playground] writable = playground members = dirk@client dirk@workstation Danach uebertraegt man die neue Konfiguration auf den Server. $ git commit -a -m "playground erzeugt" [master 8a62406] playground erzeugt 1 files changed, 4 insertions(+), 0 deletions(-) $ git push Counting objects: 5, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 375 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To gitosis@foo:gitosis-admin.git 4755284..8a62406 master -> master Wir initialisieren das Repositories (ebenfalls lokal): $ git clone gitosis@server:playground.git playground-server.git Cloning into playground-server.git... Initialized empty Git repository in /srv/gitosis/repositories/playground.git/ warning: You appear to have cloned an empty repository. $ cd playground-foo.git/ $ touch foo $ git add . $ git commit -m "init" [master (root-commit) 8b70e1d] init 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 server $ git push origin master Counting objects: 3, done. Writing objects: 100% (3/3), 197 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To gitosis@server:playground.git * [new branch] master -> master Nachdem das alles funktioniert, koennen die Subversion-Repositories migriert werden, [[http://progit.org/book/ch8-2.html|Anleitung]] dazu im freien [[http://progit.org/book/|Buch Pro Git]]. Subversion nutzt Usernamen um die Commits zu kennzeichnen, Git nutzt reale Namen und E-Mail-Adressen, damit ist der erste Schritt klar, wir brauchen eine Liste der User, die schon in unser Repository geschrieben haben und muessen diese mit Realnamen abgleichen. $ svn log --xml | grep author | sort -u | perl -pe 's/.>(.?)<./$1 = /' Mit dem obigen Befehl bekommt man alle Committer aus einem Subversion-Repository, damit laesst sich eine Datei ''users.txt'' aufbauen, in der die Usernamen und die Git-Namen zu finden sind. Ich habe das auch zur Konsolidierrung benutzt. dirk = Dirk Deimeke lux = Dirk Deimeke user = Vorname Nachname Mit dieser Vorarbeit ist es bereits moeglich, das Subversion-Repository zu klonen und zu konvertieren (ACHTUNG: Unterschied zum Buch, bei mir hat die Option ''-s'' nicht funktioniert, da ich kein Standard-Layout verwendet habe und statt ''git-svn'' habe ich ''git svn'' benutzt). $ git svn clone http://my-project.googlecode.com/svn/ \ --authors-file=users.txt --no-metadata my_project Jetzt gilt es noch, Aufraeumarbeiten durchzufuehren. Zuerst machen wir aus den Tags von Subversion Git Tags. $ cp -Rf .git/refs/remotes/tags/* .git/refs/tags/ $ rm -Rf .git/refs/remotes/tags Als naechstes machen wir aus den remote Referenzen lokale Branches: $ cp -Rf .git/refs/remotes/* .git/refs/heads/ $ rm -Rf .git/refs/remotes So, jetzt muessen wir das ganze noch hochladen. $ git remote add origin git@my-git-server:myrepository.git Und, weil wir alles uebertragen wollen, geht es mit dem folgenden Kommando los: $ git push origin --all Fertig! Ich hatte bei der Migration mit einem groesseren Problem zu kaempfen. Mein privates Repository hat ueber 2000 commits und einige Gigabytes an Daten. Das hat meinen lokalen Rechner in die Knie gezwungen, da waren 4 GB Speicher zu knapp. Ich habe die Migration kurzerhand auf einem Server mit 8 GB RAM laufen lassen, das ging. Alternativ dazu kann man aber mit ''git-svn'' die Migration haeppchenweise durchfuehren. Mit ''git svn clone -r0:100'' (und den anderen Optionen weiter oben) werden nur die ersten 100 Commits geklont, dann macht man mit ''-r100:200'' weiter bis man letztendlich fertig ist. Es gibt einen sehr guten [[http://git.or.cz/course/svn.html|Git - SVN Crash Course]], daher fuehre ich hier nur die Unterschiede der haeufigsten Kommandos an. * git clone ersetzt svn checkout * git pull ersetzt svn update * git add mach das gleiche wie svn add * git commit -a (oder git commit -am) ersetzt svn commit bzw. svn commit -m * UNTERSCHIED: git push uebertraegt die lokalen Commits erst auf den Server [[adminstoriesartikel|Zurück zur Uebersicht]]