Aller au contenu principal

Stratégie de branches Git sur GitHub : laquelle choisir selon ton projet

GitHub Flow, Git Flow, trunk-based : chaque modèle répond à un contexte précis. Cet article part de cinq situations, du portfolio en solo à l'équipe qui livre plusieurs fois par jour, et montre pour chacune la stratégie qui tient, les réglages GitHub qui l'accompagnent et les erreurs qui font dérailler une équipe.

Outils & environnement ·
Adel LATIBI
Adel LATIBI
Stratégie de branches Git sur GitHub : laquelle choisir selon ton projet

Le Briefing Dev - les ressources et actus de la semaine, droit dans ta boîte chaque vendredi gratuitement.

En vous inscrivant, vous acceptez de recevoir notre newsletter. Désinscription possible à tout moment.

Le schéma de Git Flow, avec ses branches develop, release et hotfix qui s'entrecroisent, circule depuis plus de quinze ans, des supports de cours jusqu'aux questions d'entretien. Beaucoup d'équipes l'ont adopté parce qu'il était là, sans se demander s'il collait à leur façon de livrer.

Pour une personne en reconversion ou un développeur junior qui arrive sur son premier projet à plusieurs, la question tombe vite : pourquoi cette équipe travaille avec une branche develop alors que celle d'à côté fusionne tout directement dans main ? Les deux ont souvent raison, chacune dans son contexte.

Le blocage vient de la façon dont ces stratégies sont présentées : on aligne des modèles, chacun avec son diagramme, sans donner les critères qui permettent de trancher. On retient les noms, rarement les raisons.

Ici, on prend le chemin inverse : on part des situations, du projet perso jusqu'à l'équipe qui déploie plusieurs fois par jour, et on associe à chacune une stratégie avec les réglages GitHub qui la font tenir. Si les bases (commit, branche, push) sont encore récentes, le guide Git pour débutants : le guide pratique pour coder sans stress reprend tout depuis le début.

Le problème : un modèle choisi pour de mauvaises raisons

Prends une équipe de trois développeurs sur une application web. Un seul serveur de production, des mises en ligne plusieurs fois par semaine, aucune ancienne version à maintenir. Elle adopte Git Flow parce que c'est « le standard ». Quelques mois plus tard, develop et main ne contiennent plus la même chose, une branche release est ouverte pour une correction de deux lignes, et chaque correctif urgent doit être fusionné à deux endroits. Le modèle ajoute des étapes sans rien protéger que l'équipe ait besoin de protéger.

Le détail le plus parlant vient de l'auteur de Git Flow lui-même. Vincent Driessen a publié le modèle en janvier 2010 sur son blog. En mars 2020, il a ajouté en tête de l'article d'origine une note de recul : pour une équipe qui livre une application web en continu, il conseille un flux plus simple comme GitHub Flow, et réserve Git Flow aux logiciels versionnés explicitement ou maintenus en plusieurs versions. Sa note se termine sur une consigne sans détour, « Consider your own context », que le reste de l'article applique à la lettre : tiens compte de ton propre contexte.

Le principe : les critères avant le modèle

Une stratégie de branches répond à une seule question : où vit le code pendant qu'il n'est pas encore en production, et comment il y arrive. Pour y répondre, cinq critères suffisent.

  • Le nombre de personnes qui poussent du code sur le dépôt.
  • Le rythme des mises en production : à chaque fusion, chaque semaine, ou à chaque version numérotée.
  • Le nombre de versions à maintenir en parallèle : une seule en ligne, ou une v2 et une v3 installées chez des clients différents.
  • La fiabilité de l'intégration continue (CI) : est-ce que des tests automatiques bloquent une fusion qui casse le projet ?
  • La possibilité de cacher une fonctionnalité inachevée en production, avec un interrupteur dans le code (un feature flag).

Le critère qui pèse le plus lourd est le troisième. Avec une seule version en ligne, aucune branche permanente n'est nécessaire à côté de main, puisque tout finit au même endroit. Dès qu'il faut corriger la v2 sans embarquer ce qui se prépare pour la v3, chaque version a besoin de sa propre branche, et la stratégie se complique mécaniquement.

Les commandes de l'article utilisent git switch, disponible depuis Git 2.23, plutôt que l'ancien git checkout pour changer de branche. Les réglages GitHub cités sont ceux de la documentation officielle au moment où ces lignes sont écrites, et certains dépendent de ton offre GitHub : c'est précisé à chaque fois.

Cinq situations, cinq façons de brancher

Situation 1 : seul sur un projet perso ou un portfolio

