Rebase vs Merge — Choisir au bon moment
Les deux histoires du même projet
Imaginez que vous travaillez sur feature/dark-mode. Pendant ce temps, deux commits sont arrivés sur main (un fix de login et une nouvelle feature de cache).
Voici ce que donnent les deux approches :
Avec merge
git checkout feature/dark-mode
git merge main
main: A──B──fix──cache
\
feature: A──B──D──E──────M (M = merge commit)
git log --graph --oneline :
* abc123 Merge branch 'main' into feature/dark-mode
|\
| * def456 feat(cache): add memoize utility
| * efg789 fix(auth): add email validation
* | hij012 feat(ui): add dark mode toggle
* | klm345 feat(theme): add theme system
|/
* nop678 feat(utils): add sortByPriority
→ L'historique est fidèle mais difficile à lire.
Avec rebase
git checkout feature/dark-mode
git rebase main
main: A──B──fix──cache
\
feature: D'──E' (nouveaux SHA)
git log --oneline :
e5f6a7b feat(ui): add dark mode toggle
d4e5f6a feat(theme): add theme system
def456 feat(cache): add memoize utility
efg789 fix(auth): add email validation
nop678 feat(utils): add sortByPriority
→ Historique linéaire, comme si la feature avait été développée sur la version la plus récente.
TP — Mettre à jour une feature branch avec rebase
cd ~/git-workshop/ng-baguette-conf
git checkout feature/speaker-search
# Vérifier la divergence avec main
git log --oneline feature/export-csv ^main
# 1 commit en avance
git log --oneline main ^feature/export-csv
# Tous les commits de main (la feature est basée sur un ancien état)
# Rebaser sur main
git rebase main
# Résoudre les éventuels conflits, puis :
git rebase --continue
# Vérifier le résultat
git log --oneline -5
# Vos commits de feature apparaissent EN DERNIER (les plus récents)
# après tous les commits de main
TP — Gérer un conflit de rebase
Les conflits en rebase se gèrent comme en merge, mais un commit à la fois :
# Simuler un conflit
git checkout main
echo "// version main" >> src/utils/sort.js
git add . && git commit -m "refactor(sort): add main comment"
git checkout feature/export-csv
echo "// version feature" >> src/utils/sort.js
git add . && git commit -m "refactor(sort): add feature comment"
# Rebaser (va créer un conflit)
git rebase main
Git s'arrête sur le commit conflictuel :
CONFLICT (content): Merge conflict in src/utils/sort.js
error: could not apply abc123... refactor(sort): add feature comment
Résolvez le conflit :
# Voir les fichiers en conflit
git status
# Éditer le fichier pour résoudre
# Choisir ou combiner les deux versions
# Stager la résolution
git add src/utils/sort.js
# Continuer le rebase
git rebase --continue
# Git vous demandera peut-être de valider/modifier le message
Si vous vous perdez, annulez tout et recommencez :
git rebase --abort
# Revient à l'état exact avant git rebase
--force-with-lease : pousser après rebase
Après un rebase, les SHA ont changé. Un git push normal sera rejeté si la branche a déjà été pushée. Vous devez forcer :
# ❌ Dangereux : écrase tout ce que quelqu'un aurait pushé entre temps
git push --force
# ✅ Sûr : refuse si quelqu'un a pushé depuis votre dernier pull
git push --force-with-lease
--force-with-lease vérifie que votre référence remote locale correspond à l'état réel du serveur. Si quelqu'un d'autre a pushé, le push échoue avec un message clair.
Stratégie recommandée
┌─────────────────────────────────────────────────────┐
│ Branche locale, non encore pushée ? │
│ → git rebase main librement │
├─────────────────────────────────────────────────────┤
│ Branche pushée, mais personne d'autre ne l'utilise │
│ → git rebase main + git push --force-with-lease │
├─────────────────────────────────────────────────────┤
│ Branche partagée (main, develop, staging...) │
│ → JAMAIS de rebase. Utilisez git merge. │
└─────────────────────────────────────────────────────┘
Checklist avant un rebase
# 1. Sauvegarder sa position actuelle (par précaution)
git log --oneline -1
# Notez le hash — vous pouvez toujours revenir ici avec git reset --hard
# 2. Vérifier que personne n'a basé son travail sur votre branche
git log origin/feature/dark-mode..feature/dark-mode # commits locaux non pushés
# 3. Lancer le rebase
git rebase main
# 4. En cas de problème, utiliser le reflog pour revenir en arrière
git reflog
git reset --hard HEAD@{N}
Challenge — Rebase + bisect
Après avoir trouvé le bug avec bisect (module précédent), nettoyez l'historique de main pour que la correction soit propre :
- Créez une branche
fix/sort-prioritydepuis le commit juste avant le bug - Appliquez la correction dans
src/utils/sort.js(high: 0) - Rebaser
fix/sort-prioritysurmain - Faire un fast-forward merge dans
main - Vérifier avec
node tests/sort.test.jsque les tests passent
# Hint : trouver le hash du commit juste avant le bug
git log --oneline | grep "update priority constants"
# abc123 refactor(sort): update priority constants
git checkout -b fix/sort-priority abc123^
# (le ^ remonte d'un commit)