un des principaux outils au coeur de la gestion d'un projet
Dans un projet à plusieurs, gérer les développements concurrents est un point crucial.
Fusionner peut être dangereux : on peut réintroduire discrètement des "bugs" corrigés ou en créer de nouveaux :
La façon dont les VCS gèrent les branches et les fusions entre branches est donc très importante.
Avec SVN on crée une nouvelle branche en copiant une branche existante,
puis on récupère une copie locale.
SVN permet de travailler à plusieurs simultanément dans la même branche.
C'est la façon la plus simple, et donc naturelle, de procéder avec SVN.
DVCS : pas de serveur central qui stocke les metadata.
Chaque clone contient une copie autonome du projet avec tout l'historique et un espace de travail.
La récupération de modifications est découplée de la fusion avec les modifications locales.
Avec un DVCS, chaque "commit" est potentiellement une branche en lui-même.
Si on démarre à plusieurs à partir de la même révision,
alors, chacun crée en fait, lors du 1er commit, un petit "fork" du projet.
Branches et fusions sont complètement naturelles avec les DVCS
et donc perçues différemment que dans le monde SVN.
Tant Mercurial que Git peuvent associer un nom aux branches que l'on veut faire durer.
L'historique d'un projet montre bien ce parallélisme et sa structure en branches, avec qui a fait quoi, quand et pourquoi.
SVN n'impose aucune organisation particulière des packages qu'il gère.
svn copy
.
$> svn co /branches/myfeature
$> cd myfeature/deep/in/subdir
$> svn ci
svn update
fonctionne de la même façon :
il est tout à fait possible d'avoir des portions de son espace de travail
synchronisées avec différentes révisions de l'histoire de la branche.
Au contraire, les DVCS traitent la totalité du dépôt comme une unité de travail.
git commit -a
n'importe où
dans le dépôt,
toutes les modifications effectuées seront prises en charge et on créera
une nouvelle version du projet.
hg update
mettra à jour
la totalité de l'espace de travail par rapport à un moment donné
de l'historique.
Aucun de ces outils ne peut mettre une branche dans un état inconsistant accidentellement.
C'est l'une des principales différences entre SVN et les DVCS :
Combiner le "commit" et la publication peut convenir si tous les développeurs ont
un accès en écriture sur le serveur et si tous sont connectés en permanence
sur le même réseau.
Les séparer rajoute une étape supplémentaire, mais ouvre la possibilité
de travailler hors connexion et d'utiliser des techniques de publication originales.
C'est l'une des principales différences entre SVN et les DVCS :
Dans le cas d'une petite équipe soudée, toujours efficacement connectée,
le choix de publier en "commitant" peut être le plus facile.
Dans le cadre d'une collaboration plus lâche et géographiquement très
répartie, découpler le "commit" de la publication peut davantage convenir.
C'est l'une des principales différences entre SVN et les DVCS :
Ainsi, les CVCS peuvent être bien adaptés au modèle de gestion de projet
dans lequel une équipe très structurée est menée avec des règles
très contraignantes. Les accès sont alors contrôlés par des responsables
et non partagés par des pairs. Les droits d'accès à certaines parties
du dépôt peuvent être restreints selon les équipes
ou les développeurs.
Les DVCS n'offrent par défaut pas d'autres possibilités que de couper
le dépôt en plusieurs sous-dépôts séparés.
Souvent on commence en utilisant un DVCS comme on le faisait avec SVN.
On clone l'un des dépôts principaux et y dépose en retour ses modifications.
Cette façon de travailler est familière et inspire confiance,
mais elle n'utilise qu'une toute petite partie des façons d'interagir au sein du projet.
Puisque le modèle distribué s'appuie sur la récupération des modifications en les reportant dans un dépôt local, il favorise la revue de code.
Bien sûr, on peut faire de la "revue de code avant fusion" avec un CVCS;
mais par défaut un CVCS n'y incite pas.
Il faut se fixer très explicitement ce type d'étapes et s'y contraindre,
alors que c'est complètement naturel avec un DVCS.
Les "hooks" permettent de lancer des scripts à des moments particuliers
lors de certaines opérations du VCS :
commit, changement de révision, lock (comparable à la notion de "trigger" en SQL).
Ils permettent d'introduire, au niveau du dépôt,
des contraintes définies par la gestion du projet.
Les CVCS offrent une plus grande facilité de gestion des "hooks";
par exemple, il est possible de configurer un script en "pre-commit" qui rejettera
tout "commit" introduisant une erreur détectée par une suite de tests automatique.
Avec un DVCS, ou pourra mettre en place une solution équivalente sur un dépôt jouant le rôle de dépôt central de référence, mais il sera plus difficile d'empêcher des développeurs d'échanger entre leurs dépôts des modifications à effets de bords malencontreux.
Généralement, la 1è chose que l'on fait face à un nouveau bug, c'est de parcourir l'historique à la recherche de ce qui a changé récemment et de voir qui a modifié quoi, quand et pourquoi.
Ces opérations sont quasi instantanées avec un DVCS, car les données sont stockées localement sur la machine, alors qu'elles peuvent être relativement longues si on s'adresse à un serveur SVN lointain et occupé.
Bien que le simple affichage de l'historique soit très utile, il est beaucoup plus
intéressant encore d'avoir un outil qui permette de mettre directement le doigt
sur un bug !
C'est la commande bisect
.
L'utilisation est assez simple : on lance la commande bisect
sur une révision
dont on sait qu'elle n'a pas le bug et sur une révision contenant ce bug.
Par itération et en questionnant l'utilisateur, l'outil est capable de trouver
la révision qui a introduit le bug.
Procédure facilement automatisable. Il suffit :
bisect
,Par ailleurs, la commande opère en log(n) : pour une recherche sur 1000 révisions il posera environ 10 fois la question; si on élargit la recherche sur 10000 révisions, le nombre de questions passera à 14.
Non seulement cette commande bisect
change complètement la façon
dont on recherche des bugs, mais si on écrit systématiquement les scripts
qui automatisent son utilisation, on fait d'une pierre deux coups, en développant
une suite de tests de régression !
On peut objecter que l'examen de l'historique est beaucoup plus simple avec SVN plutôt
qu'avec un DVCS puisque son historique est habituellement beaucoup plus linéaire.
Mais cette commande bisect
n'est disponible que pour Hg et Git …
Une fois qu'on a trouvé un bug, le corriger est rarement suffisant.
Imaginons qu'il existe depuis plusieurs mois et qu'il y a déjà 3 "releases" à
corriger. Chacune de ces versions a elle-même éventuellement sa propre branche
de corrections de bugs.
Si l'idée de copier une correction d'une branche à l'autre est simple,
la mise en pratique, elle, n'est pas si simple.
Mercurial, Git et Subversion ont tous la possibilité de "sélectionner
à la main" (cherry-picking) un ensemble de modifications dans une branche
et de l'appliquer sur une autre. Mais c'est assez risqué.
Une modification ne flotte pas comme ça en l'air : elle existe dans un contexte
et dépend de son environnement, du code autour.
Et certaines de ces dépendances sont sémantiques si bien que,
malgré une fusion réussie, la modification donnera une erreur plus tard.
Lorsque ces dépendances sont simplement textuelles, il suffit d'inspecter la modification et de la corriger avec un éditeur adéquat. Les DVCS proposent un certain nombre de techniques pour résoudre efficacement ce type de problème.
Par exemple, avec Mercurial ou Git, il y a une alternative possible en utilisant des branches anonymes :
bisect
;
Cette nouvelle modification peut alors facilement être propagée dans toutes les branches touchées par le bug, sans avoir à se coltiner de sélection à la main, en utilisant alors les outils habituels de fusion et de résolution de conflits plus simples et plus fiables qu'une "sélection à la main".
Là encore, rien en théorie, n'interdit d'utiliser une technique similaire
avec Subversion; mais l'utilisation de ses branches est beaucoup plus lourde que celle des DVCS
et du coup, beaucoup moins utilisée.
Un des points forts des CVCS est la gestion des fichiers binaires, en particulier quand ils sont gros.
Les fichiers binaires sont difficiles à compresser et ne peuvent être fusionnés.
Chaque révision est pratiquement stockée telle quelle et leur accumulation
peut vite devenir importante.
La fusion de 2 fichiers n'est pratiquement jamais possible - pratiquement aucune application à l'origine de ces fichiers ne fournit de solution pour résoudre ce type de conflits.
La possibilité de faire des "commits" locaux facilement encourage le développeur utilisant un DVCS à développer rapidement, par petites modifications.
Imaginons qu'on soit en cours de développement d'un truc compliqué
et qu'on ait envie de tester un "refactoring" hasardeux …
Avec un DVCS :
rebase
pour éliminer certains des "commits" effectués durant les tests.
Cette façon de procéder est certainement plus ou moins possible avec SVN,
mais l'expérience montre qu'elle est beaucoup plus fréquente avec les DVCS.
Il est probable que le côté privé de la branche, sur son ordinateur,
ajouté aux réponses instantanées des DVCS, encourage davantage à
une utilisation avancée et généralisée de l'outil.
On peut observer un effet similaire avec les fusions. Dans la mesure où elles sont
au coeur de l'activité des DVCS, elles apparaissent beaucoup plus fréquemment
que dans les projets gérés avec Subversion.
Bien que toute fusion demande un effort et fait prendre des risques, lorsqu'on fusionne
ses branches fréquemment, les fusions sont plus légères
et moins périlleuses.
Chaque outil de gestion de version a sa propre approche et sa vision du travail
en projet collaboratif.
Et en retours, il influence la façon de travailler de chacun au sein du groupe.
Un outil donné ne conviendra pas nécessairement à une équipe
donnée : chaque outil vient avec ses avantages et ses contraintes qu'il faut essayer
d'évaluer.
Merci !
Évolution du temps de réponse d'un commit avec le temps (nbre de ci)
(4000 fichiers de 4050 bytes chacun)
Évolution de la taille du dépôt avec le temps (nbre de ci)
(4000 fichiers de 4050 bytes chacun)
Évolution du temps de réponse en fonction du nombre de fichiers "commités"
Évolution du temps de réponse du "commit" d'un fichier en fonction du nombre de fichiers "commités" précédemment
Il n'est pas étonnant que Mercurial et Git ait une approche similaire face à la fusion des modifications, alors que Subversion s'y prend tout à fait différemment.
Comme les opérations de fusion sont réalisées très
fréquemment avec Mercurial et Git, ces derniers sont particulièrement
bien équipés pour ça.
Un cas d'utilisation délicat à gérer lors des fusions est le cas
où des dossiers ou des fichiers ont été renommés.
Renommage dans les environnements multiplateformes.
Windows, Mac OS X et les systèmes Unix n'ont pas les mêmes conventions
de gestion de la casse des noms de fichier (FOO.TXT versus foo.txt).
Mercurial est capable de détecter et de gérer correctement le passage d'un environnement ignorant la casse à un environnement sensible à la casse.