Feature Branch Workflow
Le Feature Branch Workflow est un workflow Git dans lequel chaque fonctionnalité est développée dans sa propre branche, puis intégrée à la branche principale main après une relecture, au moyen d'une merge request (MR).
La semaine A05 en a présenté le principe (voir Workflow Git). Cette page détaille son fonctionnement technique : les commandes Git, les étapes sur GitLab et la publication des versions.
Ce workflow est très répandu pour les applications web livrées en continu. GitHub le décrit sous le nom de GitHub flow (avec des pull requests, l'équivalent des merge requests de GitLab).
Source : GitHub Docs - GitHub flow
Principe
Une branche principale toujours stable
- Une seule branche permanente :
main. maincontient uniquement du code terminé, relu et fonctionnel → elle peut être déployée en production à tout moment.- Personne ne fait de commit directement dans
main: GitLab l'interdit si la branche est protégée (voir Protéger la branche main).
Une branche par fonctionnalité
- Chaque fonctionnalité ou correction est développée dans une branche dédiée, créée depuis
main(ex.feature/blog-joel.dacomo,fix/footer-color). - La branche a une durée de vie courte : quelques heures à quelques jours. Elle est supprimée dès qu'elle est fusionnée.
- Tant que le travail n'est pas fusionné, il n'a aucun effet sur
mainni sur le travail des autres.
La merge request
Une merge request est une demande, faite sur GitLab, de fusionner une branche (la branche source) dans une autre (la branche cible, ici main).
Elle permet
- De relire les modifications (onglet
Changes) et de les commenter ligne par ligne. - De corriger le code avec de nouveaux commits sur la même branche : la MR se met à jour automatiquement à chaque
push. - D'approuver les modifications (
Approve), puis de les fusionner (Merge) avec un clic. - De garder une trace de la discussion, même après la suppression de la branche.
Analogie
Une merge request ressemble à la relecture d'un rapport avant son envoi : vous rédigez votre partie dans un brouillon (la branche), un collègue la relit et annote les passages à corriger (les commentaires), vous corrigez (nouveaux commits), puis il donne son accord et votre partie est ajoutée au document officiel (la fusion dans main).
Source : GitLab Docs - Merge requests
Comparaison avec Gitflow
| Critère | Gitflow Workflow | Feature Branch Workflow |
|---|---|---|
| Branches permanentes | main et develop |
main uniquement |
| Branches temporaires | feature/…, release-…, hotfix-… |
feature/…, fix/… |
| Intégration d'une branche | Merge local, puis push de develop |
Merge request relue, puis fusion sur GitLab |
| Relecture du code | Non prévue par le workflow | Au coeur du workflow (merge request) |
| Publication d'une version | Branche release-… fusionnée dans main et develop |
Tag sur un commit de main |
| Adapté à | Logiciels publiés en plusieurs versions maintenues en parallèle | Applications web livrées en continu (une seule version en production) |
Note
Gitflow n'est pas "faux" : il reste adapté aux logiciels dont plusieurs versions doivent être maintenues en même temps (ex. version 2.x et 3.x d'une bibliothèque).
Pour un site web, qui n'a qu'une seule version en production, develop et les branches release ajoutent surtout des étapes et des risques de conflit.
Source : Vincent Driessen - A successful Git branching model (Note of reflection)
Cycle de vie d'une fonctionnalité
Les commandes ci-dessous ont toutes un équivalent dans IntelliJ IDEA (menu Git et fenêtre Git).
Elles utilisent git switch, une commande plus récente que git checkout et dédiée uniquement au changement de branche (git checkout, vu au TP05.2, fonctionne aussi).
main A---B-----------------M
\ /
feature/x C-----D-----E
| | |
commits, push, relecture et corrections
Créer la branche
-
Mettez à jour la branche
mainlocale :git switch main git fetch git rebase origin/main -
Créez la branche de la fonctionnalité depuis
mainet basculez dessus :git switch -c feature/blog-joel.dacomo→ Equivalent de
git checkout -b feature/blog-joel.dacomo.
Source : Git - Reference (git switch)
Développer et pousser
- Faites des commits comme d'habitude : un ensemble logique de modifications par commit, avec un message qui respecte les règles vues en cours.
-
Envoyez la branche sur
origindès les premiers commits, pour la sauvegarder et la rendre visible :git push -u origin feature/blog-joel.dacomo- L'option
-u(--set-upstream) relie la branche locale à la brancheorigin/feature/blog-joel.dacomo: lespushsuivants se font simplement avecgit push.
- L'option
Source : Git - Reference (git push, --set-upstream)
Ouvrir une merge request
Sur GitLab, dans le projet : Code → Merge requests → New merge request.
- Choisissez la branche source (
feature/blog-joel.dacomo) et la branche cible (main). - Rédigez un titre clair et une description : ce que fait la MR, comment la tester, ce qui reste à faire.
- Si le projet contient un modèle de MR (fichier
.gitlab/merge_request_templates/Default.mdde la branchemain), GitLab pré-remplit la description avec son contenu, par exemple une liste de contrôles à cocher.
- Si le projet contient un modèle de MR (fichier
- Indiquez la personne qui relit votre travail dans le champ
Reviewer. - Laissez cochée l'option de suppression de la branche source après la fusion.
Merge request en brouillon (Draft)
Vous pouvez ouvrir la MR avant d'avoir terminé, en la marquant comme brouillon (Mark as draft, ou préfixe Draft: dans le titre).
Une MR en brouillon ne peut pas être fusionnée : elle sert à montrer l'avancement et à demander un avis tôt. Retirez le statut de brouillon (Mark as ready) quand le travail est prêt à être relu.
Source : GitLab Docs - Draft merge requests
Source : GitLab Docs - Description templates
Relire et corriger
Personne qui relit (reviewer)
- Récupère la branche pour tester le résultat :
git fetch, puisgit switch feature/blog-joel.dacomo. - Lit les modifications dans l'onglet
Changesde la MR et laisse des commentaires sur les lignes concernées. - Approuve la MR (
Approve) quand les corrections sont faites.
Auteur de la MR
- Corrige dans de nouveaux commits sur la même branche, puis
git push: la MR se met à jour automatiquement. - Répond aux commentaires et marque les discussions comme résolues (
Resolve thread).
Mettre à jour la branche
Pendant que vous travaillez, d'autres MR sont fusionnées : main avance et votre branche est "en retard".
Avant la fusion, rejouez vos commits par-dessus la version actuelle de main avec un rebase :
Avant le rebase Après le rebase
main A---B---F---G main A---B---F---G
\ \
feature/x C---D feature/x C'---D'
-
Mettez à jour votre branche :
git fetch git switch feature/blog-joel.dacomo git rebase origin/main -
En cas de conflit, Git interrompt le
rebasesur le commit qui pose problème et place des marqueurs de conflit (<<<<<<<,=======,>>>>>>>) dans les fichiers concernés :- Ouvrez chaque fichier en conflit (ou utilisez la fenêtre de résolution des conflits d'IntelliJ IDEA), gardez les modifications des autres et les vôtres, et supprimez les marqueurs.
- Indiquez à Git que le conflit de ce fichier est résolu :
git add <fichier>. - Une fois tous les fichiers résolus, reprenez le
rebase:git rebase --continue.- Git recrée le commit avec le contenu corrigé, puis rejoue le commit suivant : d'autres conflits peuvent encore apparaître.
- En cas de doute,
git rebase --abortannule tout et remet la branche dans son état d'avant lerebase.
-
Envoyez la branche réécrite :
git push --force-with-lease
Si aucun conflit n'est possible, GitLab propose aussi un bouton Rebase directement dans la MR.
Pourquoi git add pendant un rebase ?
Pendant un rebase, git add ne prépare pas un nouveau commit : il marque le conflit du fichier comme résolu, en plaçant sa version corrigée dans l'index (la staging area, voir Git).
- Tant qu'un fichier en conflit n'a pas été ajouté à l'index, Git le considère comme non résolu et
git rebase --continuerefuse de continuer. - C'est le contenu de l'index que
git rebase --continueutilise pour recréer le commit interrompu (ex.C'dans le schéma ci-dessus).
Analogie : le git add revient à dire à Git "j'ai fini de corriger ce fichier, tu peux reprendre".
Source : Git - Reference (git rebase)
Pourquoi un push forcé, et pourquoi --force-with-lease
Le rebase crée de nouveaux commits (C' et D', avec de nouveaux identifiants) qui remplacent C et D.
origin/feature/blog-joel.dacomo contient encore les anciens commits : un git push normal est refusé, car il ferait "disparaître" des commits de origin.
--forceremplace la branche suroriginsans aucun contrôle, même si quelqu'un y a poussé des commits entre-temps.--force-with-leasene remplace la branche que si elle est encore dans l'état que vous connaissez (celui de votre dernierfetch). Sinon, lepushest refusé et rien n'est perdu.
🚨 Réécrire l'historique est acceptable uniquement sur votre propre branche feature, sur laquelle personne d'autre ne travaille.
Jamais de push forcé sur main ou sur une branche partagée : vous effaceriez le travail des autres (voir TP05.2).
Fusionner
Quand la MR est approuvée et à jour, la personne autorisée clique sur Merge dans GitLab.
La fusion a lieu sur le serveur GitLab : personne ne fait de merge local dans main.
GitLab supprime alors la branche source sur origin (si l'option est cochée) et la MR passe à l'état Merged.
Nettoyer
Après la fusion, mettez à jour votre dépôt local et supprimez la branche locale :
git switch main
git fetch --prune
git rebase origin/main
git branch -d feature/blog-joel.dacomo
--prunesupprime les références locales (origin/feature/…) des branches qui n'existent plus surorigin.git branch -drefuse de supprimer une branche dont les commits n'ont pas été fusionnés.- Après un
rebasefait par GitLab (boutonRebase), vos commits locaux ont d'autres identifiants que ceux demain: vérifiez dans l'historique que votre travail est bien dansmain, puis utilisezgit branch -Dpour forcer la suppression.
- Après un
Sources :
Méthodes de fusion dans GitLab
La méthode de fusion est choisie pour tout le projet (Settings → Merge requests → Merge method).
Merge commit
- GitLab crée toujours un commit de fusion, comme
git merge --no-ff. - La branche peut être fusionnée même si elle est en retard sur
main.
main A---B---F-------M
\ /
feature/x C-------D
Merge commit with semi-linear history
- GitLab crée un commit de fusion, mais seulement si la branche est à jour par rapport à
main: sinon, il faut d'abord faire unrebase. - Chaque fonctionnalité reste visible comme un groupe de commits, et elle a été testée sur la version actuelle de
main.
main A---B---F-----------M
\ /
feature/x C'------D'
Fast-forward merge
- Pas de commit de fusion : les commits de la branche sont ajoutés directement à la suite de
main(historique linéaire). - La branche doit aussi être à jour par rapport à
main.
main A---B---F---C'---D'
Squash
L'option squash regroupe tous les commits de la branche en un seul commit au moment de la fusion. Elle simplifie l'historique, mais fait disparaître le détail des commits : dans ce cours, où la qualité de chaque commit est évaluée, elle n'est pas utilisée.
Sources :
Protéger la branche main
Une branche protégée est une branche sur laquelle GitLab limite les actions possibles. La configuration se fait dans Settings → Repository → Branch rules (rôle Maintainer nécessaire).
Configuration habituelle pour ce workflow
Allowed to push and merge→No one: personne ne peut faire depushdirectement surmain.Allowed to merge→Developers + Maintainers: les membres du projet peuvent fusionner une MR.Allowed to force push→ désactivé : lepushforcé est interdit surmain.
La seule façon de modifier main est une merge request : la règle "pas de commit direct dans main" est appliquée par GitLab, et non plus seulement par la discipline de chacun.
Source : GitLab Docs - Protected branches
Approbation obligatoire
Dans les éditions Premium et Ultimate de GitLab (c'est le cas du GitLab de l'école), on peut aussi exiger une approbation avant toute fusion (Settings → Merge requests → Merge request approvals) :
- Règle
All eligible usersavecApprovals required→1: le boutonMergereste bloqué tant que la MR n'a pas été approuvée. Prevent approval by merge request creator (author): l'auteur ne peut pas approuver sa propre MR.Remove all approvalslorsqu'un commit est ajouté (facultatif) : après chaque correction ourebase, la MR doit être approuvée à nouveau.
Sources :
Versions et releases
Sans branche release, une version correspond simplement à un commit de main, marqué par un tag.
Changelog
- En haut du fichier
CHANGELOG.md, une section## [Unreleased]regroupe les modifications pas encore publiées. - Chaque merge request ajoute sa ligne dans cette section (sous
### Added,### Changed,### Fixed…) : le changelog est relu avec le code. - Au moment de publier, la section
[Unreleased]devient la section de la nouvelle version (ex.## [0.5.0] - 2026-11-05), et une nouvelle section[Unreleased]vide est créée au-dessus. Commemainest protégée, cette modification passe elle aussi par une MR.
## [Unreleased]
### Added
- Blog page of Joël Dacomo
- Blog page of …
Source : Keep a Changelog - Keep a Changelog (2.0.0)
Tags
Un tag est une étiquette permanente posée sur un commit précis, par exemple pour marquer une version publiée.
- Tag annoté (
-a) : contient l'auteur, la date et un message → à utiliser pour les versions. - Tag léger (sans
-a) : simple nom donné à un commit, pour un usage personnel ou temporaire.
git switch main
git fetch
git rebase origin/main
git tag -a v0.5.0 -m "Release 0.5.0"
git push origin v0.5.0
- Le tag est posé sur le dernier commit de
main, après la fusion de la MR qui met à jour le changelog. - Un
git pushordinaire n'envoie pas les tags : il faut les envoyer explicitement. - Le préfixe
v(v0.5.0) est une convention courante pour les noms de tags (le numéro de version lui-même reste0.5.0).
Sources :
- Git - Reference (git tag)
- Semantic Versioning - Semantic Versioning 2.0.0 (FAQ - Is "v1.2.3" a semantic version?)
Releases GitLab
Une release GitLab est une page qui présente une version publiée : notes de version (ex. reprises du changelog) et archives du code source à télécharger.
- Elle repose sur un tag Git : on la crée dans
Deploy→Releases→New release, en choisissant le tag (ou en le créant à cette occasion). - Le rôle Developer suffit pour créer une release.
Source : GitLab Docs - Releases
Corrections
Il n'y a pas de branche hotfix : une correction est une modification comme une autre.
- Branche
fix/…créée depuismain(ex.fix/footer-color). - Merge request, relecture, fusion.
- Si la correction doit être publiée seule : nouvelle version avec le numéro de correctif incrémenté (ex.
0.5.0→0.5.1).
Commandes Git de ce workflow
| Commande | Description |
|---|---|
git switch <branche> |
Bascule sur une branche existante |
git switch -c <branche> |
Crée une branche depuis la branche actuelle et bascule dessus |
git push -u origin <branche> |
Envoie une nouvelle branche sur origin et relie la branche locale à celle-ci |
git rebase origin/main |
Rejoue les commits de la branche actuelle par-dessus la dernière version de main |
git push --force-with-lease |
Remplace la branche sur origin après un rebase, seulement si personne n'y a poussé entre-temps |
git fetch --prune |
Récupère les nouveautés de origin et oublie les branches supprimées sur origin |
git branch -d <branche> |
Supprime une branche locale déjà fusionnée |
git tag -a <tag> -m "<message>" |
Crée un tag annoté sur le commit actuel |
git push origin <tag> |
Envoie un tag sur origin |
Bonnes pratiques
- Une merge request = une fonctionnalité ou une correction : de petites MR sont plus faciles et plus rapides à relire.
- Relisez vous-même votre MR (onglet
Changes) avant de demander une relecture. - Mettez souvent votre branche à jour avec
main: plus la branche vit longtemps, plus les conflits sont nombreux. - Ne fusionnez pas une MR qui n'a pas été relue, même si GitLab le permet.
- Supprimez les branches fusionnées, sur
originet en local.