{{tag> git}}
====== Git Workflow ======
{{ :development:git-model2x.png?direct&400|}}
Cette page est une traduction et une synthèse de l'article de
[[http://nvie.com/about/|Vincent Driessen]] dans [[http://nvie.com/posts/a-successful-git-branching-model/|A successful git branching model]]
Cette traduction ne reflète pas le modèle pratiqué au sein d'Elosys
mais sert de point de départ à la compréhension d'un workflow git.
En travaillant avec git, chaque collaborateur a un dépôt. Dans les
faits, tout dossier contenant un sous-dossier ''.git'' est un dépôt.
Dans le modèle centralisé, un dépôt central reçoit les commits des
collaborateurs pour les rendre disponibles à l'ensemble des
participants du projet, mais ce n'est pas le seul moyen d'échanger
ses commits.
Dans ce qui suit ''dépôt'' ou ''repo'' désignera la copie locale de
chaque collaborateur.
Dépôt central ou ''central repos'' désignera le dépôt qui sert de
point d'échange entre tous les intervenants. C'est par exemple ce
que nous que nous désignons par une adresse du type
''git@git.elosys.net:group/projet.git''.
----
===== Les branches principales =====
Dans un modèle centralisé le ''dépôt central'' contient deux branches
principales avec une durée de vie illimitée :
{{ development:main-branches@2x.png?direct&200 }}
* ''master''
* ''develop''
Du point de vue du collaborateur ces deux branches correspondent au
résultat de la commande
git branch -r
* ''origin/master''
* ''origin/develop''
On va considérer ''origin/master'' comme branche principale où le
code source reflète l'état __production-ready__.
On va considérer ''origin/develop'' comme branche principale où le
code source reflète les derniers changements en vue de la prochaine
''release''.
Quand le code source de la branche develop atteint un point de
stabilité et est prêt pour une release tous les changements qui y
ont été apportés doivent être mergés dans master puis taggé avec un
numéro de release.
Ainsi, quand tous ces changements sont mergés dans master, cela
représente de fait une release de production.
Nous aurons tendance a être strict sur ce point car théoriquement
nous pourrons utiliser un Git hook pour automatiser un build ou un
déploiement sur un serveur de production à chaque fois qu'il y a un
commit sur master.
===== Les branches de support =====
Les branches de support sont là pour aider aux développements
parallèles entre les membres des équipes, faciliter le suivi des
releases, préparer les releases de production et aider aux
dépannages rapide des problèmes en production.
Contrairement aux branches principales, ces branches ont une durée
de vie limitée puisqu'elle seront éventuellement effacées.
* Feature branches (branches de fonctionnalité)
* Release branches (branches de release)
* Hotfix branches (branches de dépannages à chaud)
Chacune de ces branches a un objectif précis et des règles strictes.
==== Feature branches (branches de fonctionnalité) ====
* **Démarrent depuis** : develop
* **Retournent à** : develop
* **Nommées** : tout sauf master, develop, release-\* ou hotfix-\*
{{ development:fb@2x.png?direct&100 }}
Appelées aussi ''topic branches'', les feature branches sont
utilisées pour développer de nouvelles fonctionnalités pour une
plus ou moins proche release.
Quand on commence à développer une nouvelle fonctionnalités la
release cible (''target release'') dans laquelle cette fonctionnalité
sera incorporée peut être connue.
La feature branch (branche de fonctionnalité) existe tant que la
fonctionnalité est en développement.
Elle peut soit être mergée dans la branche ''develop'' pour
définitivement ajouter cette fonctionnalité dans la prochaine
release soit abandonnée en cas d'expérience déroutante.
Typiquement, les branches de fonctionnalité (feature branches)
demeurent dans les dépôts des développeurs seulement et on ne les
retrouvent pas dans ''origin''.
=== Création d'une branche de fonctionnalité ===
On démarre toujours une branche de fonctionnalité depuis la branche develop
$ git checkout -b mafonctionalite develop
Switched to a new branch "mafonctionalite"
=== Incorporer une fonctionnalité achevée dans develop ===
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff mafonctionalite
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d mafonctionalite
Deleted branch mafonctionalite (was 05e9557).
$ git push origin develop
L'option ''--no-ff'' va obliger le merge a créer un commit de merge même
si le merge aurait pu se faire en fast-forward. Cela permet d'éviter
de perdre l'information de l'existence d'une branche de
fonctionnalité.
{{ development:merge-without-ff2x.png?direct&400 }}
Sans l'option ''--no-ff'' il est impossible de voir dans l'historique de
Git quel est la série de commits qui a introduit la fonctionnalité.
Défaire ces commits ultérieurement serait très difficile.
Cela va bien sûr créer des commits vides mais le gain en vaut le coup.
==== Release branches (branches de release) ====
* **Démarrent depuis** : develop
* **Retournent à** : develop **ET** master
* **Nommées** : release-\*
Les branches de release sont là pour la préparation d'une release
de production. C'est la branche où on fait les derniers
peaufinages : dépannage de bugs mineurs, réglages des métadata de
la release (le numéro de version, la date de sortie etc).
En faisant cela sur une branche de release, la branche develop est
nettoyée pour recevoir les fonctionnalités pour la prochaine grande
release.
Le moment clé pour faire sortir une branche de release depuis la
branche develop est quand cette dernière reflète l'état désiré pour
la prochaine release.
Tout au moins toutes les fonctionnalités (features) qui ont été
ciblées pour cette release doivent être mergées dans develop à ce
moment.
Toutes les fonctionnalités qui ont été ciblées pour une release
postérieure doivent attendre que la release branche soit sortie
(branched off)
C'est exactement au début d'une release branch que la prochaine
release se voit attribuée un numéro de version et pas avant.
Jusqu'à ce moment la branche develop reflète les changements pour
la prochaine release mais il n'est pas encore décidé si cette
prochaine release sera une 0.3 ou une 1.0 jusqu'à ce que la branche
de release soit démarrée.
La décision est fait au début de la branche de release et dépend
des règles du projet sur la numérotation de versions.
=== Création d'une branche de release ===
Les branches de release sont créées à partir de la branche
develop. Admettons, par exemple, que la version de production
actuelle est 1.1.5 et que nous avons une grande release à venir.
L'état de la branche develop est prêt pour la prochaine release et
nous avons décidé que le numéro de version sera 1.2 (au lieu de
1.1.6 ou 2.0).
$ git checkout -b release-1.2 develop
Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2
Files modified successfully, version bumped to 1.2.
$ git commit -a -m "Bumped version number to 1.2"
[release-1.2 74d9424] Bumped version number to 1.2
1 files changed, 1 insertions(+), 1 deletions(-)
Après avoir créé une nouvelle branche et switché dedans on
applique le numéro de version. Ici, ''bump-version.sh'' est un
script shell imaginaire qui change quelques fichiers pour indiquer
la nouvelle version. Cela peut bien sûr être fait à la main. Puis
l'ajout du numéro de version est commité.
Cette nouvelle branche peut rester là un certain temps avant que
la release ne se produise définitivement en la mergeant dans la
branche master. Pendant ce temps, des bug fixes peuvent être
appliqués à cette branche au lieu de la branche develop.
L'ajout de grandes nouvelles fonctionnalités est strictement
interdit. Celles-ci doivent être mergées dans la branche develop
et attendre la prochaine grande release.
=== Fin d'une branche de release ===
Quand l'état de la branche release est prêt à devenir une vraie
release, certaines actions sont à effectuer.
* La branch release est mergée dans master (chaque commit dans master est une nouvelle release par définition)
* Ce commit doit être tagé pour faciliter sa référence dans l'historique du projet.
* Enfin, les changements fait sur la branch release doivent être mergés en retour dans la branch develop pour que les futurs releases comportent les bug fixes qui ont été apportés.
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2
Pour garder les changements apportés à la release branch, on doit
les merger dans la branch develop.
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
Cette étape peut donner lieu à un conflit de merge (c'est plus que
probable puisque le numéro de version a été changé)
Maintenant que les choses sont faites, la release branch peut être
supprimé. Nous n'en avons plus besoin.
$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).
==== Hotfix branches (branches de dépannages à chaud) ====
* **Démarrent depuis** : master
* **Retournent à** : develop **ET** master
* **Nommées** : hotfix-\*
{{development:hotfix-branches@2x.png?direct&200 }}
Les branches de dépannage sont semblables aux branches de release
car elles visent à préparer une nouvelle release de production. La
différence c'est qu'elles ne sont pas planifiées.
Elles naissent de la nécessité d'agir rapidement pour corriger un
état indésirable de fonctionnement en production.
Quand un bug critique dans la version de production doit être
résolu immédiatement, une branche hotfix est créée à partir d'un
tag de la branche master qui représente la version en production.
=== Création de la branche hotfix ===
Les branches hotfix sont créées à partir de la branche master.
Admettons que la version 1.2 est la version de production live en
cours et qu'elle connaît un bug sévère.
La branche develop de son côté est encore instable.
$ git checkout -b hotfix-1.2.1 master
Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)
Le numéro de version est modifié dès la création de la branche.
La réparation peut se faire ensuite en un ou plusieurs commits.
$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)
=== Clôture de la branche hotfix ===
Une fois terminée, la correction du bug doit être mergée dans
master mais également dans develop de façon à ce que cette
correction soit également incluse dans la prochaine release.
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2.1
Ensuite, on ajoute le bugfix à la branche develop.
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
La seule exception à ce schéma, c'est lorsqu'une branche release
est en cours. Les changements de la branche hotfix doivent être
mergés dans la branche release au lieu de la branche develop.
Le merge du hotfix dans la branche release va de toute manière
être inclus dans la branche develop quand la branche release est
achevée.
(Si la branche develop requière immédiatement cette correction de
bug et ne peut attendre la fin de la release branch, on peut
également y merger le bugfix)
Enfin, cette branche temporaire est supprimée.
$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).
===== Conclusions =====
Les branches renseignent sur les états d'avancement et de stabilité
d'un projet. Il suffit de constater la présence d'une branche hotfix
pour saisir que le projet connait une situation critique puisque
l'intervention concerne un code déployé en production.
Les branches release sont également un moment fort dans la vie d'un
projet car elles renseignent sur la prochaine mutation du code en
production et valident les travaux entrepris jusque-là sur les
branches de fonctionnalité.
Au-delà de la facilité et des optimisations introduites par Git dans
la gestion du code source, ce système est un indicateur de la
vitalité des projets qui l'utilisent.