Ouvrez l’historique d’un vieux projet d’équipe et vous verrez parfois un enchevêtrement de commits de fusion impossible à suivre. Ouvrez celui d’une équipe disciplinée : une ligne droite, lisible commit après commit. La différence tient souvent à un seul choix d’outil — merge ou rebase. Tous deux intègrent le travail d’une branche dans une autre, mais ils racontent l’histoire différemment. À la fin de ce tutoriel, vous saurez rebaser une branche, nettoyer vos commits avec le rebasage interactif, et — surtout — vous connaîtrez la règle d’or qui sépare un usage sûr d’une catastrophe pour votre équipe.
🎯 Ce que vous allez apprendre
- Comprendre ce que
git rebasefait réellement aux commits. - Rebaser une branche de fonctionnalité au-dessus de
main. - Appliquer la règle d’or : ne jamais rebaser un historique déjà partagé.
- Nettoyer une série de commits avec le rebasage interactif (squash, reword, drop).
- Choisir entre
mergeetrebaseselon le contexte. - Annuler un rebasage qui tourne mal.
🛠️ Ce que vous allez construire
Sur le dépôt boutique-inventaire, vous développerez une fonctionnalité de filtres sur plusieurs commits « brouillons », puis vous les transformerez en un historique impeccable : d’abord en rebasant la branche sur une main qui a avancé, ensuite en condensant vos commits désordonnés en une suite claire, prête à être relue par un collègue.
Prérequis
- Être à l’aise avec les branches et la fusion. Au besoin, revoir Branches Git et fusion.
- Un dépôt avec une branche
mainet de quoi créer une branche de fonctionnalité. - Niveau intermédiaire. ⏱️ Temps estimé : environ 50 minutes.
Étape 1 — Le problème : deux manières de réunir des branches
Quand votre branche de fonctionnalité et main ont divergé, il faut les réunir. La fusion (merge) crée un commit de fusion qui relie les deux histoires : elle préserve fidèlement ce qui s’est passé, mais multiplie les bifurcations dans le graphe. Le rebasage (rebase) adopte la stratégie inverse : il rejoue vos commits, un par un, au-dessus du dernier commit de main, comme si vous aviez commencé votre travail à partir de là. Résultat : une ligne droite, sans commit de fusion.
Aucune des deux approches n’est « meilleure » dans l’absolu. La fusion dit la vérité historique ; le rebasage raconte une histoire plus lisible. Le bon réflexe consiste à savoir ce que chacune fait vraiment sous le capot — c’est l’objet des étapes suivantes — pour choisir en connaissance de cause.
Étape 2 — Ce que rebase fait réellement
Point crucial, source de toutes les confusions : le rebasage ne déplace pas vos commits, il en crée de nouveaux. Chaque commit rejoué reçoit un nouvel identifiant SHA, car son parent a changé. Les commits d’origine, eux, ne sont plus référencés par la branche et seront nettoyés à terme. Autrement dit, rebaser, c’est réécrire l’historique de la branche.
Mettons-le en pratique. Créons une fonctionnalité pendant que main avance de son côté, puis rebasons.
git switch -c feature/filtres
echo "function filtrer(stock, critere) { return stock.filter(critere); }" > filtres.js
git add filtres.js
git commit -m "Ajoute le filtrage du stock"
git switch main
echo "// maj entête" >> README.md
git add README.md
git commit -m "Met à jour l'entête du projet"
git switch feature/filtres
git rebase main
Git annonce Successfully rebased and updated refs/heads/feature/filtres. Votre commit de filtrage est maintenant posé au-dessus du commit d’entête de main, alors qu’il avait été écrit avant lui. Vérifiez avec git log --oneline --graph --all : l’historique de la branche est linéaire, sans commit de fusion. La fonctionnalité semble avoir été développée à partir de la version la plus récente de main.
✅ Point d’étape — Après le rebasage,
git log --onelinesurfeature/filtresmontre le commit d’entête demainavant votre commit de filtrage. Si un conflit survient pendant le rebasage, c’est normal — sa résolution est détaillée dans le tutoriel sur les conflits (résumé : résoudre,git add, puisgit rebase --continue).
Étape 3 — La règle d’or du rebasage
Voici la règle la plus importante de tout ce tutoriel, à graver dans le marbre : ne rebasez jamais des commits que vous avez déjà partagés (poussés sur un serveur que d’autres utilisent). La raison est mécanique. Comme le rebasage crée de nouveaux commits avec de nouveaux SHA, votre branche locale et la branche distante divergent. Pour pousser, vous seriez contraint à un push --force, qui réécrit l’historique distant. Tout collègue ayant déjà récupéré les anciens commits se retrouve alors avec une histoire incompatible, des doublons, et des heures perdues à réparer.
La règle pratique est simple : rebasez librement vos commits locaux, tant qu’ils ne sont qu’à vous ; dès qu’un travail est partagé, intégrez les nouveautés avec merge, ou n’utilisez le rebasage que sur votre propre branche de fonctionnalité dont vous êtes le seul auteur. En cas de réécriture assumée d’une branche personnelle déjà poussée, préférez git push --force-with-lease à --force : cette variante refuse d’écraser le travail distant si quelqu’un a poussé entre-temps, un garde-fou précieux.
Étape 4 — Mettre à jour avec pull –rebase
Au quotidien, récupérer le travail des autres avec un simple git pull crée des commits de fusion à répétition, qui polluent l’historique. L’alternative git pull --rebase récupère les nouveautés puis rejoue vos commits locaux par-dessus, gardant une ligne propre.
git pull --rebase
Pour ne plus y penser, on peut en faire le comportement par défaut sur tous ses dépôts. Ce réglage est l’un des plus rentables de Git.
git config --global pull.rebase true
Attention toutefois : cette commande s’applique à vos commits locaux non encore partagés, ce qui respecte la règle d’or. C’est précisément le cas d’usage sûr et recommandé du rebasage.
Étape 5 — Le rebasage interactif : nettoyer ses commits
Le rebasage interactif est l’outil qui transforme un brouillon en chef-d’œuvre. Imaginez avoir commité trois fois pendant le développement : « début filtres », « oups typo », « ça marche enfin ». Personne n’a besoin de voir ce désordre. Condensons ces commits en un seul, propre, avant de proposer la fonctionnalité. Fabriquons d’abord ce désordre.
echo "// brouillon 1" >> filtres.js
git commit -am "debut filtres"
echo "// correction" >> filtres.js
git commit -am "oups typo"
echo "// fin" >> filtres.js
git commit -am "ca marche enfin"
Lancez le rebasage interactif sur les trois derniers commits. La syntaxe HEAD~3 désigne « les trois commits avant la pointe ».
git rebase -i HEAD~3
Votre éditeur s’ouvre avec la liste des commits et, en commentaire, le menu des actions possibles. Les plus utiles sont : pick (garder tel quel), reword (garder mais réécrire le message), edit (s’arrêter pour modifier le contenu), squash (fondre dans le commit précédent en combinant les messages), fixup (comme squash mais en jetant le message), drop (supprimer le commit), et la possibilité de réordonner les lignes pour réordonner les commits.
Pour condenser, laissez pick sur le premier et remplacez pick par fixup (ou squash) sur les deux suivants :
pick a1b2c3d debut filtres
fixup e4f5g6h oups typo
fixup i7j8k9l ca marche enfin
Enregistrez et fermez l’éditeur. Git rejoue les commits selon vos instructions et il ne reste qu’un seul commit propre. Avec squash à la place de fixup, Git vous aurait proposé de rédiger un message combiné. Relisez le résultat avec git log --oneline.
✅ Point d’étape —
git log --onelinedoit désormais montrer un unique commit pour la fonctionnalité de filtres, au lieu de trois. Si vous vous êtes trompé dans le menu, pas de panique :git rebase --abortannule tout et vous ramène à l’état d’avant.
Étape 6 — Aller plus vite avec –autosquash
Quand vous savez, au moment de commiter une correction, qu’elle devra fusionner dans un commit précis, marquez-la d’emblée. La commande git commit --fixup <sha> crée un commit spécial étiqueté pour ce commit cible.
git commit -a --fixup a1b2c3d
git rebase -i --autosquash HEAD~2
Avec --autosquash, Git préremplit le menu en plaçant automatiquement votre commit de correction en position fixup sous le bon commit : il ne vous reste qu’à confirmer. Ajoutez l’option --autostash si vous avez des modifications non commitées : Git les met de côté avant le rebasage et les restaure après, vous évitant un message d’erreur. Ces deux options transforment le nettoyage d’historique en routine fluide.
Étape 7 — Merge ou rebase : choisir à bon escient
Vous disposez maintenant des deux outils ; reste à savoir lequel dégainer. Le tableau ci-dessous résume les arbitrages courants. Notez aussi l’option intermédiaire git merge --squash <branche>, qui aplatit tous les commits d’une branche en un seul changement à committer sur la destination, sans commit de fusion ni réécriture de la branche source.
| Situation | Recommandation | Pourquoi |
|---|---|---|
Mettre à jour ma branche locale avec main |
rebase (ou pull --rebase) |
Historique linéaire, commits encore privés |
| Intégrer une branche déjà partagée | merge |
Ne réécrit pas l’historique des autres |
| Nettoyer mes commits avant de les proposer | rebase -i |
Squash, reword, réordonnancement |
| Garder la trace explicite d’une fonctionnalité | merge --no-ff |
Le commit de fusion documente le bloc |
| Aplatir une branche en un seul commit | merge --squash |
Un changement net, sans historique intermédiaire |
Rebaser une portion précise avec –onto
Il arrive qu’une branche de fonctionnalité ait été créée à partir d’une autre branche de fonctionnalité, et non de main. Quand la branche parente est abandonnée, vous voulez « déplacer » uniquement vos commits sur main, sans embarquer ceux du parent. L’option --onto de git rebase sert exactement à cela : elle précise la nouvelle base, le point de départ à exclure, et la branche à rejouer.
git rebase --onto main ancienne-base feature/ma-branche
Lisez la commande ainsi : « rejoue les commits de feature/ma-branche postérieurs à ancienne-base, et pose-les sur main ». Git ne reprend que vos commits propres, en écartant tout l’historique de la branche parente devenue inutile. C’est l’outil de précision du rebasage : là où un rebasage simple rejoue tout depuis l’ancêtre commun, --onto vous laisse découper exactement la tranche d’historique à transplanter. On y recourt rarement au début, mais le jour où une branche s’est greffée au mauvais endroit, c’est lui qui vous évite de recréer les commits à la main.
🐞 Pièges fréquents
| Symptôme / erreur | Cause probable | Correctif |
|---|---|---|
| Collègues avec des commits en double après un push | Rebasage d’un historique déjà partagé | Respecter la règle d’or ; communiquer avant toute réécriture |
| Updates were rejected au push après rebasage | La branche distante diverge (SHA réécrits) | git push --force-with-lease sur une branche personnelle uniquement |
| Rebasage interrompu par un conflit | Modifications concurrentes des mêmes lignes | Résoudre, git add, git rebase --continue ; voir le tutoriel sur les conflits |
| « J’ai tout cassé pendant le rebasage » | Manipulation interactive ratée | git rebase --abort, ou récupérer via le reflog |
--autosquash ne range rien |
Le commit n’a pas été créé avec --fixup |
Recréer la correction avec git commit --fixup <sha> |
Travailler avec une connexion limitée
Le rebasage est une opération entièrement locale : réorganiser, condenser et linéariser votre historique ne demande aucune connexion. C’est même une excellente habitude lorsque le réseau est rare : on accumule des petits commits hors ligne au fil du travail, sans se soucier de leur propreté, puis on les peigne avec git rebase -i juste avant de se connecter pour partager une série de commits nette. La synchronisation finale envoie alors un historique déjà soigné, en une seule fois.
✅ Récapitulatif
Vous savez désormais que le rebasage rejoue vos commits en les réécrivant (nouveaux SHA), qu’il produit un historique linéaire, et qu’il ne doit jamais toucher un historique partagé — la règle d’or. Vous maîtrisez git pull --rebase pour des mises à jour propres, le rebasage interactif pour condenser et réordonner vos commits, et --autosquash pour automatiser le rangement. Vous savez enfin arbitrer entre merge et rebase. Une question demeure, inévitable dès que deux personnes touchent les mêmes lignes : que faire quand Git ne peut pas réconcilier seul ? C’est tout l’art de la résolution des conflits.
🧾 Aide-mémoire
| Commande | Rôle |
|---|---|
git rebase main |
Rejouer la branche courante au-dessus de main |
git pull --rebase |
Récupérer puis rejouer ses commits locaux |
git rebase -i HEAD~n |
Rebasage interactif des n derniers commits |
pick / reword / edit / squash / fixup / drop |
Actions du menu interactif |
git commit --fixup <sha> |
Marquer une correction pour un commit cible |
git rebase --autosquash |
Ranger automatiquement les commits --fixup |
git rebase --continue / --abort |
Poursuivre / annuler un rebasage |
git push --force-with-lease |
Pousser une branche personnelle réécrite, en sécurité |
💪 À vous de jouer
Créez une branche avec trois commits dont les messages laissent à désirer (« wip », « test », « fix »). Utilisez le rebasage interactif pour : réécrire le message du premier, fondre les deux suivants dedans, et obtenir un unique commit clair. Vérifiez le résultat.
Voir une solution
git switch -c feature/exercice
echo "a" > ex.js && git add ex.js && git commit -m "wip"
echo "b" >> ex.js && git commit -am "test"
echo "c" >> ex.js && git commit -am "fix"
git rebase -i HEAD~3
# Dans l'éditeur :
# reword -> "Ajoute le module exercice"
# fixup
# fixup
git log --oneline
Le reword ouvre un éditeur pour le nouveau message ; les deux fixup absorbent les commits suivants sans garder leurs messages. Il ne reste qu’un commit propre.
FAQ
Q : Le rebasage supprime-t-il des commits ?
R : Il crée de nouveaux commits et délaisse les anciens, qui restent récupérables un temps via le reflog. Tant que vous ne rebasez pas d’historique partagé, c’est sûr.
Q : Pourquoi mes collègues se plaignent-ils après mon rebasage ?
R : Vous avez probablement réécrit un historique déjà partagé. Respectez la règle d’or : pas de rebasage sur des commits que d’autres ont récupérés.
Q : squash ou fixup ?
R : squash combine les messages et vous laisse les éditer ; fixup jette le message du commit absorbé. Utilisez fixup pour des corrections sans intérêt narratif.
Q : --force ou --force-with-lease ?
R : Toujours préférer --force-with-lease : il refuse d’écraser des commits distants que vous n’avez pas vus, contrairement à --force qui écrase aveuglément.
Q : Puis-je annuler un rebasage déjà terminé ?
R : Oui, via le reflog : git reflog pour retrouver l’état d’avant, puis git reset --hard HEAD@{n}. Voir le tutoriel sur l’annulation et la réparation.
Ressources
- Pro Git, « Rebaser » : git-scm.com/book/fr/v2
- Documentation de
git rebase: git-scm.com/docs/git-rebase - Documentation de
git merge: git-scm.com/docs/git-merge
Dans la même série
🔝 Retour au guide complet : Maîtriser Git et GitHub.