Git/Travailler avec Git local et un dépôt Subversion distant

< Git

Git permet de participer à de nombreux autres systèmes de contrôle de version, comme git-svn ou git-cvsimport.

La compatibilité entre Git et Subversion est assurée par git-svn qui autorise un utilisateur à accéder et participer à un dépôt SVN. Les utilisateurs peuvent générer des patchs locaux pour les envoyer par liste de diffusion, ou soumettre leurs changements aux dépôts d'origine.


Premiers pas

modifier

Pour commencer à utiliser Git avec des projets sur des serveurs Subversion, il faut créer un dépôt local, et configurer git-svn :

 mkdir projet1
 cd projet1
 git svn init <URL du dépôt root> -T/chemin/du/tronc
 git svn fetch -r <première révision>:HEAD

Le paramètre "première révision" peut être "1", mais pour gagner du temps il est possible de ne prendre que les 10 dernières révisions. svn info indique alors ces révisions.

Généralement quand on travaille avec des dépôts Subversion, on communique l'URL du projet complète. Pour déterminer l'URL du dépôt racine :

 git svn info <URL du dépôt root>

Une ligne du résultat indique le dépôt racine. Le chemin du tronc est simplement le reste de l'URL qui suit.

Il est possible de simplement donner à git-svn l'URL complète du projet, mais cela peut stopper la possibilité de travailler sur des branches SVN.

Exemples

modifier

Obtenir Pywikipedia :

$ git svn init http://svn.wikimedia.org/svnroot/pywikipedia/trunk/pywikipedia/
Initialized empty Git repository in .../.git/
$ git svn fetch -r 1:HEAD
...
r370 = 318fb412e5d1f1136a92d079f3607ac23bde2c34 (refs/remotes/git-svn)
        D       treelang_all.py
        D       treelang.py
W: -empty_dir: treelang.py
W: -empty_dir: treelang_all.py
r371 = e8477f292b077f023e4cebad843e0d36d3765db8 (refs/remotes/git-svn)
        D       parsepopular.py
W: -empty_dir: parsepopular.py
r372 = 8803111b0411243af419868388fc8c7398e8ab9d (refs/remotes/git-svn)
        D       getlang.py
W: -empty_dir: getlang.py
r373 = ad935dd0472db28379809f150fcf53678630076c (refs/remotes/git-svn)
        A       splitwarning.py
...

Récupérer AWB (AutoWikiBrowser) :

$ git svn init svn://svn.code.sf.net/p/autowikibrowser/code/
Initialized empty Git repository in .../.git/
$ git svn fetch -r 1:HEAD
...
r15 = 086d4ff454a9ddfac92edb4013ec845f65e14ace (refs/remotes/git-svn)
        M       AWB/AWB/Main.cs
        M       AWB/WikiFunctions/WebControl.cs
r16 = 14f49de6b3c984bb8a87900e8be42a6576902a06 (refs/remotes/git-svn)
        M       AWB/AWB/ExitQuestion.Designer.cs
        M       AWB/WikiFunctions/GetLists.cs
        M       AWB/WikiFunctions/Tools.cs
r17 = 8b58f6e5b21c91f0819bea9bc9a8110c2cab540d (refs/remotes/git-svn)
        M       AWB/AWB/Main.Designer.cs
        M       AWB/AWB/Main.cs
        M       AWB/WikiFunctions/GetLists.cs
r18 = 51683925cedb8effb274fadd2417cc9b1f860e3c (refs/remotes/git-svn)
        M       AWB/AWB/specialFilter.Designer.cs
        M       AWB/AWB/specialFilter.cs
r19 = 712edb32a20d6d2ab4066acf056f14daa67a9d4b (refs/remotes/git-svn)
        M       AWB/WikiFunctions/WPEditor.cs
r20 = 3116588b52a8e27e1dc72d25b1981d181d6ba203 (refs/remotes/git-svn)
...

 

Cette opération de téléchargement peut prendre une heure.

Interagir avec le dépôt

modifier