Travailler seul ne dispense pas des branches. Une branche courte par fonctionnalité, fusionnée dans main par une pull request (PR), laisse un historique lisible. Un recruteur qui ouvre ton dépôt voit des PR titrées, décrites, fusionnées une par une, là où un historique de cinquante commits « fix » poussés en direct sur main ne raconte rien.

# Git 2.23 ou plus
git switch -c feature/formulaire-contact
# ... tes commits ...
git push -u origin feature/formulaire-contact
# Ouvre ensuite la PR sur GitHub, relis le diff, fusionne

Relire son propre diff dans l'interface de GitHub avant de fusionner attrape souvent des oublis : un console.log resté là, un fichier de configuration local ajouté par erreur. Active aussi l'option Automatically delete head branches dans les paramètres du dépôt, pour ne pas accumuler des branches mortes. Si tu cherches de quoi remplir ce portfolio, la liste de projets backend pour débutants donne une base de départ.

Situation 2 : petite équipe, une seule production, déploiement à chaque fusion

C'est le terrain de GitHub Flow. Une règle unique : main est toujours déployable. Chaque changement part d'une branche créée depuis main, passe par une PR relue et testée, puis revient dans main, qui part en production.

Cette règle ne tient que si GitHub l'impose. Un ruleset sur main (section Rules des paramètres du dépôt) permet d'exiger une PR avant toute fusion, au moins une approbation, le passage des tests automatiques, et d'interdire le force push. Les rulesets sont disponibles sur les dépôts publics avec l'offre gratuite, et sur les dépôts privés à partir de GitHub Pro ou GitHub Team. Sur un dépôt privé en offre gratuite, main reste donc sans protection, et c'est à l'équipe de s'en souvenir.

Pour garder une branche courte et limiter les conflits, récupère régulièrement ce qui a bougé sur main :

git switch feature/filtre-recherche
git fetch origin
git rebase origin/main
# Le rebase réécrit tes commits : la branche distante doit être remplacée
git push --force-with-lease

--force-with-lease refuse d'écraser la branche distante si quelqu'un d'autre y a poussé entre-temps, ce que --force fait sans prévenir. Sur une branche partagée à plusieurs, cette différence évite de supprimer le travail d'un collègue.

Situation 3 : une recette à valider avant la production

Beaucoup de projets en agence ou en ESN passent par une recette où le client valide avant la mise en ligne. Le réflexe courant consiste à créer une branche par environnement, staging et production, et à fusionner de l'une vers l'autre. Ces branches finissent par diverger : un correctif appliqué directement en production n'est jamais remonté, et la recette teste un code qui ne correspond plus à ce qui tourne en ligne.

Avec GitHub, une autre voie existe : garder une seule branche main et faire porter les étapes par les environnements de GitHub Actions. Le même commit part d'abord en recette, puis en production.

# .github/workflows/deploiement.yml
name: Déploiement
on:
  push:
    branches: [main]
 
jobs:
  recette:
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - run: echo "Build et déploiement vers la recette"
 
  production:
    needs: recette
    runs-on: ubuntu-latest
    environment: production
    steps:
      - run: echo "Déploiement vers la production"

Sur l'environnement production, la règle Required reviewers met le job en attente jusqu'à ce qu'une personne désignée l'approuve. Le code validé en recette et le code mis en ligne sont alors strictement les mêmes.

Situation 4 : un logiciel versionné, plusieurs versions maintenues

Une bibliothèque publiée, une application installée chez des clients qui ne mettent pas tous à jour au même rythme : ici, plusieurs versions vivent en même temps et doivent recevoir des correctifs séparément. C'est le cas pour lequel Git Flow a été pensé, et il y reste pertinent, comme son auteur le rappelle.

Une variante plus légère suffit souvent : main reçoit le développement courant, et chaque version maintenue a sa branche de support (release/2.x, release/3.x). Un correctif part de la branche de la version concernée, puis il est reporté sur main pour ne pas réapparaître dans la version suivante.

# Correctif sur la version 2
git switch release/2.x
git switch -c fix/export-csv
# ... correction, PR vers release/2.x, fusion ...
 
# Report du correctif sur main
git switch main
git cherry-pick -x <sha-du-correctif>
 
# Publication de la version corrigée
git switch release/2.x
git pull
git tag -a v2.4.1 -m "Version 2.4.1"
git push origin v2.4.1

L'option -x ajoute au message du commit la référence du commit d'origine, ce qui permet de retrouver plus tard d'où vient chaque report. Côté GitHub, un ruleset peut cibler toutes les branches de support d'un coup avec un motif comme release/**/*, et les GitHub Releases transforment chaque tag en page de version avec des notes de version générables automatiquement à partir des PR fusionnées.

