Aller au contenu
Développement medium

Workflows distribués Git

11 min de lecture

Git est distribué : chaque développeur possède une copie complète du dépôt. Cette architecture permet plusieurs modèles de collaboration. Ce guide présente les trois principaux workflows distribués et vous aide à choisir celui qui correspond à votre équipe ou projet.

Prérequis : Remotes fondamentaux et Merge et conflits.

  • Comprendre les 3 workflows distribués : centralisé, integration-manager, dictateur
  • Identifier le workflow adapté à votre taille d'équipe et votre projet
  • Contribuer à un projet open source avec le workflow fork + PR
  • Gérer les remotes multiples (origin, upstream) dans un contexte de fork

Le modèle le plus simple : un seul dépôt partagé, tout le monde pousse sur les mêmes branches.

Dépôt central (origin)
┌──────────┐
│ main │
└────┬─────┘
┌─────┼─────┐
▼ ▼ ▼
Dev A Dev B Dev C

Tous les développeurs clonent le même dépôt et poussent directement sur main (ou develop) :

Fenêtre de terminal
git clone https://gitlab.com/team/project.git
# ... travailler ...
git pull --rebase origin main
git push origin main

Si un collègue a poussé entre-temps, Git rejette le push avec un message explicite :

! [rejected] main -> main (fetch first)
error: failed to push some refs to 'https://gitlab.com/team/project.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.

Ce refus est une protection, pas un bug : Git empêche d'écraser des commits que vous n'avez pas encore récupérés. Il faut d'abord intégrer les changements distants (pull --rebase ou pull), puis repousser.

Le workflow centralisé se justifie quand le coût d'une revue systématique dépasse le risque d'un commit hasardeux sur main. C'est le cas quand tout le monde se parle dans la journée et que le déploiement n'est pas automatique. Le critère décisif n'est pas la taille de l'équipe mais la confiance mutuelle : dès qu'un contributeur externe ou occasionnel apparaît, ce modèle montre ses limites.

  • Petites équipes (2-5 personnes)
  • Projets internes simples
  • Équipes habituées à SVN qui migrent vers Git

Ces limites se cumulent avec la croissance de l'équipe, et la plus coûteuse est la dernière : sans branche d'intégration ni revue, un commit qui casse la compilation bloque tous les développeurs jusqu'à ce que quelqu'un le corrige ou le revert. Un pipeline d'intégration continue qui teste chaque push atténue le problème, mais il ne le supprime pas, car le code cassé est déjà sur main quand l'alerte tombe.

  • Pas de revue de code formelle avant l'intégration
  • Conflits fréquents si l'équipe grandit
  • Un commit cassé sur main impacte tout le monde

C'est le modèle standard de l'open source (GitHub, GitLab). Un mainteneur contrôle le dépôt principal. Les contributeurs passent par un fork et des pull/merge requests.

Dépôt principal (blessed)
┌──────────┐
│ mainteneur│
└────┬─────┘
│ merge PR
┌────┴─────┐
▼ ▼
Fork Dev A Fork Dev B
(origin) (origin)

Le point qui déroute au début, c'est qu'il y a deux dépôts distants au lieu d'un. origin désigne votre fork, sur lequel vous avez le droit d'écrire ; upstream désigne le dépôt d'origine, sur lequel vous ne pouvez que lire. Vous poussez toujours sur origin, vous récupérez toujours depuis upstream. Le nom upstream n'a rien d'obligatoire pour Git, c'est une convention que suivent la quasi-totalité des projets, y compris la documentation de GitHub.

  1. Le contributeur forke le dépôt principal

  2. Il clone son fork et ajoute le dépôt principal comme upstream :

    Fenêtre de terminal
    git clone https://github.com/moi/project.git
    git remote add upstream https://github.com/original/project.git
  3. Il crée une branche feature, travaille, pousse sur son fork :

    Fenêtre de terminal
    git switch -c fix/typo-readme
    # ... modifications ...
    git push -u origin fix/typo-readme
  4. Il ouvre une pull request vers le dépôt principal

  5. Le mainteneur review, demande des changements si nécessaire, puis merge

  6. Le contributeur synchronise son fork :

    Fenêtre de terminal
    git fetch upstream
    git switch main
    git merge upstream/main
    git push origin main

Le déclencheur de ce modèle est une question de droits d'écriture : dès que des personnes doivent pouvoir proposer du code sans pouvoir modifier le dépôt de référence, le fork devient la seule réponse propre. En entreprise, beaucoup d'équipes obtiennent le même résultat sans fork, avec de simples branches protégées sur un dépôt partagé et une merge request obligatoire ; le fork reste réservé aux contributeurs extérieurs à l'organisation.

  • Projets open source
  • Équipes où la revue de code est obligatoire
  • Quand les contributeurs n'ont pas les droits d'écriture sur le dépôt principal

