L’utilisation conjointe de Maven pour réaliser des release et de git-flow peut s’avérer laborieuse.
En effet, lorsque vous travaillez avec des branches (quelque soit le SCM), une bonne pratique veut que chaque branche possède son propre numéro de version. Afin d’éviter des collisions de nommage, cette pratique devient indispensable lorsque vous utilisez un serveur d’intégration continue pour publier les artefacts construits dans un repo Maven.
Une fois une branche crée à partir d’une autre, chaque branche vit sa vie. Des releases Maven peuvent être réalisées de part et d’autre. Là où cela devient tendu, c’est lorsque vous devez reporter les commits d’une branche vers une autre. Des conflits de merge sur le numéro de version Maven apparaissent alors inévitablement. Lorsque votre application multi-modules comporte 15 pom.xml, c’est 15 conflits qu’il va falloir gérer manuellement. Il est effectivement risqué de conserver aveuglément la version du pom.xml local ou distant, car d’autres changements (et vrais conflits) peuvent se produire dans d’autres sections du pom.xml.
Comme cas d’études, prenons l’exemple du repo Git helloworld :
Une application HelloWorld construite avec Maven a été releasée avec Maven en version 1.0.0 sur la branche develop. La prochaine version renseignée sur develop est 1.1.0-SNAPSHOT.
Une branche de maintenance release/1.0.x a ensuite été créée à partir du tag pointant sur le commit « [maven-release-plugin] prepare release helloworld-1.0.0 ». Une faute d’orthographe a été corrigée. Afin de la livrer en production rapidement, une version 1.0.1 a été réalisée avec Maven.
Cette correction doit désormais être reportée sur la branche develop. Entre temps, 2 commits ont été réalisés sur celle-ci, dont l’un touchant au pom.xml.
Quelle solution adopter pour effectuer ce report ?
Une première solution consiste à utiliser un cherry-pick du commit « Fix spelling ». Pour rappel, cherry-pick permet de reporter commit par commit les différences entre branche. Le risque est d’oublier un commit. Et cette solution peut devenir laborieuse si beaucoup de commits séparent les 2 branches.
Une seconde solution consiste à merger la branche release/1.0.x dans la branche develop.
Apparaît alors le conflit sur le numéro de version du pom.xml évoqué en introduction :
git merge release/1.0.x Auto-merging src/main/java/com/compagny/HelloWorld.java Auto-merging pom.xml CONFLICT (content): Merge conflict in pom.xml Automatic merge failed; fix conflicts and then commit the result. git diff diff --cc pom.xml index b43c671,01257f6..0000000 --- a/pom.xml +++ b/pom.xml @@@ -6,9 -6,9 +6,13 @@@ <groupId>com.mycompagny</groupId> <artifactId>helloworld</artifactId> ++<<<<<<< HEAD + <version>1.1.0-SNAPSHOT</version> ++======= + <version>1.0.2-SNAPSHOT</version> ++>>>>>>> release/1.0.x - <description>Hello World application</description> + <description>Git merge demonstration</description>
Le conflit doit être résolu manuellement : la version 1.1.0-SNAPSHOT de la branche develop est à conserver.
Une solution permettant d’éviter de résoudre ce genre de conflits consiste à utiliser un script que va utiliser Git pour merger 2 fichiers pom.xml. C’est précisément l’objectif du driver de merge mergepom.py écrit en Python et que vous pouvez récupérer sur le repo GitHub pom-merge-driver.
L’utilisation de ce script sous Linux et Mac est décrite dans le README.md.
Sur Windows, il est nécessaire de faire quelques adaptations :
- Télécharger et installer Python (la version portable est suffisante)
- Dans le script mergepom.py, supprimer la ligne d’en-tête #! /usr/bin/env python
- Dans le fichier .gitconfig, ajouter le chemin vers python.exe :
[merge "pommerge"] name = A custom merge driver for Maven's pom.xml driver = '/C/dev/python/python.exe' C:/dev/git/mergepom.py %O %A %B
Afin de laisser la liberté aux autres développeurs d’utiliser ce script ou non, j’ai ajouté le fichier attributes dans le répertoire .git/info de mon repo local :
pom.xml merge=pommerge
Remarque : alternativement, on peut également ajouter cette ligne dans le fichier .gitattributes situé dans le répertoire racine du repo Git. Tous les développeurs de l’application en profitent alors.
On relance la commande de merge. Cette fois-ci, le script détecte un conflit sur le numéro de version du pom.xml et décide de garder celui de la branche courante, à savoir 1.1.0-SNAPHSOT :
git merge release/1.0.x Merging pom version 1.0.2-SNAPSHOT into develop. Keeping version 1.1.0-SNAPSHOT Auto-merging src/main/java/com/compagny/HelloWorld.java Auto-merging pom.xml Merge made by the 'recursive' strategy. pom.xml | 2 +- src/main/java/com/compagny/HelloWorld.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
Le script Python respecte le workflow git-flow. De ce fait, les merge dans le master des branches de release et de hotfix conservent le numéro de version de ces dernières.
Comme moi, j’espère que l’existence de ce driver de merge Git vous simplifiera vos merges. Ne prenant en compte que les fichiers pom.xml encodé en UTF-8, j’ai fait une demande d’évolution. En attendant, vous pouvez changer l’encodage en dur dans le script ou bien, encore mieux, soumettre une pull request.
Enfin, sachez que d’autres drivers de merge Git existent. pomutils est écrit en Java. Si vous en avez testé, n’hésitez pas à laisser un feedback.
Très utile, merci pour ce tutoriel
Merci pour l’article qui m’a appris des choses 🙂
J’ai eu des probleme avec le script python conseillé qui ne semble pas supporter les versions récentes de Python. Alors je viens de commencer à tester la même chose en Java qui semble pour l’instant faire le job: https://github.com/cecom/pomutils
Voila, c’etait juste pour info. Merci !
Merci François pour ce retour. Pour ma part, j’utilise Python 3.6.0a4 sous Windows 7.
J’ai collègue qui utilise pomutils et il en ai également très satisfait.