Le prix à payer est connu : chaque correctif demande au moins deux fusions, et plus il y a de versions maintenues, plus le risque d'en oublier une grandit. Si une seule version est en ligne à la fois, cette complexité ne rapporte rien.

Situation 5 : équipe rodée, CI solide, déploiements fréquents

Le trunk-based development pousse la logique de GitHub Flow au bout : tout le monde intègre son travail dans main au moins une fois par jour, les branches vivent quelques heures, et les fonctionnalités pas encore prêtes partent en production désactivées derrière un interrupteur.

// panier.js (Node.js, modules ES)
import { panierV1, panierV2 } from "./panier-versions.js";
 
const nouveauPanierActif = process.env.FLAG_NOUVEAU_PANIER === "true";
 
export function afficherPanier(utilisateur) {
  if (nouveauPanierActif) {
    return panierV2(utilisateur);
  }
  return panierV1(utilisateur);
}

Le nouveau panier est fusionné, déployé, mais invisible tant que la variable n'est pas activée. Plus besoin d'une branche qui vit trois semaines en attendant que la fonctionnalité soit terminée.

Quand beaucoup de PR arrivent sur main chaque jour, deux PR testées séparément peuvent casser le projet une fois réunies. La merge queue de GitHub règle ce cas : elle regroupe les PR en file, teste chacune avec la dernière version de main et celles qui la précèdent, et ne fusionne que ce qui passe. Les workflows GitHub Actions doivent alors écouter l'événement merge_group, sans quoi les vérifications ne se lancent jamais et la file reste bloquée.

on:
  pull_request:
  merge_group:

La merge queue est disponible sur les dépôts publics appartenant à une organisation, et sur les dépôts privés des organisations en GitHub Enterprise Cloud. Un compte personnel n'y a pas accès.

Sans CI fiable, le trunk-based est un piège : chaque fusion ratée atterrit directement dans le code qui part en production, sans branche intermédiaire pour l'arrêter. Mettre en place des tests qui bloquent les fusions défaillantes passe avant le choix de la stratégie, et c'est le cœur de la formation CI/CD avec GitHub Actions.

La grille de décision

Le tableau ne désigne pas de gagnant. Il sert à repérer la colonne qui décrit ton projet aujourd'hui, en sachant qu'elle peut changer quand l'équipe grandit.

Critère GitHub Flow GitHub Flow + environnements Branches de release / Git Flow Trunk-based
Taille d'équipe 1 à quelques personnes Petite à moyenne Toutes tailles Toutes tailles, équipe rodée
Rythme de mise en prod À chaque fusion Après validation en recette À chaque version numérotée Plusieurs fois par jour
Versions en parallèle Une Une Plusieurs Une
CI requise Recommandée Indispensable pour déployer Recommandée Non négociable
Feature flags Optionnels Optionnels Rarement utiles Indispensables
Branches permanentes main main main + une par version (ou develop) main

Merge, squash ou rebase : le bouton en bas de la PR

La stratégie de branches décide où va le code. Le bouton de fusion décide à quoi ressemble l'historique une fois qu'il y est arrivé, et GitHub en propose trois versions.

  • Create a merge commit : tous les commits de la branche sont conservés, plus un commit de fusion qui marque le point de jonction. C'est l'équivalent d'un git merge --no-ff, l'option que Git Flow utilise pour chaque fusion.
  • Squash and merge : tous les commits de la PR deviennent un seul commit sur la branche cible. Les « wip » et « correction typo » disparaissent de l'historique principal.
  • Rebase and merge : les commits sont rejoués un par un sur la branche cible, sans commit de fusion. L'historique reste linéaire, mais GitHub crée toujours de nouveaux identifiants (SHA) pour ces commits.

Le squash convient aux branches courtes de GitHub Flow et du trunk-based : une PR, une modification logique, un commit. Il devient un piège sur une branche qui vit longtemps, et la documentation GitHub le signale : si tu continues à travailler sur une branche après l'avoir fusionnée en squash, les PR suivantes embarquent des commits déjà intégrés, et les mêmes conflits reviennent. Squasher develop vers main dans un Git Flow produit exactement ce problème à chaque version.

Dans les paramètres du dépôt, tu peux désactiver les méthodes que l'équipe n'utilise pas. Ne laisser qu'un seul bouton évite qu'une PR soit squashée et la suivante rebasée selon l'humeur de la personne qui fusionne.

Les pièges qui font dérailler une stratégie

La branche qui vit trois semaines

