Nous allons voir aujourd’hui comment migrer un projet SVN existant vers un repository Git existant (GitHub, GitLab ou autre) en gardant toutes les branches et les tags. Cette migration va se dérouler en 6 étapes.

1. Récupérer la liste des utilisateurs

Pour pouvoir migrer convenablement votre projet SVN, nous devons mapper les utilisateurs SVN avec les utilisateurs GIT afin de pouvoir convertir l’historique de commit convenablement. Pour cela, placez vous dans le répertoire racine de votre checkout SVN et lancez la commande suivante :

svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); \ 
sub(" $", "", $2); print $2" = "$2" <"$2">"}' | \
sort -u > authors.txt
Le caractère ‘\’ en fin de ligne permet juste de taper la commande sur plusieurs lignes afin d’avoir une meilleure visibilité du code sur le blog.

Attention cependant, les utilisateurs retournés ne correspondent qu’aux utilisateurs SVN. Pas aux utilisateurs GIT. Vous devrez donc remplacer chaque ligne :

jwilkins = jwilkins <jwilkins>

Par ceci :

jwilkins = John Albin Wilkins <johnalbin@example.com>

2. Cloner votre projet SVN avec git-svn

Maintenant, la conversion SVN vers GIT commence. Vous avez juste à lancer la commande suivante :

git svn clone [SVN repo URL] --no-metadata -A authors.txt --stdlayout ~/temp

Cette commande va convertir votre checkout SVN en repository GIT tout en effectuant un mappage des utilisateurs par rapport au fichier authors.txt généré tout à l’heure. Le checkout sera effectué dans le répertoire ~/temp.

3. Push vers un dépôt .git vide

Votre repository GIT est effectué mais il est lié à aucun dépôt. Nous allons donc créer notre dépôt vide comme ceci :

git init --bare ~/new-bare.git
cd ~/new-bare.git
git symbolic-ref HEAD refs/heads/trunk

Maintenant, vous n’avez plus qu’à envoyer votre repository vers le dépôt fraichement créé :

cd ~/temp
git remote add bare ~/new-bare.git
git config remote.bare.push 'refs/remotes/*:refs/heads/*'
git push bare
Maintenant, vous pouvez supprimer ~/temp en toute sécurité.

4. Remplacement de trunk par master

Dans les dépôts subversion, la branche de développement s’appelle trunk. Dans GIT, il s’agit de la branche master. Nous allons donc renommer notre branche trunk en master.

cd ~/new-bare.git
git branch -m trunk master

5. Nettoyage des tags et des branches

git-svn rend le nommage des branches et des tags très courts, de la forme tags/name, alors que GIT utilise des noms plus longs que ça pour s’y retrouver. Nous allons donc lancer une commande pour arranger tout ça.

cd ~/new-bare.git
git for-each-ref --format='%(refname)' refs/heads/tags |
cut -d / -f 4 | 
while read ref
do
    git tag "$ref" "refs/heads/tags/$ref";
    git branch -D "tags/$ref";
done

6. Copie du dépôt vers votre serveur GIT

Dernière étape : L’envoie du dépôt GIT vers votre dépôt GitHub, GitLab ou autres. Cette étape est relativement simple à effectuer. Voyez plutôt :

cd ~/new-bare.git
git remote add origin [GIT repo URL]
git push -f --tags origin refs/heads/*:refs/heads/*

Conclusion

Voilà. Votre repository SVN a été pleinement migré et converti sur GIT. J’ai oublié une étape vue dans mes sources. Il s’agit de renseigner tous les fichiers ignorés de SVN dans le .gitignore. Sauf que la commande en question n’a pas marchée chez moi sur mes différents postes (ubuntu 12.10 et OSX).

Sources :