Aller au contenu
Développement medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Rebase fondamental : réécrire l'historique Git

9 min de lecture

git rebase rejoue vos commits sur une nouvelle base pour obtenir un historique linéaire. Au lieu de créer un commit de fusion comme git merge, le rebase réécrit l’historique comme si vous aviez commencé votre travail depuis le dernier commit de la branche cible. Ce guide couvre le rebase interactif, la règle d’or à ne jamais enfreíndre et le rebase --onto pour les déplacements avancés.

Prérequis : Merge et résolution de conflits.

  • Comprendre le mécanisme du rebase et pourquoi les hashes changent
  • Comparer merge et rebase pour choisir la bonne stratégie
  • Appliquer la règle d’or : ne jamais rebaser une branche partagée
  • Utiliser rebase -i pour nettoyer un historique avant de pousser
  • Transporter une branche avec rebase --onto

Imaginons deux branches divergentes :

Avant rebase :
C4 ← C5 (main)
/
C1 ← C2 ← C3
\
C6 ← C7 (feature ← HEAD)

Un git merge main depuis feature créerait un commit de fusion. Un git rebase main fait autre chose :

  1. Git identifie les commits propres à feature (C6, C7)
  2. Git les « détache » temporairement
  3. Git avance feature sur le bout de main (C5)
  4. Git rejoue C6 et C7 un par un, créant de nouveaux commits (C6', C7')
Après git rebase main (depuis feature) :
C6' ← C7' (feature ← HEAD)
/
C1 ← C2 ← C3 ← C4 ← C5 (main)

L’historique est maintenant linéaire. Les commits C6' et C7' sont de nouveaux commits (hash différent) mais avec le même contenu que C6 et C7.

Fenêtre de terminal
# 1. Basculez sur votre branche feature
git switch feature
# 2. Rebasez sur main
git rebase main
# 3. Retournez sur main et faites un fast-forward
git switch main
git merge feature # Fast-forward garanti

Après le rebase, le merge depuis main est toujours un fast-forward puisque feature est « devant » main dans le graphe linéaire.

Le rebase rejoue les commits un par un. Un conflit peut survenir à chaque étape :

Fenêtre de terminal
# Git s'arrête et affiche :
# CONFLICT (content): Merge conflict in fichier.txt
# ...
# hint: Resolve all conflicts manually, mark them as resolved with
# hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
  1. Éditez le fichier et résolvez le conflit (mêmes marqueurs que dans un merge)

  2. Marquez le fichier résolu :

    Fenêtre de terminal
    git add fichier.txt
  3. Continuez le rebase :

    Fenêtre de terminal
    git rebase --continue
  4. Si le conflit suivant apparaît, répétez les étapes 1 à 3.

Vous pouvez aussi abandonner le rebase en cours :

Fenêtre de terminal
git rebase --abort

Le dépôt revient exactement à l’état d’avant le rebase.

Ce qui se passe concrètement si vous rebasez de l’historique pushé

Section intitulée « Ce qui se passe concrètement si vous rebasez de l’historique pushé »

Imaginez que vous poussez C6 et C7 sur origin/feature. Un collègue les récupère (git fetch). Vous rebasez ensuite et force-pushup C6' et C7' (mêmes contenus, nouveaux hashes).

Votre collègue se retrouve avec :

Son historique local :
... ← C6 ← C7 (sa branche, basée sur les anciens commits)
Ce qu'affiche origin/feature après votre force-push :
... ← C6' ← C7' (nouveaux hashes)

Git voit deux histoires divergentes. La réconciliation est complexe et génère des commits dupliqués dans l’historique final.

La règle est simple :

SituationAction
Branche locale, jamais pousséeRebase sans souci
Branche poussée, mais vous êtes le seul à travailler dessusRebase possible (puis git push --force-with-lease)
Branche partagée avec d’autresMerge uniquement

Par défaut, git pull fait un fetch + merge. Avec --rebase, il fait un fetch + rebase : vos commits locaux sont rejoués sur les commits distants.

Fenêtre de terminal
git pull --rebase origin main

Pour en faire le comportement par défaut :

Fenêtre de terminal
git config --global pull.rebase true

C’est la configuration recommandée pour garder un historique propre quand vous travaillez seul sur une branche.

--onto permet de déplacer une chaîne de commits d’une base vers une autre. C’est utile quand vous avez branché depuis la mauvaise branche :

Avant :
C8 ← C9 (ma-feature ← HEAD)
/
C6 ← C7 (develop)
/
C1 ← C2 ← C3 ← C4 ← C5 (main)

Vous voulez que ma-feature parte de main au lieu de develop :

Fenêtre de terminal
git rebase --onto main develop ma-feature
Après :
C8' ← C9' (ma-feature ← HEAD)
/
C1 ← C2 ← C3 ← C4 ← C5 (main)
\
C6 ← C7 (develop)

La syntaxe : git rebase --onto <nouvelle-base> <ancienne-base> <branche>.

CritèreMergeRebase
HistoriqueNon-linéaire (losanges)Linéaire
TraçabilitéCommit de merge explicitePas de commit de merge
SécuritéPas de réécritureRéécrit les hash
ConflitsUne seule résolutionRésolution commit par commit
Travail partagéToujours sûrDangereux si poussé

Recommandation pragmatique :

  • Rebase pour mettre à jour votre branche locale avec les derniers changements de main
  • Merge (avec --no-ff) pour intégrer une branche terminée dans main

Cette approche donne un historique propre avec des points de merge explicites marquant chaque fonctionnalité.

SymptômeCause probableSolution
Conflit sur chaque commit pendant le rebaseDivergence importante entre branchesEnvisagez un merge plutôt qu’un rebase
fatal: It seems that there is already a rebase-merge directoryRebase précédent non terminégit rebase --abort pour nettoyer
Commits dupliqués après pushRebase de commits déjà poussésgit reflog pour retrouver l’état, évitez à l’avenir
! [rejected] (non-fast-forward) après rebaseLe remote a les anciens commitsgit push --force-with-lease (si branche perso)
  • Rebase rejoue vos commits sur une nouvelle base → historique linéaire
  • Merge crée un commit de fusion → préserve l’historique tel quel
  • Règle d’or : ne jamais rebaser des commits déjà partagés
  • git pull --rebase garde un historique propre au quotidien
  • git rebase --onto déplace une chaîne de commits vers une autre base
  • En cas de doute, privilégiez le merge : il est toujours sûr

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn