Git merge ou rebase : quelle stratégie choisir pour votre équipe
Merge et rebase intègrent tous deux les changements d'une branche, mais traitent l'historique différemment : merge le conserve tel quel et ajoute un commit de fusion, rebase réécrit vos commits sur une nouvelle base et rend l'historique linéaire. Règle pratique : rebase pour ranger vos commits non publiés, merge pour intégrer un travail terminé dans les branches partagées.
En bref : la différence entre merge et rebase
Le débat « git merge ou rebase » ne porte pas vraiment sur la meilleure commande, mais sur l'historique de projet que vous voulez lire. Les deux aboutissent au même code final. Ce qui change, c'est le chemin enregistré dans le journal.
- Merge relie deux lignes d'historique et consigne honnêtement que le travail s'est fait en parallèle. Les commits existants restent intacts, un commit de merge à deux parents est ajouté.
- Rebase réécrit vos commits comme si vous aviez commencé à partir de la version la plus récente de la branche de base. L'historique devient une ligne droite, mais les commits reçoivent de nouveaux hashes.
La mécanique de chaque commande — options, résolution des conflits, mode interactif — est détaillée dans des articles dédiés. Ici, on parle uniquement du choix de stratégie.
À quoi ressemble l'historique dans les deux cas
Situation de départ : vous avez créé feature, fait deux commits, et pendant ce temps deux commits d'autres personnes sont arrivés sur main.
D---E feature
/
A---B---C---F---G main
Après git merge feature sur main :
D---E
/ \
A---B---C---F---G---M main
Après git rebase main sur feature puis avance rapide de main :
A---B---C---F---G---D'---E' main
Dans le premier cas, l'historique montre que la fonctionnalité a été développée en parallèle et à quel moment elle a été intégrée. Dans le second, l'historique se lit comme un récit séquentiel, mais la trace du travail parallèle a disparu : D' et E' sont de nouveaux commits créés au moment du rebase.
Tableau comparatif merge vs rebase
| Critère | git merge | git rebase |
|---|---|---|
| Commits existants | Inchangés | Recréés avec de nouveaux hashes |
| Forme de l'historique | Graphe ramifié avec commits de merge | Linéaire |
| Sûreté sur les branches partagées | Toujours sûr | Dangereux pour les commits publiés |
| Force push nécessaire | Non | Oui, si la branche est déjà sur le serveur |
| Conflits | Résolus une seule fois, dans le commit de merge | Peuvent surgir sur chaque commit rejoué |
| Contexte « d'où ça vient » | Conservé | Perdu |
| Annuler une fonctionnalité entière | Un seul git revert -m 1 du commit de merge | Revert de chaque commit ou d'une plage |
Confort avec git bisect et git log | Graphe plus difficile à lire | Plus simple : une seule ligne droite |
| Courbe d'apprentissage | Faible | Plus élevée, il faut comprendre la réécriture d'historique |
| Nettoyage des commits (squash, reword) | Seulement --squash en bloc | Souple via rebase -i |
Avantages et inconvénients de merge
Avantages
- Ne détruit pas l'historique. Tout ce qui a été publié reste en place. Vos collègues n'auront rien à réparer après votre opération.
- Le conflit se résout une seule fois. Même avec 30 commits dans la branche, vous traitez l'état final et non chaque étape.
- Le contexte est préservé. Le commit de merge montre quand chaque tâche est arrivée dans la branche principale, et on peut facilement l'annuler en bloc.
Inconvénients
- Un graphe bruyant. Avec des synchronisations fréquentes, l'historique se couvre de commits « Merge branch 'main' into feature » et
git log --graphse transforme en plan de gare de triage. - Les commits brouillons atterrissent dans l'historique. « wip », « fix », « encore un fix » restent pour toujours dans la branche principale si on ne les écrase pas.
Avantages et inconvénients de rebase
Avantages
- Un historique linéaire et lisible. Chaque commit est à sa place,
git logse lit comme une liste de changements etgit bisecttrouve plus facilement le commit fautif. - La possibilité de remettre de l'ordre dans les commits avant la revue : les fusionner, les renommer, les réordonner.
- Pas de commits de merge techniques issus de la synchronisation avec la branche principale.
Inconvénients
- Réécrit l'historique. Rebaser une branche partagée déjà publiée casse le travail de tous ceux qui l'ont récupérée.
- Exige un force push pour les branches présentes sur le serveur, donc de la discipline et
--force-with-lease. - Conflits répétés. Une même zone de code peut entrer en conflit sur plusieurs commits d'affilée.
- Les commits intermédiaires peuvent ne plus compiler. Après le déplacement sur la nouvelle base, personne n'a testé les anciens commits dans le nouvel environnement.
Quand utiliser merge ou rebase
Rebase pour votre travail local
Vous mettez à jour votre branche avant de pousser : git pull --rebase. Vous préparez la branche pour la revue et voulez supprimer les commits brouillons : git rebase -i. Votre branche de fonctionnalité personnelle a pris du retard sur main : git rebase origin/main. Dans tous ces cas, vous réécrivez des commits que vous seul avez vus (ou qui n'appartiennent qu'à vous).
Merge pour les branches partagées et l'intégration
Une fonctionnalité terminée est intégrée dans main ou develop. Plusieurs personnes travaillent sur la branche. Il faut réintégrer une branche de release dans la branche principale. Ici, il est essentiel de ne pas toucher aux commits déjà publiés, et merge est la seule option correcte.
La règle simple
Si les commits n'existent que chez vous, rebase est permis. Si quelqu'un les a déjà récupérés, uniquement merge.
Workflows types pour une équipe
| Workflow | Fonctionnement | Pour qui |
|---|---|---|
| Merge uniquement | Les fonctionnalités sont intégrées avec --no-ff, la synchronisation se fait avec git merge main | Débutants avec Git, équipes qui tiennent à une chronologie complète et à des retours arrière simples |
| Rebase + merge | La branche est rebasée sur main avant intégration, puis commit de merge avec --no-ff | Équipes qui veulent à la fois un historique propre et des frontières de fonctionnalités visibles |
| Rebase + fast-forward | La branche est rebasée puis intégrée en avance rapide, l'historique est entièrement linéaire | Petites équipes aux commits soignés et atomiques |
| Squash merge | Chaque pull request devient un seul commit sur main | Équipes aux tâches courtes, où l'historique détaillé de la branche n'est pas utile |
Sur GitHub et GitLab, ces workflows correspondent aux boutons « Create a merge commit », « Rebase and merge » et « Squash and merge ». Mieux vaut n'autoriser que l'option retenue dans les paramètres du dépôt, pour que l'historique ne devienne pas un mélange de styles.
Les réglages qui verrouillent le choix
# pull sans commits de merge superflus
git config --global pull.rebase true
# ou : pull en avance rapide uniquement, sinon erreur — à vous de décider
git config --global pull.ff only
# toujours un commit de merge lors de l'intégration des fonctionnalités
git config --global merge.ff false
Attention à merge.ff false : il s'applique aussi à git pull en mode merge. Beaucoup préfèrent ne pas le définir globalement et écrire explicitement --no-ff lors de l'intégration d'une fonctionnalité.
Exemple : une même tâche dans les deux styles
Prenons un scénario concret. Vous développez pendant trois jours une fonctionnalité de paiement dans la branche feature/payment, et pendant ce temps cinq autres tâches ont été intégrées dans main. Avant d'ouvrir la pull request, il faut récupérer le main à jour et vérifier que tout fonctionne.
Version avec merge
git switch feature/payment
git fetch origin
git merge origin/main
# conflits résolus une seule fois, git add, git commit
git push
La branche a reçu un commit « Merge remote-tracking branch 'origin/main' into feature/payment ». Le push est normal, les collègues qui suivaient la branche ne remarquent rien. Si vous synchronisez ainsi tous les jours, la branche contiendra trois commits de ce genre, et ils arriveront dans main avec la fonctionnalité si vous intégrez sans squash.
Version avec rebase
git switch feature/payment
git fetch origin
git rebase origin/main
# conflits résolus au fil de l'eau, commit par commit : git add, git rebase --continue
git rebase -i origin/main # facultatif : fusionner les commits brouillons
git push --force-with-lease
La branche semble avoir été créée ce matin à partir du main à jour, sans commits superflus, et le relecteur suit plus facilement les changements étape par étape. Le prix à payer : un push forcé et la nécessité de s'assurer que personne d'autre ne committe sur cette branche.
Ce que main verra au final
Lors de l'intégration via pull request, la différence subsiste. Le style merge produit un graphe avec des ramifications et des merges de synchronisation, le style rebase une chaîne propre de commits de la fonctionnalité, intégrable en avance rapide ou par un seul commit de merge. Le code, lui, sera identique si les conflits sont résolus de la même façon.
Comment trancher en équipe
Répondez à quelques questions. Plusieurs personnes travaillent-elles sur la même branche ? Si oui, rebase est exclu pour cette branche. Quel est le niveau de l'équipe sur Git ? S'il y a souvent des débutants, commencez par merge et squash merge, qui pardonnent les erreurs. Avez-vous besoin d'une chronologie complète pour l'audit et l'analyse d'incidents ? Les commits de merge des fonctionnalités sont alors utiles. Un git log lisible et un usage fréquent de git bisect comptent-ils ? Alors penchez pour rebase et un historique linéaire.
Consignez la décision dans le CONTRIBUTING ou le README du dépôt et activez la protection de la branche principale : interdiction du force push, pull request obligatoire, méthode de fusion autorisée. Une règle imposée par la configuration fonctionne bien mieux que n'importe quel accord oral.
Idées reçues fréquentes
- « Rebase, c'est pour les experts, merge pour les débutants. » Non : ce sont deux outils pour deux usages différents. Les développeurs expérimentés utilisent les deux.
- « Les commits de merge, c'est du bruit. » Ceux de synchronisation, souvent oui. Mais le commit de merge qui intègre une fonctionnalité est un repère utile : il permet de voir et d'annuler une tâche entière.
- « Avec rebase, il y a moins de conflits. » Les conflits sont les mêmes, puisque ce sont les mêmes lignes qui changent. Rebase les répartit simplement commit par commit, là où merge les règle d'un coup.
- « Rebase fait perdre des commits. » Les anciens commits restent dans
git refloget peuvent être récupérés tant que le ramasse-miettes ne les a pas supprimés.
En résumé
Choisir entre git merge ou rebase, c'est choisir entre une chronologie fidèle et un historique linéaire lisible. Merge est sûr et préserve le contexte, rebase apporte de la clarté mais réécrit les commits. La pratique la plus fiable consiste à combiner les deux : rebaser et nettoyer votre branche tant qu'elle vous appartient, puis intégrer le travail terminé dans les branches partagées par merge ou squash selon les règles de l'équipe. L'essentiel est de s'accorder sur un workflow et de le verrouiller dans les paramètres du dépôt. Les deux stratégies et le travail en équipe avec les branches sont abordés en pratique dans le cours Git.
Questions fréquentes
Faut-il utiliser merge ou rebase pour git pull ?
Pour mettre à jour une branche locale, rebase est plus pratique : vos commits non publiés se placent au-dessus des commits distants récents sans commit de merge superflu. On l'active avec git config --global pull.rebase true.
Peut-on mélanger merge et rebase dans un même projet ?
Oui, et c'est même l'approche la plus répandue : rebase pour vos propres branches, merge pour les branches partagées. Il faut simplement que toute l'équipe connaisse la règle.
Que choisir quand on débute ?
Commencez par merge : il ne réécrit pas l'historique et il est plus difficile de casser quelque chose. Apprenez rebase sur vos branches locales une fois que reflog et force push vous sont familiers.
Le choix de stratégie change-t-il le code final ?
Non, si les conflits sont résolus de la même manière, l'état final des fichiers est identique. Seul l'historique des commits enregistré diffère.
Quelle différence entre squash merge et rebase ?
Le squash merge compresse toute la branche en un seul nouveau commit sur la branche principale, alors que rebase déplace chaque commit séparément. Les deux donnent un historique linéaire, mais le squash perd le détail des étapes.
Ce sujet est traité en détail avec de la pratique dans le cours « Git de zéro à développeur confirmé ».
- Processus Git dans les équipes réelles : quel workflow choisir ?
- Outils avancés : rebase, stash, cherry-pick et les tags