{"id":808,"date":"2012-06-24T13:37:17","date_gmt":"2012-06-24T11:37:17","guid":{"rendered":"http:\/\/blog.speedyj.de\/?p=808"},"modified":"2014-07-08T21:35:39","modified_gmt":"2014-07-08T19:35:39","slug":"svn-repos-auf-eigenen-git-server-migrieren","status":"publish","type":"post","link":"https:\/\/blog.speedyj.de\/?p=808","title":{"rendered":"SVN-Repos auf eigenen Git Server migrieren"},"content":{"rendered":"<p>Vor einer Weile hatte hatte ich mir einen <a title=\"SVN &amp; WAMP\" href=\"http:\/\/blog.speedyj.de\/?p=349\">SVN Server mittels WAMP<\/a> zusammengebastelt. Die L\u00f6sung l\u00e4uft bei mir aktuell immer noch, obwohl ich schon seit einer Weile <a title=\"SVN und GIT nutzen\" href=\"http:\/\/blog.speedyj.de\/?p=651\">auf lokale GIT Repositories gewechselt bin<\/a>. Das hat es mir erm\u00f6glicht, jederzeit und unterwegs mit dem Repository zu arbeiten, also Verlauf einsehen und \u00c4nderungen einchecken, und sobald ich wieder netzwerktechnisch auf mein SVN zugreifen konnte, wurden die durchgef\u00fchrten Commits einfach ins SVN \u00fcbertragen. Den SVN-Server durch einen GIT &#8222;Server&#8220; zu ersetzen, war mir bisher zu aufwendig.<\/p>\n<p>Die Tage bin ich dann \u00fcber <a href=\"http:\/\/gitblit.com\/\" target=\"_blank\">gitblit<\/a> gestolpert. Dabei handelt es sich um ein Tool, in dem man einfach seine GIT Repositories hosten und auch f\u00fcr andere zug\u00e4nglich machen kann. Das ganze kommt mit einem \u00fcbersichtlichen Webfrontend daher, kurz gesagt: scheinbar ein perfekter Ersatz f\u00fcr meinen SVN Server.<\/p>\n<p><strong>Installation<\/strong><\/p>\n<p>gitblit gibt es in verschiedenen Download-Varianten. Die &#8222;GO&#8220; Variant beinhaltet alles was man braucht um direkt loszulegen, kommt dabei &#8222;aber&#8220; mit einem eigenen Jetty Webserver daher. Da ich eher einen lokalen Tomcat verwenden m\u00f6chte, habe ich mir einfach die WAR-Datei (Web Archive) heruntergeladen.<\/p>\n<p>Der Tomcat liegt bei mir unter D:\\temp\\apache-tomcat-7.0.28, d.h. die WAR-Datei wird in das Unterverzeichnis &#8222;webapps\\gitblit&#8220; entpackt. \u00c4nderungen an den Einstellungen habe ich f\u00fcr meinen Test keine vorgenommen. Die vollst\u00e4ndige Einrichtung erledige ich wenn ich genug getestet habe. Zum Abschluss sollte man pr\u00fcfen, ob der Tomcat auch gestartet ist.<\/p>\n<p>Tja, das war es eigentlich auch schon. Wenn man jetzt im Webbrowser die Adresse http:\/\/localhost:8080\/gitblit\/ aufruft, bekommt man folgende Seite zu Gesicht.<\/p>\n<p><a href=\"http:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblit-start.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-810\" title=\"gitblit-start\" alt=\"\" src=\"http:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblit-start-300x102.png\" width=\"300\" height=\"102\" srcset=\"https:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblit-start-300x102.png 300w, https:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblit-start.png 1000w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><strong>Erste Schritte<\/strong><\/p>\n<p>F\u00fcr die Verwaltung der Repositories muss man sich anmelden. Einfach oben rechts mit Benutzer admin und Passwort admin anmelden. Jetzt bekommt man zus\u00e4tzliche Navigationspunkte und Funktionen angezeigt.<\/p>\n<p><a href=\"http:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblit-loggedin.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-811\" title=\"gitblit-loggedin\" alt=\"\" src=\"http:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblit-loggedin-300x95.png\" width=\"300\" height=\"95\" srcset=\"https:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblit-loggedin-300x95.png 300w, https:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblit-loggedin.png 1000w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Etwa rechts in der Mitte (also oberhalb der leeren Repository-Liste) hat man die M\u00f6glichkeit ein neues Repository anzulegen. Mit einem Klick auf &#8222;new repository&#8220; gelangt man zu einer Seite mit vielen Einstellungen. Ich gebe nur ins erste Feld den Name &#8222;test&#8220; ein und klicke ganz unten auf &#8222;Save&#8220;. Damit habe ich ein neues Repository angelegt und das wird jetzt in der \u00dcbersicht als leer angezeigt. Jetzt muss man seinem lokalen Git-Repository nur noch den neuen Remote-Server mitteilen, und schon kann man mittels Push das Repo auf den Server \u00fcbertragen. Die notwendigen Schritte\/Befehle werden direkt im gitblit-Frontend angezeigt. Einfacher geht es nicht.<\/p>\n<p><strong>SVN Migration<\/strong><\/p>\n<p>Als n\u00e4chstes m\u00f6chte ich eines meiner SVN-Repositories in das eben erstellte importieren. Das gestaltet sich nicht ganz so einfach, da man mehrere Dinge beachten sollte:<\/p>\n<ol>\n<li>Man ben\u00f6tigt ein Author-Mapping, damit die Namen aus dem SVN-Repository nicht verloren gehen<\/li>\n<li>Alle SVN-Branches m\u00fcssen in Git als Branch angelegt werden<\/li>\n<li>Alle SVN-Tags m\u00fcssen in Git angelegt werden<\/li>\n<\/ol>\n<p>Zum Gl\u00fcck muss ich mir nicht alles selbst zusammensuchen und kann auf <a href=\"http:\/\/jausoft.com\/blog\/2009\/07\/08\/svn-to-git-migration-1\/\" target=\"_blank\">Hilfe auf dem Internet<\/a> zugreifen. S\u00e4mtliche nun folgenden Arbeiten f\u00fchre ich in der &#8222;Git Bash&#8220; aus, die man ja eigentlich intstalliert hat, wenn man mit Git unter Windows arbeitet. Wenn nicht, dann <a href=\"http:\/\/code.google.com\/p\/msysgit\/\" target=\"_blank\">msysGit<\/a> installieren.<\/p>\n<p><strong>Author Mapping<\/strong><\/p>\n<p>Um \u00fcberhaupt an die eine Liste der Authoren heranzukommen, greift man am Besten auf ein kleines Bash-Script zur\u00fcck. Das in <a href=\"http:\/\/jausoft.com\/blog\/2009\/07\/08\/svn-to-git-migration-1\/\" target=\"_blank\">Sven&#8217;s Blog<\/a> bereitgestellte Skript, musste ich leicht anpassen, da es a) mit Leerzeichen in Authoren nicht klar kam und b) ein lokales SVN-Repository ben\u00f6tigte. An die ge\u00e4nderte Version kann ich einfach eine URL zum SVN-Server \u00fcbergeben und schon bekomme ich eine Liste der Authoren. Hier das ge\u00e4nderte Script &#8222;svn_author_export.sh&#8220; (Download weiter unten):<\/p>\n<pre style=\"padding-left: 30px; color: #888;\"><span style=\"color: #888888;\">#!\/bin\/bash<\/span>\r\n<span>IFS=$(echo -en \"\\n\\b\")<\/span>\r\n<span>authors=$(svn log -q $1 | grep -e '^r' | awk 'BEGIN { FS = \"|\" } ; { print $2 }' | sort | uniq)<\/span>\r\n<span>for author in ${authors}; do<\/span>\r\n<span>\u00a0 echo \"${author} = ${author} &lt;${author}@domain.com&gt;\" &gt;&gt; svn.authors ;<\/span>\r\n<span>done<\/span><\/pre>\n<p>Der Aufruf sieht dann wie folgt aus:<\/p>\n<pre style=\"padding-left: 30px;\"><span style=\"color: #888888;\">.\/svn_author_export.sh http:\/\/localhost\/svn\/svnGitTest<\/span><\/pre>\n<p>Im lokalen Verzeichnis gibt es nach dem Ausf\u00fchren eine Datei namens &#8222;svn.authors&#8220;, die man jetzt entsprechend anpassen sollte.<\/p>\n<p><strong>SVN Repository clonen<\/strong><\/p>\n<p>Das eben erstellte Author-Mapping kommt beim Clonen des SVN-Repositories zum Einsatz.<\/p>\n<pre style=\"padding-left: 30px;\"><span style=\"color: #888888;\">git svn --authors-file=.\/svn.authors clone -s http:\/\/localhost\/svn\/svnGitTest<\/span><\/pre>\n<p>Jetzt hat man ein lokales Git-Repository mit s\u00e4mtlichen Commits aus dem SVN und den entsprechend gemappten Author-Namen\/Emailadressen. Das kann man durch einen Blick ins &#8222;git log&#8220; \u00fcberpr\u00fcfen.<\/p>\n<p><strong>Repository migrieren<\/strong><\/p>\n<p>Nachdem man das SVN-Repository nach Git geclont hat, sind einige Aufr\u00e4umarbeiten notwendig. So muss man f\u00fcr jede SVN-Branch auch eine lokale Git-Branch erstellen, und auch die Tags aus dem SVN korrekt \u00fcbernehmen. Um diesen Schritt zu automatisieren habe ich ein kleines Script gebastelt (Download weiter unten):<\/p>\n<pre style=\"padding-left: 30px;\"><span style=\"color: #888888;\">#!\/bin\/bash<\/span>\r\n<span style=\"color: #888888;\">branches=$(git branch -a | grep -e ' remotes\/' | awk -F: '{print substr($0, 3)}')<\/span>\r\n<span style=\"color: #888888;\">for branch in ${branches}; do<\/span>\r\n<span style=\"color: #888888;\">\u00a0 tagName=$(expr \"$branch\" : \"remotes\/tags\/\\(.*\\)\")<\/span>\r\n<span style=\"color: #888888;\">\u00a0 branchName=$(expr \"$branch\" : \"remotes\/\\(.*\\)\")<\/span>\r\n<span style=\"color: #888888;\">\u00a0 if [ -n \"$tagName\" ]; then<\/span>\r\n<span style=\"color: #888888;\">\u00a0\u00a0\u00a0 git checkout -b tag_\"$tagName\" remotes\/tags\/$tagName<\/span>\r\n<span style=\"color: #888888;\">\u00a0\u00a0\u00a0 git tag $tagName tag_\"$tagName\"<\/span>\r\n<span style=\"color: #888888;\">\u00a0\u00a0 \u00a0git checkout master<\/span>\r\n<span style=\"color: #888888;\">\u00a0\u00a0 \u00a0git branch -D tag_\"$tagName\"<\/span>\r\n<span style=\"color: #888888;\">\u00a0\u00a0 \u00a0git branch -D -r tags\/$tagName<\/span>\r\n<span style=\"color: #888888;\">\u00a0 else <\/span>\r\n<span style=\"color: #888888;\">\u00a0\u00a0\u00a0 if [ \"$branchName\" != \"trunk\" ]; then<\/span>\r\n<span style=\"color: #888888;\">\u00a0\u00a0\u00a0\u00a0\u00a0 git checkout -b $branchName remotes\/$branchName<\/span>\r\n<span style=\"color: #888888;\">\u00a0\u00a0 \u00a0fi<\/span>\r\n<span style=\"color: #888888;\">\u00a0\u00a0 \u00a0git checkout master<\/span>\r\n<span style=\"color: #888888;\">\u00a0\u00a0 \u00a0git branch -D -r $branchName<\/span>\r\n<span style=\"color: #888888;\">\u00a0 fi<\/span>\r\n<span style=\"color: #888888;\">done<\/span><\/pre>\n<p>Ok, was passiert in diesem Script?<\/p>\n<ol>\n<li>Zun\u00e4chst werden alle Remote-Branches ermittelt<\/li>\n<li>Dann wird unterschieden, ob es sich um einen Tag oder eine echte Branch handelt<\/li>\n<li>Bei Tags wird tempor\u00e4r eine Branch (basierend auf dem Remote-Tag) angelegt und darauf ein entsprechender Tag erzeugt.<\/li>\n<li>Bei Branches wird einfach eine entsprechende Branch angelegt (au\u00dfer f\u00fcr die Remote-Branch &#8222;remotes\/trunk&#8220;)<\/li>\n<li>&#8230; und nebenbei werden alle Remote-Branches gel\u00f6scht, also das Repository vom SVN abgekoppelt.<\/li>\n<\/ol>\n<p>Jetzt sollte man genau pr\u00fcfen, ob irgendwelche Fehler aufgetreten sind. Falls etwas schief gegangen ist, hilft es meist nur,\u00a0 das gesamte Repository frisch aus dem SVN zu clonen (oder man hat sich vorher ein Backup vom Verzeichnis gemacht). Ggf. sollte man den 5ten Schritt weglassen, wenn man sein SVN- und den Git-Server parallel laufen und Commits zwischen beiden syncronisieren lassen m\u00f6chte.<\/p>\n<p><strong>Auf den Server \u00fcbertragen<\/strong><\/p>\n<p>Nun ist es an der Zeit unser Repository auf den Server zu \u00fcbertragen. Dazu m\u00fcssen wir unserem lokalen Git-Repository erstmal ein neues Remote mitteilen und dann unsere Branches und Tags pushen.<\/p>\n<pre style=\"padding-left: 30px;\"><span style=\"color: #888888;\">git remote add gitblit http:\/\/localhost:8080\/gitblit\/git\/svnGitTest.git<\/span>\r\n<span style=\"color: #888888;\">git push gitblit master work_test work_new work_experimental first_tag<\/span><\/pre>\n<p>Das kann nat\u00fcrlich wieder aufw\u00e4ndig werden, wenn man sehr viele Branches\/Tags hat. Daf\u00fcr kann man aber auch ein kleines Script (commit_all_branches_and_tags.sh) benutzen.<\/p>\n<p><a href=\"http:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitpush2gitblit.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-821\" title=\"gitpush2gitblit\" alt=\"\" src=\"http:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitpush2gitblit-300x142.png\" width=\"300\" height=\"142\" srcset=\"https:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitpush2gitblit-300x142.png 300w, https:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitpush2gitblit.png 677w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Wie man sieht, ermittelt das Script selbstst\u00e4ndig alle Branches und Tags und puscht diese an das Remote mit dem Namen &#8222;gitblit&#8220;. Wenn ein anderer Name f\u00fcr den Remote verwendet wurde, dann kann man den Namen einfach als ersten Parameter an das Script \u00fcbergeben. Hier noch das Script (Download weiter unten):<\/p>\n<pre style=\"padding-left: 30px;\"><span style=\"color: #888888;\">#!\/bin\/bash<\/span>\r\n<span style=\"color: #888888;\">remote=\"gitblit\"<\/span>\r\n<span style=\"color: #888888;\">if [ -n \"$1\" ]; then<\/span>\r\n<span style=\"color: #888888;\">\u00a0 remote=$1<\/span>\r\n<span style=\"color: #888888;\">fi<\/span>\r\n<span style=\"color: #888888;\">branches=$(git branch | awk -F: '{print substr($0, 3)}')<\/span>\r\n<span style=\"color: #888888;\">tags=$(git tag)<\/span>\r\n<span style=\"color: #888888;\">entries=\"${branches} ${tags}\"<\/span>\r\n<span style=\"color: #888888;\">entries=${entries[*]}<\/span>\r\n<span style=\"color: #888888;\">echo \"Committing: ${entries}\" <\/span>\r\n<span style=\"color: #888888;\">git push ${remote} ${entries}<\/span><\/pre>\n<p>Jetzt kann man sich auch das Ergebnis im Webfrontend anschauen oder sich das Repository auf einen anderen Rechner clonen.<\/p>\n<p><a href=\"http:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblitafterpush.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-822\" title=\"gitblitafterpush\" alt=\"\" src=\"http:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblitafterpush-300x283.png\" width=\"300\" height=\"283\" srcset=\"https:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblitafterpush-300x283.png 300w, https:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/gitblitafterpush.png 969w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p><strong>Zusammenfassung<\/strong><\/p>\n<p>Auch wenn das Migrieren im ersten Moment doch etwas aufw\u00e4ndig erscheint, kann man mit wenigen Handgriffen oder durch die Verwendung von Scripts recht schnell zum Ziel gelangen. Grad der in die Scripte gesteckte Aufwand wird sich bei der Migration der weiteren Repositories auszahlen. Ob man bei der Migration gitblit oder eine andere L\u00f6sung aufbaut &#8212; in beiden F\u00e4llen kann ich hier wieder auf die Scripte und Vorgehensweise zur\u00fcckgreifen.<\/p>\n<p>Eine kleine \u00c4nderung an der Konfiguration von gitblit musste ich dann doch vornehmen. Bei Branches und Tags wurde im Webfrontend nur eine leere Seite angezeigt. Das Problem ist aber <a href=\"http:\/\/code.google.com\/p\/gitblit\/issues\/detail?id=11\" target=\"_blank\">bekannt <\/a>und kann (in des Dateien reference.properties und web.xml) durch das Setzen von &#8222;web.mountParameters&#8220; auf &#8222;false&#8220; beseitigt werden.<\/p>\n<p>Die restlichen Funktionen von gitblit muss ich jetzt nach und nach ausprobieren. Aber mein SVN-Server wird wohl bald ausgediehnt haben.<\/p>\n<p><strong>Links<\/strong><br \/>\n<a href=\"http:\/\/gitblit.com\/\" target=\"_blank\">Gitblit-Homepage<\/a><br \/>\n<a href=\"http:\/\/jausoft.com\/blog\/2009\/07\/08\/svn-to-git-migration-1\/\" target=\"_blank\">SVN to Git Migration von Sven Goethel<\/a><br \/>\n<a href=\"http:\/\/blog.speedyj.de\/wp-content\/uploads\/2012\/06\/speedyjs-svn2git-utils.zip\">Download der Scripte<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Vor einer Weile hatte hatte ich mir einen SVN Server mittels WAMP zusammengebastelt. Die L\u00f6sung l\u00e4uft bei mir aktuell immer noch, obwohl ich schon seit einer Weile auf lokale GIT Repositories gewechselt bin. Das hat es mir erm\u00f6glicht, jederzeit und unterwegs mit dem Repository zu arbeiten, also Verlauf einsehen und \u00c4nderungen einchecken, und sobald ich [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,9],"tags":[35,36,37],"class_list":["post-808","post","type-post","status-publish","format-standard","hentry","category-software","category-tools","tag-git","tag-gitblit","tag-svn"],"_links":{"self":[{"href":"https:\/\/blog.speedyj.de\/index.php?rest_route=\/wp\/v2\/posts\/808","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.speedyj.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.speedyj.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.speedyj.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.speedyj.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=808"}],"version-history":[{"count":22,"href":"https:\/\/blog.speedyj.de\/index.php?rest_route=\/wp\/v2\/posts\/808\/revisions"}],"predecessor-version":[{"id":1054,"href":"https:\/\/blog.speedyj.de\/index.php?rest_route=\/wp\/v2\/posts\/808\/revisions\/1054"}],"wp:attachment":[{"href":"https:\/\/blog.speedyj.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=808"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.speedyj.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=808"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.speedyj.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=808"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}