W3docs

git rebase

Découvrez la commande git rebase, ses exemples d'utilisation et la différence entre le rebase standard et le rebase interactif.

Ce que fait git rebase

Rebaser signifie déplacer une série de commits vers un nouveau commit de base. En d'autres termes, git rebase change le point de départ de la branche courante d'un commit à un autre, de sorte qu'il semble que vous ayez créé la branche à partir d'un point différent dans l'historique.

Le point essentiel à comprendre : rebase ne déplace pas vos commits d'origine. Il crée des commits entièrement nouveaux avec les mêmes modifications et messages de commit, mais avec des commits parents différents et donc des hashes de commit (SHA) différents. Les anciens commits deviennent inaccessibles, même si la branche semble identique.

git rebase

Cette page couvre le rebase standard, le rebase interactif, la forme --onto, la résolution des conflits et la façon de récupérer en cas de problème lors d'un rebase.

Rebase vs. merge

git rebase et git merge intègrent tous deux les modifications d'une branche dans une autre, mais ils façonnent l'historique différemment :

  • Merge crée un nouveau commit de fusion qui relie les deux historiques de branches. L'historique est non linéaire mais entièrement préservé — rien n'est réécrit.
  • Rebase rejoue vos commits au-dessus de la branche cible. L'historique reste linéaire (sans commits de fusion), mais les commits d'origine sont réécrits.

Utilisez rebase quand vous souhaitez un historique propre et linéaire pour une branche de fonctionnalité avant de la partager. Utilisez merge quand vous voulez préserver l'historique exact de la façon dont les branches ont été réunies, ou quand la branche est déjà publique.

Rebase standard

En mode standard, git rebase prend les commits propres à votre branche courante et les rejoue au-dessus de <base>. La <base> peut être un nom de branche, un tag ou un identifiant de commit.

git rebase <base>

Le flux de travail typique : master a avancé depuis que vous avez créé votre branche, et vous souhaitez intégrer les dernières modifications de master sous votre travail de fonctionnalité sans commit de fusion.

# you are on your feature branch
git switch feature
# replay feature's commits on top of the current tip of master
git rebase master

Avant le rebase, l'historique ressemble à ceci (feature a été créée à partir d'un ancien master) :

      A---B---C feature
     /
D---E---F---G master

Après git rebase master, les commits de feature sont recréés au-dessus de G :

              A'--B'--C' feature
             /
D---E---F---G master

A', B' et C' portent les mêmes modifications que A, B, C, mais ce sont de nouveaux commits avec de nouveaux hashes.

Ne jamais rebaser l'historique public

Ne rebasez jamais des commits qui ont déjà été poussés et sur lesquels d'autres personnes ont peut-être basé leur travail. Comme rebase remplace les commits par de nouveaux, toute personne ayant récupéré les anciens commits se retrouvera avec un historique désynchronisé — il semblera qu'une partie du projet a disparu, et des commits dupliqués ou conflictuels apparaîtront au prochain pull.

Avertissement

La règle d'or du rebase : ne rebasez que des commits qui existent uniquement sur votre branche locale et qui n'ont pas été partagés. Rebaser des commits déjà publiés est la façon la plus courante dont les équipes cassent les dépôts de leurs collègues.

La limite sûre est simple : rebasez librement votre travail privé ; ne rebasez jamais la branche partagée master/main ni aucune branche sur laquelle d'autres travaillent activement. C'est la même précaution qui s'applique à git reset et à git commit --amend.

Rebase interactif

Le mode interactif (-i, abréviation de « interactive ») vous permet de modifier, réordonner, fusionner ou supprimer des commits individuels au fur et à mesure qu'ils sont rejoués. C'est l'outil que les développeurs utilisent pour nettoyer une branche de fonctionnalité avant de la fusionner — combiner de petits commits « correction de faute de frappe », reformuler des messages peu clairs et supprimer des expériences sans issue.

git rebase -i <base>

Par exemple, pour réorganiser les 3 derniers commits de votre branche :

git rebase -i HEAD~3

Cela ouvre votre éditeur avec une liste de « todo » — une ligne par commit, le plus ancien en haut :

pick 11a1456 Add login form
pick a23db19 Fix typo in label
pick 31d332c Add password validation

# Rebase d4e5f6a..31d332c onto d4e5f6a (3 commands)
#
# Commands:
# p, pick   = use commit
# r, reword = use commit, but edit the commit message
# e, edit   = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup  = like "squash", but discard this commit's log message
# x, exec   = run command (the rest of the line) using shell
# d, drop   = remove commit

Pour fusionner la correction de faute de frappe dans le commit du formulaire de connexion et reformuler le commit de validation, vous changeriez la liste comme suit :

pick 11a1456 Add login form
fixup a23db19 Fix typo in label
reword 31d332c Add password validation

Enregistrez et fermez l'éditeur ; Git rejoue les commits en appliquant chaque instruction dans l'ordre.

Commandes du rebase interactif

Chaque ligne de la liste todo commence par l'une de ces commandes :

  • pick — conserver le commit tel quel. C'est la valeur par défaut pour chaque ligne.
  • reword — conserver les modifications du commit, mais s'arrêter pour modifier son message.
  • edit — s'arrêter à ce commit pour pouvoir modifier son contenu (le diviser, ajouter des fichiers, etc.), puis git rebase --continue.
  • squash — fusionner ce commit dans le précédent et combiner les deux messages en un seul.
  • fixup — comme squash, mais supprimer le message de ce commit (ne garder que le précédent).
  • drop — supprimer entièrement le commit de l'historique.
  • exec — exécuter une commande shell après le commit précédent (utile pour lancer des tests à chaque étape).

