Retour au cours

infra / git-github

Rebase

Leçon 61 exercice

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 -i avant de les partager
  • Utiliser --force-with-lease plutôt que --force aprè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 -iEffet
pickGarde le commit tel quel
squashFusionne dans le commit précédent
rewordGarde le contenu, permet de réécrire le message
dropSupprime 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.

bash
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)
bash
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
bash
# Rebase interactif : réécrire, réordonner, fusionner ou supprimer des commits locaux
git rebase -i HEAD~5
bash
# É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
bash
# 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 -i permet 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-lease est bien plus sûr que --force après un rebase.

Exercices pratiques

1 disponible
1

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.

Résoudre l’exercice →