L'avantage de travailler avec Git sur des dépôts SVN est l'utilisation en local. Dans ce cas :

  1. Ne pas lancer git pull
  2. Dans une branche mieux vaut éviter de lancer git-svn dcommit car les soumissions fusionnées ont tendance à embrouiller git-svn. Par contre, combiner les changements avec ceux de Subversion en amont est équivalent à svn update :
 git stash     # cache les changements pour obtenir un arbre propre
 git svn fetch # amène les derniers changements
 git rebase trunk
 git stash apply

La première et la dernière ligne ne sont pas nécessaires si l'arbre est propre.

Le git rebase trunk laisse les soumissions locales au dessus du HEAD SVN[1].

Changements locaux

modifier

Pour éviter de propager des modifications locales indésirables (débogages, tests...), avec git svn dcommit, sans les perdre peut passer par deux approches.

Premièrement, maintenir une branche locale pour chacune qui devra contenir des changements locaux. Par exemple faire un rebase sur "branche1" au-dessus de "branche1-locale". Exemple :

 git rebase trunk branche1-locale
 git rebase branche1-locale branche1

Deux choix sont ensuite possibles, effectuer directement les changements sur la branche locale, ce qui est plus rapide que de les soumettre à la branche distante avant de les récupérer dans la locale. Ensuite il est possible d'utiliser git reset[2] pour les retirer de la branche distante.

Comme une alternative à l'approche centrée recombinaison, il existe une méthode basée sur la fusion. Tout en conservant les changements sur une branche locale, mais sans avoir à conserver la branche au dessus de la branche locale par recombinaison.

C'est un avantage car :

  1. Sinon il y a plus à écrire[précision nécessaire].
  2. Historiquement, la recombinaison a souvent demandé de résoudre le même conflit deux fois, s'il survient pendant la première recombinaison.

Donc à la place des recombinaisons, on crée une nouvelle branche servant à la construction. Il faut la démarrer avec la soumission à tester. Ensuite git merge fusionne la branche locale, apportant tous les changements dans un seul arbre. La raison de cette fusion dans une branche reconstruction est pour dissuader l'utilisation de git-svn dcommit (qui soumettrait les tests indésirables sur le serveur).

Cette approche peut même rendre facultative la recombinaison quotidienne la branche avec le tronc. En cas de branches multiples, les recombinaisons permanentes peuvent s'avérer chronophages :

git checkout build
git reset --hard trunk              # s'assurer de l'absence de changement important
git merge branche1 branche1-locale

La construction contient ensuite les changements du tronc, branche1 et branche1-locale !

Il est possible de conserver plusieurs branches locales dont une avec les tests. Cette approche peut être développée avec une branche par sujet dans un arbre :

git merge sujet1 sujet2 config debug...

Malheureusement, la fusion de cette pieuvre ne résout pas les conflits. Dans ce cas il faut appliquer les fusions une par une :

git merge sujet1
git merge sujet1
git merge local
...

Envoyer des changements en amont

modifier

Éventuellement, pour soumettre au serveur des branches sujet avec un accès commit, on peut lancer git-svn dcommit. Cela prendra chaque soumission locale dans la branche courante et le soumettra à subversion. Par exemple avec trois soumissions locales, après dcommit il y aura trois nouvelles soumissions dans subversion.

Sans accès commit, le patch devra probablement être soumis via une liste de diffusion ou un logiciel de suivi de problèmes (bug tracker). Pour cela on peut utiliser git-format-patch. Par exemple pour trois soumissions locales :

git format-patch HEAD~3..

Le résultat sera trois fichiers en $PWD, 0001-commit-name.patch, 0002-commit-name.patch, et 0003-commit-name.patch, qui pourront être attachés à des emails ou joint à Bugzilla. Remarque : il existe git-send-email pour envoyer les emails directement :

git send-email *.patch

Si les séries de patchs ne sont pas dans l'ordre, voir git rebase -i.

Références

modifier
  1. git-rebase
  2. http://www.kernel.org/pub/software/scm/git/docs/git-reset.html