Réordonner les lignes réordonne les commits ; supprimer une ligne est équivalent à drop.

La forme --onto

Le flag --onto vous donne un contrôle précis sur quels commits se déplacent et ils atterrissent :

git rebase --onto <newbase> <oldbase> <branch>

Il prend les commits qui sont dans <branch> mais pas dans <oldbase>, et les rejoue sur <newbase>. C'est ainsi que l'on déplace une branche d'une base dont elle n'a plus besoin.

Supposons que featureY ait été créée à partir de featureX, mais qu'elle soit en réalité indépendante des modifications de featureX et qu'elle appartienne à master :

                          o---o---o featureY
                         /
            o---o---o---o featureX
           /
o---o---o---o master

Exécutez :

git rebase --onto master featureX featureY

Ici featureX est <oldbase>, master est <newbase> et featureY est la branche en cours de rebase. Git rejoue uniquement les commits propres à featureY sur master, en les détachant de featureX :

                  o'--o'--o' featureY
                 /
o---o---o---o---o master
           \
            o---o---o---o featureX

Résolution des conflits lors d'un rebase

Comme rebase réapplique vos commits un par un, un conflit peut stopper le processus à n'importe quel commit. Lorsque cela se produit, Git fait une pause et vous indique quels fichiers sont en conflit.

Le flux de travail pour s'en sortir :

# 1. fix the conflicted files in your editor, then stage them
git add <resolved-file>

# 2. continue replaying the remaining commits
git rebase --continue

Autres contrôles pendant qu'un rebase est en pause :

  • git rebase --skip — ignorer le commit courant et continuer (à utiliser avec précaution ; vous perdez les modifications de ce commit).
  • git rebase --abort — tout arrêter et restaurer la branche exactement à l'état où elle était avant que vous commenciez.

Une branche à longue durée de vie qui a beaucoup divergé de master génère le plus de conflits, parfois le même conflit sur plusieurs commits. Deux habitudes réduisent cette douleur : rebasez régulièrement par rapport à master plutôt qu'une seule fois à la fin, et gardez vos commits petits et ciblés.

Options de configuration

Certains paramètres par défaut de rebase peuvent être définis avec git config. Ils modifient le comportement de git rebase et ce qu'il affiche :

  • rebase.stat — un boolean (par défaut false) qui active ou désactive un diffstat visuel des modifications depuis le dernier rebase.
  • rebase.autoSquash — un boolean qui active ou désactive le comportement --autosquash (réorganisation automatique des commits fixup!/squash! lors du rebase interactif).
  • rebase.missingCommitsCheck — contrôle ce qui se passe lorsque des commits sont supprimés de la liste todo. Accepte l'une des valeurs suivantes :
ValeurComportement
ignorePar défaut. Tous les avertissements de commits manquants sont ignorés.
warnUn avertissement est affiché en mode interactif à propos des commits supprimés.
errorLe rebase s'arrête et affiche des messages d'avertissement sur les commits supprimés.
  • rebase.instructionFormat — une string au format git log utilisée pour formater chaque ligne de commit affichée dans la liste todo interactive.

Récupération après un rebase raté

Un rebase peut sembler destructeur : avec squash ou drop, des commits disparaissent du journal de votre branche et il semble qu'ils soient perdus définitivement. Ce n'est pas le cas. Git conserve un enregistrement de l'endroit où pointait votre branche avant chaque opération dans le git reflog.

Pour annuler un rebase, trouvez l'entrée juste avant celui-ci et réinitialisez votre branche à cet état :

# see where the branch was before the rebase
git reflog

# example output:
# a23db19 HEAD@{0}: rebase (finish): returning to refs/heads/feature
# 31d332c HEAD@{5}: rebase (start): checkout master
# c0ffee1 HEAD@{6}: commit: the state you want back

# move the branch back to the pre-rebase commit
git reset --hard HEAD@{6}

C'est votre filet de sécurité — tant que vous pouvez lire le reflog, aucun rebase n'est vraiment irréversible.

Récupération après un rebase en amont

Si un coéquipier rebase et force-push une branche sur laquelle vous travaillez également, un simple git pull tentera de réconcilier vos commits avec la pointe distante réécrite et peut vous laisser avec un historique dupliqué ou enchevêtré.

La solution utilise le reflog de la branche de suivi distant pour trouver où elle pointait avant le rebase, puis rejoue votre travail sur la nouvelle pointe avec --onto :

# find the old tip of origin/feature in the remote-tracking reflog
git reflog show origin/feature

# replay your local commits from the old base onto the new one
git rebase --onto origin/feature <old-origin-tip> feature

Cela déplace uniquement vos commits sur la pointe après le force-push, sans entraîner les anciens commits désormais réécrits.

Sujets connexes

  • git merge — l'alternative sans réécriture pour intégrer des branches.
  • git reflog — votre journal d'annulation pour récupérer après un mauvais rebase.
  • git reset — déplacer un pointeur de branche, y compris vers un état antérieur au rebase.
  • git cherry-pick — rejouer des commits individuels sans rebaser une branche entière.

Pratique

Pratique
What are the correct statements about the " `git rebase` command as described in the W3Docs Git Tutorial?
What are the correct statements about the " `git rebase` command as described in the W3Docs Git Tutorial?
Was this page helpful?