Quelle que soit la stratégie, plus une branche s'éloigne de sa base, plus la fusion finale est douloureuse : au bout de quelques semaines, d'autres ont renommé des fonctions et déplacé des fichiers que la branche modifie aussi. Découper la fonctionnalité en PR plus petites, ou la cacher derrière un feature flag, coûte moins cher qu'une journée de résolution de conflits.

Le correctif qui ne remonte jamais

Dès qu'il existe plus d'une branche permanente, chaque correctif urgent doit être reporté partout. Oublier une seule fois, et le bug réapparaît à la version suivante, ce qui arrive d'autant plus que l'urgence pousse à fusionner vite et à passer à autre chose. Une case à cocher « reporté sur main » dans le modèle de PR limite la casse.

Le nommage laissé au hasard

Entre test2, nouvelle-branche et modif-julien, personne ne sait ce qui est en cours. Des préfixes simples (feature/, fix/, release/) rendent la liste des branches lisible et permettent de cibler des règles GitHub par motif.

La stratégie que personne n'a écrite

Une stratégie qui n'existe que dans la tête du plus ancien de l'équipe sera mal appliquée par les autres. Quelques lignes dans un fichier CONTRIBUTING.md à la racine du dépôt suffisent : d'où partent les branches, comment on les nomme, quel bouton de fusion utiliser. GitHub met ce fichier en avant quand quelqu'un ouvre une PR.

Changer de stratégie en cours de route

Passer de Git Flow à GitHub Flow se fait sans tout casser si l'on procède dans l'ordre :

  1. Terminer ou abandonner les branches release et hotfix en cours.
  2. Fusionner develop dans main pour repartir d'une base commune.
  3. Faire de main la branche par défaut du dépôt si ce n'était pas le cas.
  4. Changer la branche cible des PR encore ouvertes : GitHub permet de modifier la base d'une PR sans la recréer.
  5. Mettre à jour les déclencheurs de la CI qui visaient develop, puis supprimer develop.

Prévois un moment calme pour le faire, pas une veille de mise en production. Et préviens l'équipe avant, sinon quelqu'un repartira de develop le lendemain, par habitude.

Pour pratiquer ces manipulations sur un vrai dépôt, la formation Git et GitHub couvre branches, PR et dépôts distants, et la formation CI/CD avec GitHub Actions prend le relais sur les tests et les déploiements qui rendent une stratégie simple tenable. Pour situer Git parmi les autres outils du quotidien côté serveur, le guide des technologies backend donne une vue d'ensemble.

Questions fréquentes

Git Flow est-il obsolète ?

Non. Son auteur a précisé en 2020 qu'il le déconseille pour les applications web livrées en continu, mais qu'il reste adapté aux logiciels versionnés explicitement ou maintenus en plusieurs versions. Ce qui pose question, c'est son adoption par défaut dans des projets qui livrent en continu.

Faut-il une branche develop ?

Seulement si main doit contenir exclusivement des versions publiées et que le projet suit un cycle de versions numérotées. Si chaque fusion part en production, develop ajoute une étape et une source de divergence sans rien protéger.

Combien de temps doit vivre une branche de fonctionnalité ?

Le moins longtemps possible. En trunk-based, quelques heures. En GitHub Flow, viser quelques jours reste une bonne pratique. Au-delà d'une semaine, mieux vaut découper la fonctionnalité en plusieurs PR ou la cacher derrière un feature flag.

Comment protéger la branche main sur GitHub ?

Avec un ruleset ou une règle de protection de branche, dans les paramètres du dépôt. Tu peux exiger une PR, un nombre d'approbations, le passage des tests et bloquer le force push. Ces protections sont disponibles sur les dépôts publics avec l'offre gratuite, et sur les dépôts privés à partir de GitHub Pro ou Team.

La merge queue est-elle utile pour une petite équipe ?

Rarement. GitHub la présente comme utile sur les branches qui reçoivent beaucoup de PR par jour de la part de nombreuses personnes. Pour deux ou trois développeurs, exiger que la branche soit à jour avant fusion suffit. Elle n'est d'ailleurs disponible que pour les organisations, sur dépôts publics, ou sur dépôts privés en GitHub Enterprise Cloud.

Merge, squash ou rebase : lequel choisir pour fermer une PR ?

Le squash convient aux branches courtes où une PR correspond à une seule modification. Le merge commit conserve tout l'historique et suit la logique de Git Flow. Le rebase donne un historique linéaire mais crée de nouveaux identifiants de commits. Le choix compte moins que le fait de s'y tenir : désactive les méthodes non utilisées dans les paramètres du dépôt.

Vous êtes expert ?

Partagez votre expertise sur notre blog

Tutoriel, retour d'expérience, analyse - publiez un article invité et gagnez en visibilité.

Écrire pour nous