
> git merge vs rebase — la décision en 10 secondes▋
Merge ou rebase, une seule question tranche : le commit a-t-il quitté ta machine ? La table de décision, le cas fast-forward, et le sauvetage par reflog quand un rebase part de travers.
mrsaynothing· 5 octobre 2026· 8 min de lecture
Tu vas taper l'une de ces deux commandes des milliers de fois dans ta carrière, et la moitié des conseils en ligne en font une religion — rebase partout, l'historique doit être propre d'un côté, jamais de rebase, ça détruit le travail de l'autre. Les deux camps oublient la vraie règle, qui tient en dix secondes. Cet article est la décision, pas la théologie, et il rejoint le cluster Undo Anything in Git — même famille que git revert vs reset, l'autre paire « deux commandes, une question ». Git lui-même a été écrit de zéro en dix jours en avril 2005 ; le débat merge-vs-rebase court depuis.
La checklist de cinq minutes
Quelle est la différence entre git merge et git rebase ?
Les deux commandes livrent le même code ; elles se disputent sur ce que l'historique doit en raconter. Merge écrit le désaccord noir sur blanc : un nouveau commit à deux parents, la divergence préservée pour quiconque lit le graphe plus tard. Rebase fait comme si tu étais parti de la base du jour : tes trois commits sont rejoués en trois commits neufs avec de nouveaux SHA, et les anciens deviennent inatteignables depuis toute branche.
J'ai lancé les deux dans un banc jetable sous git 2.47.3, avec les mêmes cinq commits. Le run merge a gardé chaque SHA d'origine et ajouté un nœud ; le run rebase a changé l'identité des commits de la branche — c3 est entré sous le nom 5d48940 et ressorti en 6b2be0a. Même arbre, historique différent :
vérifie : git log --oneline --graph → un nœud |\ signifie merge, une ligne droite signifie que le rebase a gagné
Quand un merge devient-il un fast-forward ?
Si main n'a pas bougé depuis ta branche, il n'y a rien à merger — git fait juste glisser l'étiquette vers l'avant. C'est un fast-forward, et c'est pourquoi les partisans du rebase obtiennent leur ligne propre sans forcer quoi que ce soit : rebase ta feature sur main, puis le merge devient un fast-forward, et le graphe reste une droite. Depuis le banc :
* 67c0442 c4 feature 2 # rebasé, puis mergé — fast-forward
* 6b2be0a c3 feature 1 # nouveaux SHA — 5d48940 avant le rebase
* 1398836 c5 main moved on
* facd5a4 c2 main work
* f45b000 c1 base
Cinq commits, zéro nœud. La contrepartie : ces SHA prime n'existent plus nulle part ailleurs que sur ta machine. Pousse-les et le clone d'un collègue garde toujours les originaux — deux versions du « même » commit, exactement le gâchis dont parle la cinquième section.
vérifie : git merge --ff-only feature → Fast-forward dans la sortie, aucun commit de merge créé
Quels commits sont encore à toi seul ?
La réponse tient en une commande, pas dans une impression. git log origin/main..HEAD liste les commits qu'origin n'a jamais vus — ceux-là se rebasent. Le miroir, git log origin/main..origin/main, est vide par définition ; la commande qui compte vérifie la branche sur laquelle les autres construisent. Si la liste contient un commit qu'un autre clone possède peut-être déjà — un push, une pull request ouverte, une branche poussée puis force-poussée — il n'est plus à toi seul, quoi qu'affirme ton graphe local.
Le travail non poussé est exactement la raison d'être du rebase : rejoue-le sur la base à jour et ta pull request se lit comme une seule séquence propre. C'est aussi pourquoi « pull avec rebase » est un défaut sain pour les branches privées — git pull --rebase rejoue tes commits locaux par-dessus ce qui est arrivé, au lieu de tisser un nœud de merge à chaque synchro. Le cas du travail en stash vit dans git stash a single file ; la variante fork dans sync fork with upstream.
Que casse un rebase sur une branche partagée ?
Chaque clone qui détient les anciens commits se met en désaccord avec le tien sur la réalité. Le rebase donne à tes commits de nouveaux SHA ; ta branche poussée et ta branche réécrite ne partagent plus aucune ascendance, donc le prochain push exige --force — et tous ceux qui ont tiré l'ancienne version doivent merger leur copie de commits qui « n'existent plus ». Leurs doublons refont surface dans chaque merge futur. Ce n'est pas une hypothèse d'école : le merge de commits doublons est l'après-classique, et le démêler coûte un après-midi.
La règle fait une phrase, et le livre officiel la porte comme un avertissement, pas comme une suggestion :
Do not rebase commits that exist outside your repository and that people may have based work on.
— Pro Git, 2e édition, « Git Branching — Rebasing »
Les commentaires de revue accrochés à des SHA précis se détachent dans le même mouvement — rebase une pull request ouverte et le contexte de revue s'évapore avec les anciens identifiants.
Comment annuler un rebase ?
Les anciens commits survivent au rebase — le reflog est leur cachette. Le rebase déplace des pointeurs de branche ; il ne supprime pas d'objets. Le sauvetage du banc, après un reset --hard qui a jeté deux commits :
$ git reflog | head -4
1398836 HEAD@{0}: reset: moving to HEAD~2
67c0442 HEAD@{1}: merge feature: Fast-forward
1398836 HEAD@{2}: checkout: moving from feature to main
67c0442 HEAD@{3}: rebase (finish): returning to refs/heads/feature
$ git reset --hard HEAD@{1}
HEAD is now at 67c0442 c4 feature 2
Une ligne, branche restaurée, travail stagé et non-stagé avec. Les entrées de reflog expirent après environ 90 jours par défaut, donc le sauvetage a un chrono — le même mécanisme que dans git undo last commit, et la décision complète revert/reset vit dans git revert vs reset.
vérifie : git reflog | head -3 → la pointe d'avant rebase attend sur HEAD@{1}, à un reset de là
Quelle commande pour ta situation ?
La table est tout l'article en six lignes — filtre selon ta branche.
| Situation | Commande | Pourquoi elle gagne |
|---|---|---|
| Ta branche feature, jamais poussée | git rebase main |
Historique linéaire, une séquence propre pour la revue |
| Une branche que d'autres tirent | git merge |
Aucune réécriture de SHA — aucun doublon dans le clone de personne |
| main local divergé, rien de poussé | git pull --rebase |
Synchronise sans nœud ; tes commits restent au-dessus |
| Fork qui rattrape l'upstream | git merge upstream/main |
Colle au flux de fork sync ; la PR reste attachée |
| Hotfix qui doit atterrir maintenant | git merge --no-ff |
Marqueur visible de l'entrée du fix, même sur une branche fast-forwardable |
| Un rebase parti de travers | git reset --hard HEAD@{1} |
Le reflog garde la pointe d'avant (~90 jours) |
Et --squash dans tout ça ?
git merge --squash prend les changements d'une branche et les stage en un seul tas non commité — pas de commit de merge, pas de lien avec l'historique de la branche. L'autocomplétion montre que « merge vs rebase vs squash » se cherche tous les jours : squash est la troisième réponse, pour jeter une branche après avoir atterri son changement net. Il ne réécrit rien ; il refuse juste d'enregistrer les étapes internes de la branche.
Une équipe peut-elle n'en choisir qu'un ?
Beaucoup le font : rebase-pour-le-local, merge-vers-le-partagé est la politique la plus répandue, et le bouton merge de GitHub garde merge par défaut. Un « rebase partout » fonctionne aussi — tant qu'aucune branche partagée n'est jamais réécrite, la seule phrase qui survit à tous les débats de workflow.
La version dix secondes, une dernière fois : le commit a-t-il quitté ta machine ? Non → rebase. Oui → merge. Quand le mauvais gagne quand même, le reflog garde la sortie — et le reste de la carte de l'annulation vit dans le hub git undo.
faq
— mrsaynothing
$ Articles similaires
Field Notes #3 : nous avons supprimé 16 langues. Le trafic s'en est à peine aperçu.
Six langues restées, seize supprimées, et Google envoie encore des lecteurs vers les pages effacées via des redirections. Ce qu'une traduction doit prouver avant de partir ici.
2026-10-04 · 6 min de lecture

Git Revert vs Reset: Which One Saves Your History?
Git revert vs reset explained: which command undoes commits safely, when reset --hard destroys work, and how each rewrites shared GitHub history.
2026-09-15 · 7 min de lecture

Git Cherry Pick: Multiple Commits, Branches, Conflicts
Git cherry-pick explained: copy a commit from another branch, pick multiple commits or a range, fix conflicts, and know when merge or rebase fits better.
2026-09-12 · 6 min de lecture

Git Remove Untracked Files: Safe git clean Guide
Git remove untracked files safely with git clean: dry-run first, -fd for directories, -x for ignored files — plus why git clean isn't removing anything.
2026-09-09 · 8 min de lecture

$ Partager cet article
$ Recevez le prochain how-to par e-mail
Un e-mail par article. Réparez et avancez.