Wie Du ein Subversion Repository (SVN) nach Git konvertierst
In diesem Howto beschreibe ich, wie ein existierendes Projekt aus einem Apache Subversion (SVN) Repository in ein Git Repository konvertiert werden kann.
Diesen kann mit Hilfe der bidirektionalen Subversion Brücke git-svn
von Git erreicht werden.
Dieses führe ich mit dem Projekt test-spring-simple
aus dem Beitrag Spring an einem einfachem Beispiel der Tutorial Serie Einführung in das Spring Framework vor.
Einige Informationen zu Git habe ich im Kapitel Wissenswertes zu Git des Beitrag Git mit GitHub schon einmal beschrieben.
Die Installation der bidirektionalen Subversion Brücke git-svn
Die bidirektionale Unterstützung von Subversion muss für Git gesondert installiert werden.
$ sudo apt-get update $ sudo apt-get install git-svn $
Die Vorbereitung der Benutzerkennungen
Dazu muss die Datei authors.txt
erstellt werden. In dieser Datei werden die abgekürzten Namen der Subversion Benutzer auf den kompletten Namen der Git Benutzer zugeordnet.
Dadurch werden die Benutzer in der Historie richtig im Git-Style (Name des Benutzers und Email) angezeigt.
$ cat authors.txt frank = Frank W. Rahn <...@frank-rahn.de> $
Zusätzlich sollte noch zwei Einträge für Commits ohne Namen (no author
) hinzugefügt werden. Leider benötigt Subversion die Eigenschaft svn:author
nicht zwingend. Unterumständen kann dieser Name auch noch in der deutschen Übersetzung vorkommen.
$ svn log -r 4711 ------------------------------------------------------- r4711 | (no author) | (no date) | 1 line ------------------------------------------------------- $ $ cat authors.txt frank = Frank W. Rahn <...@frank-rahn.de> (no author) = Frank W. Rahn <...@frank-rahn.de> (kein Autor) = Frank W. Rahn <...@frank-rahn.de> $
Die Datei authors.txt
kann auch mit Hilfe des folgenden Scripts direkt aus Subversion erstellt werden.
$ svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors.txt $ $ cat authors.txt frank = frank <frank> (no author) = (no author) <(no author)> $
Danach muss die Datei noch bearbeitet werden. Es müssen die korrekten E-Mail-Adressen und ggfs. die Namen der Committer ersetzt werden.
Das Initialisieren des lokalen Repositories
Zunächst muss ein lokales Git Repository angelegt und initialisiert werden.
Die erste Alternativen legt ein Verzeichnis an, initialisiert es und holt die Daten aus dem Subversion Repository.
$ mkdir test-spring-simple $ cd test-spring-simple $ $ git svn init -s --no-metadata svn://nll001/share/Repository/presentation/test-spring-simple Initialized empty Git repository in /home/frank/test-spring-simple/.git/ Using higher level of URL: svn://nll001/share/Repository/presentation/test-spring-simple => svn://nll001/share/Repository $ $ git svn fetch -A ../authors.txt W: Do not be alarmed at the above message git-svn is just searching aggressively for old history. This may take a while on large repositories ... $
Die zweite Alternative erledigt alles in einem Schritt.
$ git svn clone -s -A authors.txt --no-metadata svn://nll001/share/Repository/presentation/test-spring-simple Initialized empty Git repository in /home/frank/test-spring-simple/.git/ Using higher level of URL: svn://nll001/share/Repository/presentation/test-spring-simple => svn://nll001/share/Repository W: Do not be alarmed at the above message git-svn is just searching aggressively for old history. This may take a while on large repositories ... $
Mit der Option -rRevision:HEAD
kann die SVN-Revision angegeben werden, ab der die Daten aus dem SVN Repository ausgelesen werden. Dadurch kann das neue Repository entsprechend verkleinert werden.
$ git svn clone -s -r4711:HEAD -A authors.txt --no-metadata svn://nll001/share/Repository/presentation/test-spring-simple ... $
Das Konvertieren der Eigenschaft svn:ignore nach .gitignore
In diesem Schritt wird die SVN-Eigenschaft svn:ignore
in die Datei .gitignore
konvertiert.
$ git svn show-ignore > .gitignore $ git add .gitignore $ git commit -m "Convert svn:ignore properties to .gitignore." $
Das Konvertieren der SVN-Tag-Branches in richtige Git-Tags
Die Tags aus Subversion wurden beim Importieren nach Git in Branches tags/<name>
umgewandelt.
$ git branch -r b1.0 tags/2.0.1 tags/v1.0 tags/v1.0.1 tags/v1.0.2 tags/v2.0 tags/v2.0.1 tags/v2.0.2 tags/v2.0.3 trunk $
Der Branch tags/2.0.1
wird gelöscht, da er mit dem Branch tags/v2.0.1
identisch ist.
$ git branch -r -d tags/2.0.1 Deleted remote branch tags/2.0.1 (was c29f62b). $
Nun werden die Tags mit den folgenden zwei Befehle konvertiert.
$ git tag <name> tags/<name> $ git branch -r -d tags/<name> $
Im folgenden Beispiel werden die beiden Tags v1.0
und v1.0.1
konvertiert.
$ git tag v1.0 tags/v1.0 $ git branch -r -d tags/v1.0 Deleted remote branch tags/v1.0 (was 9899838). $ $ git tag v1.0.1 tags/v1.0.1 $ git branch -r -d tags/v1.0.1 Deleted remote branch tags/v1.0.1 (was 16d40ea). $
Für die Konvertierung aller Tags in einem Schritt kann folgende Befehlskette verwendet werden.
$ git for-each-ref --format='%(refname)' refs/heads/tags | > cut -d / -f 4 | > while read ref > do > git tag -a "$ref" -m "Convert "$ref" to a proper git tag." "refs/heads/tags/$ref"; > git branch -D "tags/$ref"; > done $
Nach dem Konvertieren aller Tags stellt sich folgendes Bild dar.
$ git branch -r b1.0 trunk $ git branch -a * master remotes/b1.0 remotes/trunk $ git tag v1.0 v1.0.1 v1.0.2 v2.0 v2.0.1 v2.0.2 v2.0.3 $
Das Entfernen von SVN-Branches mit einer Revisionsnummer im Namen
Manchmal entstehen durch die Konvertierung mit der Subversion Brücke git-svn
Branches in der Form Name@Revision.
Mit dieser Befehlskette können diese Branche entfernt werden.
$ git for-each-ref --format='%(refname)' refs/heads | > grep '@[0-9][0-9]*' | > cut -d / -f 3- | > while read ref > do > git branch -D "$ref"; > done $
Das Konvertieren der SVN-Branches in lokale Branches
Zunächst wird der Branch trunk
gelöscht, da er im Branch master
enthalten ist.
$ git branch -r -d trunk Deleted remote branch trunk (was 2f5bfb7). $ $ git branch -a * master remotes/b1.0 $
Der verbleibende entfernte Branch b1.0
muss nun noch als Upstream gekennzeichnet und danach gelöscht werden. Der Branch wird gelöscht, da er noch eine Verbindung zum SVN darstellt und diese gekappt werden soll. Im Repository bleiben die Metadaten durch das Löschen unverändert.
Auch hier bieten sich zwei Alternativen an.
$ git checkout -t -b b1.0 b1.0 Branch b1.0 set up to track local ref refs/remotes/b1.0. Switched to a new branch 'b1.0' $ $ git branch -a * b1.0 master remotes/b1.0 $ $ git branch -r -d b1.0 Deleted remote branch b1.0 (was cce8e83). $ $ git checkout master Switched to branch 'master' $ git branch -a b1.0 * master $
$ git branch --track b1.0 b1.0 Branch b1.0 set up to track local ref refs/remotes/b1.0. $ $ git branch -r -d b1.0 Deleted remote branch b1.0 (was cce8e83). $ $ git branch -a b1.0 * master $
Das Hochladen des Repositories nach GitHub
Um ein Repository bei GitHub zu erzeugen, siehe im Beitrag Git mit GitHub. Dabei sollte das Repository nicht mit einer README.md
oder .gitignore
initialisiert werden, da dieses die Historie des Repositories verändert. Dieses sollte in einem weiteren Schritt nachgeholt werden.
$ git remote add origin git@github.com:frank-rahn/test-spring-simple.git $ $ git push -u origin master b1.0 Enter passphrase for key '/home/frank/.ssh/id_rsa': Counting objects: 164, done. Delta compression using up to 8 threads. Compressing objects: 100% (128/128), done. Writing objects: 100% (164/164), 18.99 KiB, done. Total 164 (delta 54), reused 0 (delta 0) To git@github.com:frank-rahn/test-spring-simple.git * [new branch] master -> master * [new branch] b1.0 -> b1.0 Branch master set up to track remote branch master from origin. Branch b1.0 set up to track remote branch b1.0 from origin. $ $ git push --tags Enter passphrase for key '/home/frank/.ssh/id_rsa': Counting objects: 103, done. Delta compression using up to 8 threads. Compressing objects: 100% (41/41), done. Writing objects: 100% (53/53), 4.88 KiB, done. Total 53 (delta 20), reused 0 (delta 0) To git@github.com:frank-rahn/test-spring-simple.git * [new tag] v1.0 -> v1.0 * [new tag] v1.0.1 -> v1.0.1 * [new tag] v1.0.2 -> v1.0.2 * [new tag] v2.0 -> v2.0 * [new tag] v2.0.1 -> v2.0.1 * [new tag] v2.0.2 -> v2.0.2 * [new tag] v2.0.3 -> v2.0.3 $
Das konvertierte Projekt bei GitHub:
Repository bei GitHub
Die Historie bzw. der Network Graph nach dem Import:
Die Literaturempfehlungen
Update am 25.09.2012
Das Konvertieren der SVN-Tag & Branches in Git Tags & Branches
Die folgenden Kommandozeilenbefehle stellen eine andere Art dar, die Subversion-spezifischen Branches und Tags nach Git zu konvertieren.
$ cp -rf .git/refs/remotes/tags/* .git/refs/tags $ rm -rf .git/refs/remotes/tags $
$ cp -rf .git/refs/remotes/* .git/refs/heads/ $ rm -rf .git/refs/remotes $
Allerdings bevorzuge ich die Konvertierung über die Git Befehle, da diese auch die Datei .git/config
verändern.
Update am 08.01.2017
Es wurden einige neu Erkenntnisse in den Beitrag eingearbeitet.
- Wer ist der optimale Java Bean Mapper? - Freitag, 22. September 2023
- Spring Boot Webanwendung: Die ersten Schritte (Tutorial) - Montag, 28. März 2016
- Mainframe-Zugriff via Java - Sonntag, 04. Mai 2014
… netter beitrag, danke 🙂