infra / git-github
Rebase
Explication
Ce que vous allez apprendre
- Comprendre en quoi le rebase diffère fondamentalement du merge (rejouer plutôt que réunir)
- Réaliser qu'un rebase change les identifiants (SHA) des commits rejoués
- Appliquer la règle d'or : ne jamais rebase une branche déjà partagée
- Nettoyer une série de commits locaux avec
git rebase -iavant de les partager - Utiliser
--force-with-leaseplutôt que--forceaprès un rebase nécessaire
Dans quel contexte ?
Avant d'ouvrir une Pull Request sur boutique-api, un développeur réalise que sa branche feature/user-auth contient six commits, dont trois du type "wip", "fix typo" et "oops forgot file". Avec git rebase -i HEAD~6, il les réorganise et les fusionne en deux commits propres et compréhensibles, avant que quiconque d'autre n'ait récupéré cette branche — c'est précisément la condition qui rend ce nettoyage sans danger.
Une autre philosophie que le merge
D'abord, rappelle-toi le merge de la leçon précédente : il préserve l'histoire telle qu'elle s'est déroulée, quitte à créer des commits de fusion et un historique qui se ramifie visuellement.
Ce que propose le rebase à la place
Le rebase propose une philosophie différente : au lieu de "réunir" deux lignes d'historique, il rejoue tes commits, un par un, comme s'ils avaient été écrits à partir de la version la plus récente de la branche cible.
Le résultat obtenu
Le résultat est un historique parfaitement linéaire, comme si tout s'était passé dans l'ordre, sans jamais de commit de fusion.
Le prix à payer pour cette élégance
Ce résultat a une contrepartie importante : rejouer un commit produit un commit techniquement différent, avec un nouvel identifiant unique (SHA), même si son contenu semble identique.
Ce que ça signifie concrètement
Autrement dit, le rebase ne "déplace" pas vraiment tes commits, il en crée de nouvelles versions et abandonne les anciennes.
La conséquence pratique de ce détail technique
Puisque le rebase change les identifiants des commits, toute personne ayant déjà récupéré les anciens commits se retrouve avec un historique divergent dès que tu republies la version réécrite.
La règle d'or à ne jamais transgresser
C'est pourquoi la règle absolue est : ne jamais rebaser une branche déjà partagée avec d'autres personnes. Le rebase est un outil de nettoyage personnel, à utiliser sur son propre travail avant de le partager.
Piège dangereux
Rebaser puis pousser une branche que d'autres personnes ont déjà récupérée force chacune d'entre elles à gérer un historique divergent, avec des commits en double ou des conflits difficiles à comprendre. Vérifie toujours si une branche a déjà été partagée avant d'envisager un rebase dessus.
Aller plus loin : nettoyer avant de montrer
Le rebase interactif (rebase -i) pousse cette logique plus loin : il permet de réorganiser, fusionner ou même supprimer des commits locaux avant de les partager.
Ce que ça permet concrètement
C'est pratique pour transformer une série de commits brouillons, "wip", "fix typo", "oops", en une histoire propre et compréhensible, avant d'ouvrir une Pull Request.
Action dans rebase -i | Effet |
|---|---|
pick | Garde le commit tel quel |
squash | Fusionne dans le commit précédent |
reword | Garde le contenu, permet de réécrire le message |
drop | Supprime purement le commit |
Maintenant que tu sais réécrire un historique local, la leçon suivante s'attaque à ce qui se passe quand Git ne peut plus décider tout seul : la résolution de conflits.
Commandes & code
Rebase
Le rebase réécrit l'historique : il rejoue les commits d'une branche sur une nouvelle base, au lieu de créer un commit de merge.
main: A---B---E---F
feature: \---C---D
# Après "git rebase main" (depuis feature) :
main: A---B---E---F
feature: \---C'---D' (C et D REJOUÉS, nouveaux SHA)git switch feature/user-auth
git rebase main
# En cas de conflit : Git s'arrête, corriger, puis :
git add <fichiers-résolus>
git rebase --continue
# ou abandonner complètement :
git rebase --abort# Rebase interactif : réécrire, réordonner, fusionner ou supprimer des commits locaux
git rebase -i HEAD~5# Éditeur ouvert par "rebase -i" : choisir une action par commit
pick a1b2c3d Add login endpoint
squash e4f5g6h Fix typo in login endpoint # fusionne dans le commit précédent
reword h7i8j9k Add password hashing # permet de réécrire le message
drop k0l1m2n Remove debug console.log # supprime purement ce commit
pick n3o4p5q Add logout endpoint# Règle d'or : NE JAMAIS rebase une branche déjà partagée/pushée que d'autres utilisent
# -> réécrit l'historique, casse les clones des collègues (SHA différents)
# Si un rebase a déjà été poussé et qu'il FAUT le forcer (branche perso uniquement) :
git push --force-with-lease origin feature/user-auth
# "--force-with-lease" refuse d'écraser si quelqu'un d'autre a poussé entretemps
# (contrairement à "--force" qui écrase aveuglément)Résumé
- Rebase = rejoue les commits sur une nouvelle base -> historique linéaire, mais SHA changés.
rebase -ipermet squash/reword/drop/reorder pour nettoyer l'historique avant un push.- Ne jamais rebase une branche déjà partagée avec d'autres personnes.
--force-with-leaseest bien plus sûr que--forceaprès un rebase.
Exercices pratiques
Mission : éviter la catastrophe du rebase partagé
Objectif : Reconnaître quand un rebase est sûr ou dangereux selon l'état de partage d'une branche, et nettoyer un historique local avant une PR.
Contexte
Sur boutique-api, la branche feature/user-auth contient six commits brouillons ("wip", "fix typo", "oops"). Un collègue a déjà récupéré cette branche pour tester en local avant qu'elle ne soit prête, sans que l'auteur original ne le sache.