« VCS/Git/ImportSVN » : différence entre les versions
| Ligne 151 : | Ligne 151 : | ||
Listons les branches importées : | Listons les branches importées : | ||
$ git branch -a | $ git branch -a | ||
* master | * master | ||
remotes/corbeille_2 | remotes/corbeille_2 | ||
remotes/corbeille_2@2249 | remotes/corbeille_2@2249 | ||
| Ligne 177 : | Ligne 177 : | ||
Puis on la créé localement : | Puis on la créé localement : | ||
$ git branch corbeille_2 remotes/corbeille_2 $ git branch -l corbeille_2 * master | $ git branch corbeille_2 remotes/corbeille_2 | ||
$ git branch -l corbeille_2 * master | |||
Faisons de même pour la seconde branche et son tag : | Faisons de même pour la seconde branche et son tag : | ||
| Ligne 184 : | Ligne 185 : | ||
$ git tag corbeille_1_9 remotes/tags/corbeille_1_9@47807 | $ git tag corbeille_1_9 remotes/tags/corbeille_1_9@47807 | ||
$ git tag -l corbeille_1_9 | $ git tag -l corbeille_1_9 | ||
=== Pousser encore === | === Pousser encore === | ||
Dernière version du 23 janvier 2013 à 11:34
Migrer un projet SVN vers GIT
Depuis que j’ai compris que Git c’est facile, je suis de plus en plus enclin à l’utiliser couramment.
De plus, j’apprécie vraiment le service et les facilités proposés par GitHub comme son interface de consultation, la gestion des issues, le zip automatique des tags.
Mais j’ai aussi un historique de développement sous SVN, avec plein de petits projets développés et versionnés sur mon serveur SVN accouplé à une interface TRAC.
C’est donc au cas par cas que je migre chacun de ces petits projets sous Git, ce qui me permet tout à la fois de passer à Git, d’améliorer grandement mon confort de consultation par l’interface web, et de faciliter les contributions externes.
Nous allons voir deux cas pratiques de migration, en commençant par un projet simple sans branche, puis en essayant d’importer un projet avec ses branches et ses tags.
Un cas simple
Pour l’exemple, on va ici créer un projet GitHub pour le plugin SPIP Crayons, actuellement versionné sur [l’espace SVN partagé de la communauté SPIP appelé SPIP-Zone, dans le dossier _plugins_/crayons
Importer de SVN vers Git
On va utiliser pour importer la fonction git svn.
La syntaxe est simple. Pour importer le Repository SVN svn://zone.spip.org/spip-zone vers un répertoire local gitzone versionné sous Git, on utiliserait la syntaxe
git svn clone svn://zone.spip.org/spip-zone gitzone
Ici, on ne veut pas importer tout le dépôt, mais seulement un sous répertoire. On précise donc le chemin complet. On s’abstient aussi de préciser le nom du dossier local, qui sera automatiquement celui du dernier dossier du chemin :
$ git svn clone svn://zone.spip.org/spip-zone/_plugins_/crayons
Initialized empty Git repository in /Users/cedric/Repositories/import/crayons/.git/
W: Ignoring error from SVN, path probably does not exist: (160013): Filesystem has no item: File not found: revision 100, path '/_plugins_/crayons'
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
Checked Ahrough controleurs/auteur_email.html
A controleurs/date.html
....
r48121 = ad2f3331206911a4b922e52ec64f23511b25cf41
(refs/remotes/git-svn)
Checked out HEAD:
svn://zone.spip.org/spip-zone/_plugins_/crayons r48121
Voila, on a maintenant un dossier Git <ref>Utilisation de la syntaxe raccourcie git lg [[VCS/Git#Configuration_de_l.27environnement|Configuration de l’environnement Git]]</ref> :
$ cd crayons
$ git lg
* ad2f333 - (HEAD, git-svn, master) compat spip3 pour la config des crayons (guy.cesaro@... 2 days ago)
* 32aa6db - une presentation plus pratique dans la marge ; ca reste laid (fil@... 8 days ago)
* 13d72f4 - experimental: ajout de documents via drag/drop (une fois mis au point, ca pourrait être la feature qui justifie de passer a la version 2) (fil@... 8 days ago)
* da56c79 - On vire pour l'instant l'étoile des intervalles de compatibilité que l'on remplace par 3.0.0. On la remettra quand SPIP utilisera paquet.xml (eric@... 9 days ago)
...
On retrouve bien tout l’historique des commits. On voit aussi que Git a conservé les auteurs des commits SVN, ici identifiés par leurs emails. Mais on aimerait évidemment que les auteurs GitHub soient reconnus pour faciliter la navigation et l’utilisation de l’interface, et respecter au mieux les crédits de chacun.
Réattribuer les auteurs
Pour cela il suffit de définir la correspondance entre les auteurs des commits SVN et les auteurs nommés, dans un fichier que l’on indiquera avec l’option --authors-file. Comme il faut fournir la correspondance pour tous les auteurs, commençons par générer un template à partir des logs SVN. On adapte la contribution à notre cas où les auteurs sont déjà des adresses mails, pour en extraire la première partie :
authors=$(svn log -q svn://zone.spip.org/spip-zone/_plugins_/crayons | grep -e '^r' | awk 'BEGIN { FS = "|" } ; { print $2 }' | sort | uniq)
for author in ${authors}
do
echo "${author} = ${author%@*} <${author}>"
done
Il reste a copier ce template dans un fichier nommé authors, et de corriger les auteurs dont le compte GitHub n’est pas bon (c’est souvent le même pseudo que dans l’adresse mail, mais pas toujours).
Supprimons notre premier import, et recommençons avec la correspondance des auteurs :
$ git svn --authors-file=authors clone svn://zone.spip.org/spip-zone/_plugins_/crayons
Regardons le résultat :
$ cd crayons/
$ git log -n2
commit df9948ef93864d8cfc6f86fd8831fc363d63a28b
Author: guy.cesaro <guy.cesaro@...>
Date: Thu May 26 06:44:47 2011 +0000
compat spip3 pour la config des crayons
git-svn-id: svn://zone.spip.org/spip-zone/_plugins_/crayons@48121 ac52e18a-acf5-0310-9fe8-c4428f23b10a
commit 7e126aea078a1ed3003225efe973adb9286aa803
Author: Fil <fil@...>
Date: Fri May 20 21:53:52 2011 +0000
une presentation plus pratique dans la marge ; ca reste laid
git-svn-id: svn://zone.spip.org/spip-zone/_plugins_/crayons@47970 ac52e18a-acf5-0310-9fe8-c4428f23b10a
On a bien cette fois les auteurs des commits qui apparaissent sous leur vrai nom.
Nettoyer les messages de commit
En revanche on voit que les logs de commit ont été complétés par une référence au repository SVN d’origine, avec mention du commit SVN. C’est souvent très bien, mais c’est parfois gênant quand le repository d’origine est privé et que vous voulez éviter de le divulguer.
Pour cela, on peut ré-écrire tous les messages de commit grâce à la fonction filter-branch de Git. Attention, ré-écrire les messages de commit va modifier aussi les hash de tous les commits ; Git va donc ré-écrire tout l’historique. Cela est faisable dans un cas comme ici où notre dépôt n’a pas encore été publié ou partagé, mais dès que nous l’aurons poussé, ce type d’opération n’est plus envisageable (sauf à accepter de casser tous les historiques et des autres utilisateurs).
Ré-écrivons donc nos messages avec un sed bien senti :
git filter-branch --msg-filter ' sed -e "/git-svn-id:/d" '
et vérifions :
git log -n2
commit 16a6800b74cdd145d0fa22136d42205a94163ca1
Author: guy.cesaro <guy.cesaro@...>
Date: Thu May 26 06:44:47 2011 +0000
compat spip3 pour la config des crayons
commit a37d1054187f13d6ba828550116c5e0a59a64818
Author: Fil <fil@...>
Date: Fri May 20 21:53:52 2011 +0000
une présentation plus pratique dans la marge ; ca reste laid
Voilà, on a retrouvé nos messages de commits originaux (mais perdu le lien avec les commits SVN).
Pousser fort
Il ne reste plus qu’à créer un dépôt GitHub, de le relier à notre dépôt local, et de tout envoyer :
$ git remote add origin git@github.com:Cerdic/Crayons.git git push -u origin master
Et c’est gagné !
Un dépôt avec branches et tags
Cette fois nous allons faire un peu plus compliqué : importons dans Git un dépôt qui contient des branches et tags, en récupérant évidemment tout cela sous Git.
Pour l’exemple, on choisit ici le plugin SPIP Corbeille, versionné lui aussi sur l’espace SVN partagé de la communauté SPIP appelé SPIP-Zone
Référencer les auteurs
On commence par créer le fichier d’auteurs avec notre commande magique, que l’on copie dans un fichier cette fois nommé authors2 :
authors=$(svn log -q svn://zone.spip.org/spip-zone/_plugins_/corbeille | grep -e '^r' | awk 'BEGIN { FS = "|" } ; { print $2 }' | sort | uniq)
for author in ${authors}
do echo "${author} = ${author%@*} <${author}>"
done
Importer
Puis on importe en utilisant les options --trunk, --branches, --tags de git svn. Notre dossier corbeille est organisé depuis peu en 3 sous-dossiers trunk/, branches/ et tags/, nous les indiquons donc comme tel :
$ git svn --authors-file=authors2 clone svn://zone.spip.org/spip-zone/_plugins_/corbeille --trunk=trunk --branches=branches --tags=tags
C’est cette fois un peu plus long car l’analyse du dépôt SVN est plus compliquée. Une fois fini, regardons ce que git-svn nous a importé :
$ git lg * 85966e4 - (HEAD, trunk, origin/master, master) Réorganisation du plugin corbeille avec la structure conventionnelle SVN : trunk/ contient la version en cours de développement branches/ contient les branches maintenues (en général des anciennes versions, mais ce peut etre aussi des fork temporaires) tags/ contient les versions figées (cedric 5 hours ago)
Notre historique ne semble contenir qu’un commit. En fait c’est ici parce que le dernier commit SVN a été une opération de déplacement fichier à fichier pour créer le dossier trunk/, et Git a eu du mal à reconstituer l’historique.
On peut afficher tout l’historique :
$ git lg --all
On voit alors le graphe complet des branches du dépôt.
Référencer les branches importées
Listons les branches importées :
$ git branch -a * master remotes/corbeille_2 remotes/corbeille_2@2249 remotes/corbeille_2@28924 remotes/corbeille_2@48220 remotes/corbeille_2@48221 remotes/corbeille_2@5463 remotes/origin/master remotes/tags/corbeille_1_9 remotes/tags/corbeille_1_9@2249 remotes/tags/corbeille_1_9@23668 remotes/tags/corbeille_1_9@47807 remotes/tags/corbeille_1_9@5463 remotes/trunk $ git tag -l
On voit que git-svn a importé toutes les branches et tags sous forme de branches distantes, y compris a différentes périodes correspondant en général à des opérations de copie ou déplacement. Aucun tag n’a été créé.
Il suffit donc de recréer les branches et tags correctement à partir des branches distantes référencées ici. Pour vérifier le contenu d’une branche, on la checkout :
$ git checkout remotes/corbeille_2 $ ls -l ... $ git lg $ git checkout master
Puis on la créé localement :
$ git branch corbeille_2 remotes/corbeille_2 $ git branch -l corbeille_2 * master
Faisons de même pour la seconde branche et son tag :
$ git branch corbeille_1_9 remotes/tags/corbeille_1_9@47807 $ git branch -l corbeille_1_9 corbeille_2 * master $ git tag corbeille_1_9 remotes/tags/corbeille_1_9@47807 $ git tag -l corbeille_1_9
Pousser encore
Il ne reste qu’à pousser tout cela :
$ git remote add origin git@github.com:Cerdic/Corbeille.git $ git push -u origin master $ git push --all $ git push --tags
Conclusion
Dans notre dernier cas, la reprise de l’historique n’est pas une franche réussite. La faute en incombe à la dernière opération de réorganisation du repository SVN : Pour créer une organisation en 3 sous-dossiers trunk/, branches/ et tags/, on a créé le sous dossier trunk et on y a déplacé les fichiers un à un. Cela est à éviter, car pour l’import, les fichiers « apparaissent » dans trunk/. Il est préférable de déplacer le dossier complet sous SVN pour faciliter une migration ultérieure sous Git.
Hormis ce soucis, l’import de SVN vers Git à l’aide de la commande git svn permet donc de migrer assez facilement, qui plus est en découpant un gros dépôt SVN en de multiples petits dépôts Git.