L’index des leçons :
- Leçon 1 : la gestion de version
- Leçon 2 : qu’est-ce qu’un dépôt ?
- Leçon 3 : les logiciels ”clients”
- Leçon 4 : création d’un dépôt
- Leçon 5 : enregistrement de révision
- Leçon 6 : synchronisation de dépôts, mise à jour du répertoire de travail
- Leçon 7 : identifier les différences
- Leçon 8 : la gestion des branches
- Leçon 9 : la fusion de branche
- Leçon 10 : retour vers le passé
- Leçon 11 : patch et collaboration indirecte
Nous voilà maintenant avec deux branches en cours de développement. Pour faire suite à tous les commits effectués dans la leçon précédente il va falloir synchroniser le dépôt distant. Le logiciel MacHg n’est pour l’instant pas capable de faire un push directement lorsqu’une nouvelle branche fait partie du lot des révisions à envoyer. Il est donc nécessaire d’utiliser une commande terminal.
MacHg propose nativement de lancer une session terminal correctement configurée pour pouvoir effectuer des opérations sur nos dépôts. Pour faire pon push je vais alors exécuter la commande suivante :
mhg push --new-branch <url-depot-distant>
Vous avez noté ici la légère différence sur le début de la commande, mhg
au lieu du hg
que vous rencontré dans les leçons précédentes. C’est tout simplement parce MacHg, qui intègre une version de Mercurial, pour ne pas entrer en éventuel conflit avec une version déjà installée sur votre ordinateur, utilise une version renommée en mhg
. Toute la syntaxe des commandes restant bien évidemment identique.
Me voilà maintenant avec un dépôt distant et un dépôt local synchronisé comme en témoigne les compteurs :
Passés quelques jours, les deux branches ont évolué chacune de leur côté et il est temps d’envisager de fusionner les travaux.
Fusion de branche
Voilà maintenant l’état de mon dépôt :
Vous observerez que la branche default
a reçu 3 commits (révisions 5, 7 et 8) et que la branche config
en a reçu 3 également (révisions 4, 6 et 9).
Pour l’instant mon répertoire de travail reflète la branche default
et je souhaite fusionner ce qui a été fait sur la branche config
pour bénéficier du travail qui y a été effectué. Pour cela je vais utiliser la commande merge disponible sur la barre d’outils :
MacHg m’indique la révision active 8
(en violet pâle) et je sélectionne la révision 9
que je veux fusionner avec la révision courante. Il m’indique alors ce qui adviendra : “The revision selected above (9) will be merged into the current revision (8).” soit en anglais ce que j’ai dit dans la phase précédente — ce qui tombe assez bien finalement !
MacHg me permet, avant de lancer le merge (la fusion en anglais), de vérifier les différences entre les deux révisions. Voilà un exemple de ce qu’on peut obtenir en utilisant le bouton View Differences
:
Vous voyez que le fichier _public.php
a été modifié dans les deux branches, la colonne de gauche représentant l’état de la révision 9
(branche config
) et la colonne de droite représentant l’état de la révision 8
(branche default
). Les parties rouges indiquent des suppressions, les vertes des ajouts et les violettes des modifications.
Lorsque je valide en cliquant sur le bouton Merge
, MacHg compare les fichiers et dossiers. Si un fichier n’a pas été modifié ou n’existe pas dans le répertoire de travail alors qu’il l’est dans la branche à fusionner alors il l’ajoute directement. Par contre, si un fichier a été modifié dans les deux branches, MacHg me propose alors de résoudre ce conflit.
La commande terminal équivalente est la suivante (9
est le numéro de la révision à fusionner avec la branche courante) :
hg merge -r 9
Résolution de conflit
Dans le merge qui nous occupe, deux fichiers ont été modifiés dans les deux branches : _define.php
où un numéro de version à été changé et _public.php
dont les modifications sont visibles sur la différence des révisions illustrée plus haut.
Pour résoudre ces conflits il faut alors utiliser un outil qui va nous permettre de spécifier, pour chacune des modifications existantes — qu’elles soient présentes dans l’une ou l’autre des branches à fusionner — ce qu’on décide de garder, modifier ou ignorer. Sur Mac OS X j’ai sélectionné une application nommée DiffMerge qui permet justement de ces opérations — cette application fonctionne également sur Windows et Linux et est à mon avis la plus facile à appréhender.[1].
Pour le premier fichier, _define.php
, voilà ce que DiffMerge, appelé par MacHg pour résoudre ce premier conflit, me propose :
Je ne vais pas entrer dans le détail de l’utilisation de cet outil mais simplement signaler très succinctement que :
- L’affichage présente trois colonnes :
- une première à gauche avec le fichier dans son état actuel dans le répertoire de travail ;
- une deuxième au centre qui présente l’état final qu’aura le fichier[2] ;
- une troisième colonne à droite qui présente le fichier en provenance de la branche à fusionner.
- Une barre d’outils vous permet :
- de parcourir les différentes modifications ;
- de choisir si la modification à conserver doit être prise dans la colonne de gauche ou de droite ;
- de sauvegarder le fichier final (représenté par la colonne centrale).
Pour ce fichier je choisis de conserver la plus haute valeur du numéro de version spécifié dans le code (colonne de gauche et donc branche default
), je sauvegarde le résultat et ferme la fenêtre (ce qu’attendait MacHg pour me proposer la suite de la fusion).
Pour le second fichier, _public.php
, j’ai récupéré à droite et à gauche ce qui me paraissait le plus opportun et j’en ai profité pour modifier au passage le code résultant. Voilà le résultat, juste avant la sauvegarde :
Une fois cette résolution des conflits terminée, MacHg m’informe qu’il va falloir faire un commit pour enregistrer le résultat du merge :
Puis m’indique la fin de la fusion avec un message récapitulatif :
Observons maintenant la liste des révisions :
Vous voyez que les deux branches se rejoignent (lignes en pointillé) et que le prochain commit permettra d’enregistrer cela dans le dépôt. Ce que je fais immédiatement avant de faire un push pour synchroniser mon dépôt distant. Je me retrouve alors avec une branche default
dans laquelle j’ai rapatrié les modifications effectuées dans la branche config
:
Notez que je peux tout à fait continuer le travail sur la branche config
, il suffit pour cela d’utiliser la commande update, sans répercutions sur la branche default
.
Si je souhaite fermer définitivement la branche config
il faut alors, après avoir fait un update vers la dernière révision de la branche config
, sous terminal (MacHg n’est pas encore capable de le faire nativement), faire :
hg commit --close-branch -m 'fermeture branche config'
Conclusion
Vous savez maintenant l’indispensable pour gérer des dépôts Mercurial sur lesquels peuvent coexister plusieurs branches de développement que l’on peut fusionner en fonction des besoins. Vous pouvez ainsi créer autant de branches que vous le souhaitez, les fusionner, voire même les fermer si elles ne vous servent plus.
Nous verrons dans la prochaine leçon comment faire pour annuler le dernier commit, voire de supprimer toute une série de révision sur un dépôt. Ça peut parfois servir, d’ailleurs ça l’a été pour le projet Dotclear où il a fallu faire un strip (suppression sans retour en arrière possible d’une série de révisions) assez conséquent.
Glossaire
merge : fusion de deux branches.
Pour en savoir plus
- Wikipedia : La fusion (logiciels de gestion de version)