Skip to main content

Rebase interactif — Réécrire l'histoire

Le rebase interactif (git rebase -i) est l'outil le plus puissant pour nettoyer un historique avant de pousser. Il vous permet de modifier, fusionner, réordonner et supprimer des commits comme si vous réécriviez le scénario d'un film.

Les actions disponibles

Quand vous lancez git rebase -i, Git ouvre un éditeur avec une liste de commits et des actions :

pick a1b2c3 feat(nav): add responsive navigation
pick b2c3d4 fix typo in Header.astro
pick c3d4e5 feat(nav): add drawer for mobile
pick d4e5f6 WIP: broken, dont merge
pick e5f6a7 fix: actually make drawer close
CommandeAliasEffet
pickpGarder le commit tel quel
rewordrGarder le commit, modifier le message
editeS'arrêter pour modifier le contenu du commit
squashsFusionner avec le commit précédent, combiner les messages
fixupfFusionner avec le commit précédent, garder seulement le message précédent
dropdSupprimer le commit
(réordonner les lignes)Réordonner les commits

TP — Nettoyer l'historique de feature/responsive-nav

Situation de départ

La branche feature/responsive-nav ressemble à ça dans la vraie vie :

cd ~/git-workshop/ng-baguette-conf
git checkout feature/responsive-nav

# Simuler un historique de feature "honnête"
git log --oneline feature/responsive-nav ^main
# e.g.:
# a1b2c3 feat(nav): replace dropdown with drawer for mobile navigation

Ajoutons l'historique réaliste d'une vraie session de travail :

# La suite du travail en cours (commitée rapidement)
cat >> src/components/Drawer.astro << 'EOF'

<script>
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
const cb = document.getElementById('mobile-nav') as HTMLInputElement | null;
if (cb) cb.checked = false;
}
});
</script>
EOF
git add . && git commit -m "close on ESC"

# Oops, on oublie de gérer le focus
cat >> src/components/Header.astro << 'EOF'
<!-- focus trap à ajouter -->
EOF
git add . && git commit -m "add focus trap comment"

# Fix d'un bug découvert en testant
sed -i '' 's/<!-- focus trap à ajouter -->//' src/components/Header.astro 2>/dev/null || \
sed -i 's/<!-- focus trap à ajouter -->//' src/components/Header.astro
git add . && git commit -m "fix bug"

# Encore un oubli
echo "" >> src/components/Drawer.astro
git add . && git commit -m "wip"

# Finalisation
git commit --allow-empty -m "done I think"

L'historique est maintenant honteux :

git log --oneline feature/responsive-nav ^main
# 5f6a7b8 done I think
# 4e5f6a7 wip
# 3d4e5f6 fix bug
# 2c3d4e5 add focus trap comment
# 1b2c3d4 close on ESC
# a9b0c1d feat(nav): replace dropdown with drawer for mobile navigation

Nettoyer avec rebase -i

# Ouvrir le rebase interactif sur tous les commits depuis main
git rebase -i main

L'éditeur s'ouvre avec :

pick a9b0c1d feat(nav): replace dropdown with drawer for mobile navigation
pick 1b2c3d4 close on ESC
pick 2c3d4e5 add focus trap comment
pick 3d4e5f6 fix bug
pick 4e5f6a7 wip
pick 5f6a7b8 done I think

Modifiez-le pour obtenir :

reword a9b0c1d feat(nav): replace dropdown with drawer for mobile navigation
fixup 1b2c3d4 close on ESC
drop 2c3d4e5 add focus trap comment
fixup 3d4e5f6 fix bug
fixup 4e5f6a7 wip
fixup 5f6a7b8 done I think

Sauvegardez et quittez. Git vous demandera de reword le premier commit :

feat(nav): replace dropdown with drawer for mobile navigation

Corrigez en :

feat(nav): replace dropdown with accessible drawer (mobile)

Résultat final

git log --oneline feature/responsive-nav ^main
# a9b0c1d feat(nav): replace dropdown with accessible drawer (mobile)

Six commits douteux → un seul commit propre qui raconte une histoire claire.

TP — Squash de commits WIP

Scénario fréquent : vous avez commité en cours de route avec des messages wip, fix, oups.

# Voir les 5 derniers commits sur main
git log --oneline -5

Fusionner les 3 derniers commits en un seul :

git rebase -i HEAD~3

Mettez tous sauf le premier en fixup :

pick   abc123 feat: add social links (Bluesky, Twitter, LinkedIn)
fixup def456 fix: correct LinkedIn URL
fixup ghi789 chore: release v1.0.0
fixup vs squash
  • fixup : garde le message du commit au-dessus, jette le reste
  • squash : vous demande de combiner les messages → ouvre l'éditeur

TP — Supprimer un commit

Vous avez commité des credentials ou du code qu'il ne fallait pas :

# Voir l'historique
git log --oneline -5

# Supprimer le commit coupable avec drop
git rebase -i HEAD~N
# Changez "pick" en "drop" sur la ligne concernée
Attention

Si le commit à supprimer modifie des fichiers que des commits suivants utilisent, drop créera des conflits. Résolvez-les normalement avec git rebase --continue.

TP — Réordonner des commits

Parfois vous voulez changer l'ordre pour grouper des changements logiquement :

git rebase -i HEAD~4
# Avant :
pick a feat: add Speaker component
pick b feat: add CFP page
pick c fix: fix Speaker avatar size
pick d test: add schedule tests

# Après (réordonner + squash) :
pick a feat: add Speaker component
fixup c fix: fix Speaker avatar size
pick b feat: add CFP page
drop d test: add schedule tests

--autosquash : le raccourci magique

Si vous commitez avec le préfixe fixup! ou squash! suivi du message de la cible, Git prépare le rebase automatiquement :

# Commit normal
git commit -m "feat: add Agenda component"

# Plus tard, fix à fusionner avec ce commit
git commit -m "fixup! feat: add Agenda component"

# Rebase avec autosquash
git rebase -i --autosquash main
# Git place automatiquement le fixup au bon endroit !

Combiner avec un alias :

git config --global alias.fixup 'commit --fixup'
git fixup HEAD~2 # crée un commit fixup! pour HEAD~2

git commit --amend — cas simple

Pour modifier uniquement le dernier commit (avant de pusher) :

# Modifier le message du dernier commit
git commit --amend -m "feat(nav): correct message"

# Ajouter un fichier oublié au dernier commit
git add fichier-oublie.astro
git commit --amend --no-edit # garde le même message
warning

--amend réécrit le commit (nouveau SHA). Ne jamais amender un commit déjà pushé sur une branche partagée.