Ces avantages ont une contrepartie qu'il vaut mieux connaître avant de choisir ce modèle : le fork se désynchronise en permanence du dépôt principal, et c'est au contributeur de le remettre à jour. Sur un projet actif, une branche oubliée deux semaines revient avec des conflits à résoudre. La discipline de git fetch upstream avant chaque nouvelle branche coûte moins cher que le rattrapage.

  • Le mainteneur contrôle ce qui entre dans le projet
  • Chaque contribution est revue avant intégration
  • Les contributeurs travaillent de manière indépendante

Utilisé par les très grands projets (le noyau Linux). Un dictateur bienveillant intègre le travail de lieutenants, qui eux-mêmes intègrent les contributions des développeurs.

Blessed repo
┌────────────┐
│ Dictateur │
└──┬─────┬───┘
│ │
┌──────┘ └──────┐
▼ ▼
Lieutenant A Lieutenant B
(sous-système) (sous-système)
▲ ▲ ▲ ▲
│ │ │ │
Dev 1 Dev 2 Dev 3 Dev 4

L'intégration se fait par paliers successifs, chaque niveau filtrant et testant avant de transmettre au suivant. Sur le noyau Linux, ces échanges passent historiquement par des patches envoyés en liste de diffusion et par git request-pull, pas par une interface web de pull request. Chaque mainteneur de sous-système publie son propre dépôt Git public, dans lequel le niveau supérieur vient tirer les commits validés.

  1. Les développeurs soumettent leur travail au lieutenant de leur sous-système
  2. Le lieutenant intègre, teste, puis soumet au dictateur
  3. Le dictateur intègre dans le dépôt de référence (blessed repo)
  4. Tout le monde synchronise depuis le blessed repo

Ce modèle ne se décrète pas, il s'impose quand le volume de contributions dépasse ce qu'une seule personne peut relire. Le coût est celui d'une hiérarchie : une contribution traverse plusieurs niveaux avant d'arriver dans la branche de référence, ce qui allonge le délai d'intégration de plusieurs semaines.

  • Projets très larges (centaines de contributeurs)
  • Noyau Linux, certains projets GNU

Ce workflow est rarement pertinent pour les projets courants. Il est présenté ici pour compréhension.

La ligne à regarder en premier n'est pas la taille d'équipe mais la ligne Contrôle : elle décrit qui décide de ce qui entre dans la branche de référence, et c'est ce choix qui entraîne tous les autres. Les fourchettes de taille sont indicatives ; une équipe de trois personnes qui livre en production plusieurs fois par jour a tout intérêt au modèle Integration-Manager, alors qu'une équipe de dix personnes sur un outil interne peut rester en centralisé sans dommage.

CritèreCentraliséIntegration-ManagerDictator
Taille d'équipe2-55-100+100+
Revue de codeOptionnelleObligatoire (PR)Multi-niveaux
ComplexitéFaibleMoyenneÉlevée
ContrôlePartagéMainteneurHiérarchique
Cas d'usageProjets internesOpen source, équipesNoyau Linux

Quel que soit le workflow, ces règles facilitent l'intégration de vos contributions :

  1. Un sujet par branche : ne mélangez pas un bugfix et une feature dans la même PR
  2. Commits atomiques : chaque commit fait une chose et la fait bien
  3. Rebasez avant de soumettre : git fetch upstream puis git rebase upstream/main pour éviter les conflits au mainteneur
  4. Messages clairs : décrivez le « quoi » et le « pourquoi »
  5. Testez : assurez-vous que votre code fonctionne avant de soumettre
  6. Respectez les conventions du projet (linting, format des commits, etc.)

Trois de ces quatre situations viennent de la même cause de fond : le fork a pris du retard sur le dépôt principal. Avant de dérouler une solution, lancez toujours git fetch upstream puis git log --oneline HEAD..upstream/main pour mesurer l'écart en nombre de commits. Notez que le force-push de la troisième ligne réécrit l'historique de votre branche : il est acceptable sur une branche de contribution que vous êtes seul à utiliser, jamais sur une branche partagée. Préférez git push --force-with-lease, qui refuse d'écraser un commit poussé entre-temps par quelqu'un d'autre.

SymptômeCause probableSolution
Push rejeté sur le dépôt originalPas les droits d'écriturePoussez sur votre fork, puis ouvrez une PR
Fork désynchroniséPas de fetch upstreamgit fetch upstream && git merge upstream/main
PR avec conflitsBranche pas à jourgit fetch upstream && git rebase upstream/main puis git push --force-with-lease sur votre fork
Trop de commits dans la PRHistorique brouillongit rebase -i pour squasher avant soumission
  • Centralisé : simple, tout le monde pousse sur le même dépôt (petites équipes)
  • Integration-Manager : fork + PR + revue, le standard de l'open source
  • Dictator & Lieutenants : hiérarchique, pour les très grands projets
  • Bonnes pratiques : une branche par sujet, commits atomiques, rebase avant soumission
  • La plupart des équipes utilisent le workflow Integration-Manager avec des merge requests

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn