Recherche…
Syntaxe
-
git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
-
git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
-
git rebase --continue | --skip | --abort | --edit-todo
Paramètres
Paramètre | Détails |
---|---|
--continuer | Redémarrez le processus de rebasage après avoir résolu un conflit de fusion. |
--avorter | Abandonnez l'opération de réinitialisation et réinitialisez HEAD dans la branche d'origine. Si la branche a été fournie lorsque l'opération de rebase a été lancée, HEAD sera réinitialisé sur la branche. Sinon, HEAD sera réinitialisé à l'endroit où l'opération de rebase a été lancée. |
- maintenir-vide | Conservez les commits qui ne changent rien de ses parents dans le résultat. |
--sauter | Redémarrez le processus de rebasage en ignorant le correctif actuel. |
-m, --merge | Utilisez des stratégies de fusion pour rebaser. Lorsque la stratégie de fusion récursive (par défaut) est utilisée, cela permet à rebase de prendre connaissance des noms de domaine en amont. Notez qu'une fusion rebase fonctionne en relisant chaque validation depuis la branche de travail située en haut de la branche en amont. À cause de cela, quand un conflit de fusion se produit, la partie rapportée comme la nôtre est la série rebasée jusqu'ici, en commençant par l'amont, et la leur est la branche de travail. En d'autres termes, les côtés sont échangés. |
--stat | Montrer un différent de ce qui a changé en amont depuis le dernier rebase. Le diffstat est également contrôlé par l'option de configuration rebase.stat. |
-x, command --exec | Effectuer un rebase interactif, arrêter entre chaque command validation et d'exécution |
Remarques
N'oubliez pas que rebase réécrit efficacement l'historique du référentiel.
Les remises de réaffectation existant dans le référentiel distant pourraient réécrire les nœuds de référentiel utilisés par d'autres développeurs en tant que nœud de base pour leurs développements. À moins que vous ne sachiez vraiment ce que vous faites, il est recommandé de repasser avant de pousser vos modifications.
Rebranchement de branche locale
Rebasing réapplique une série de commits au-dessus d'un autre commit.
Pour rebase
une branche, rebase
la branche, puis rebase
-la sur une autre branche.
git checkout topic
git rebase master # rebase current branch onto master branch
Cela provoquerait:
A---B---C topic
/
D---E---F---G master
Se transformer en:
A'--B'--C' topic
/
D---E---F---G master
Ces opérations peuvent être combinées en une seule commande qui extrait la branche et la rebase immédiatement:
git rebase master topic # rebase topic branch onto master branch
Important: Après le rebase, les validations appliquées auront un hachage différent. Vous ne devez pas rebaser les commits que vous avez déjà envoyés sur un hôte distant. Une conséquence peut être une incapacité à git push
votre branche rebasée locale vers un hôte distant, en laissant votre seule option à git push --force
.
Rebase: les nôtres et les leurs, local et distant
Une rebase change le sens de "notre" et "leurs":
git checkout topic
git rebase master # rebase topic branch on top of master branch
Quelle que soit la direction de HEAD, c'est "la nôtre"
La première chose que fait un rebase est de réinitialiser le HEAD
pour le master
; avant picorage engage de l'ancienne branche topic
à un nouveau (tous les commits dans l'ancien topic
branche sera réécrite et seront identifiés par un hachage différent).
En ce qui concerne les terminologies utilisées par les outils de fusion (à ne pas confondre avec ref local ou ref distant )
=> local is master ("ours"),
=> remote is topic ("theirs")
Cela signifie qu'un outil de fusion / diff présentera la branche en amont comme local
( master
: la branche au-dessus de laquelle vous rebasez), et la branche de travail comme remote
( topic
: la branche en cours de rebasage)
+-----------------------------------------+
| LOCAL:master | BASE | REMOTE:topic |
+-----------------------------------------+
| MERGED |
+-----------------------------------------+
Inversion illustrée
Sur une fusion:
c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
\
\
\--y--y--y <- other branch to merge
Nous ne changeons pas le topic
branche actuelle, donc ce que nous avons est toujours ce sur quoi nous travaillions (et nous fusionnons à partir d'une autre branche)
c--c--x--x--x---------o(*) MERGE, still on branch topic
\ ^ /
\ ours /
\ /
--y--y--y--/
^
theirs
Sur un rebase:
Mais sur une rebase, nous changeons de côté car la première chose que fait une rebase est de récupérer la branche en amont pour rejouer les commits en cours!
c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
\
\
\--y--y--y <- upstream branch
Un git rebase upstream
abord HEAD
sur la branche en amont, d'où le changement de «ours» et de «leurs» par rapport à la branche de travail «actuelle» précédente.
c--c--x--x--x <- former "current" branch, new "theirs"
\
\
\--y--y--y(*) <- set HEAD to this commit, to replay x's on it
^ this will be the new "ours"
|
upstream
Le rebasage sera ensuite rejouer « leur » engage sur le nouveau « notre » topic
branche:
c--c..x..x..x <- old "theirs" commits, now "ghosts", available through "reflogs"
\
\
\--y--y--y--x'--x'--x'(*) <- topic once all x's are replayed,
^ point branch topic to this commit
|
upstream branch
Rebase interactif
Cet exemple a pour but de décrire comment on peut utiliser le git rebase
en mode interactif. On s'attend à ce que l'on ait une compréhension de base de ce qu'est le git rebase
et de ce qu'il fait.
Le rebase interactif est lancé à l'aide de la commande suivante:
git rebase -i
L'option -i
fait référence au mode interactif . En utilisant le rebase interactif, l'utilisateur peut modifier les messages de validation, ainsi que réorganiser, diviser et / ou squash (combiner en un seul) commits.
Disons que vous souhaitez réorganiser vos trois derniers commits. Pour ce faire, vous pouvez exécuter:
git rebase -i HEAD~3
Après avoir exécuté les instructions ci-dessus, un fichier sera ouvert dans votre éditeur de texte où vous pourrez sélectionner la manière dont vos commits seront rebasés. Pour les besoins de cet exemple, changez simplement l’ordre de vos commits, enregistrez le fichier et fermez l’éditeur. Cela déclenchera un rebase avec l'ordre que vous avez appliqué. Si vous cochez git log
vous verrez vos commits dans la nouvelle commande que vous avez spécifiée.
Reformulation des messages de validation
Maintenant, vous avez décidé que l'un des messages de validation est vague et que vous souhaitez qu'il soit plus descriptif. Examinons les trois derniers commits en utilisant la même commande.
git rebase -i HEAD~3
Au lieu de réorganiser la commande, les commits seront rebasés, cette fois nous changerons le pick
, la valeur par défaut, pour reword
un commit où vous voudriez changer le message.
Lorsque vous fermez l'éditeur, le rebase se lance et s'arrête au message de validation spécifique que vous souhaitez reformuler. Cela vous permettra de changer le message de validation selon votre souhait. Après avoir modifié le message, fermez simplement l'éditeur pour continuer.
Changer le contenu d'un commit
Outre la modification du message de validation, vous pouvez également adapter les modifications apportées par le commit. Pour ce faire, changez simplement pick
pour edit
pour un commit. Git s'arrêtera lorsqu'il arrivera à cette validation et fournira les modifications d'origine de la validation dans la zone de mise en attente. Vous pouvez maintenant adapter ces modifications en les désinstallant ou en ajoutant de nouvelles modifications.
Dès que la zone de transfert contient toutes les modifications souhaitées, validez les modifications. L'ancien message de validation sera affiché et pourra être adapté pour refléter le nouveau commit.
Fractionnement d'un seul engagement en plusieurs
Supposons que vous ayez fait un commit mais que, plus tard, vous avez décidé de diviser ce commit en deux ou plusieurs commits. En utilisant la même commande qu'auparavant, remplacez plutôt pick
par edit
et appuyez sur enter.
Maintenant, git s'arrêtera à la validation que vous avez marquée pour l'édition et place tout son contenu dans la zone de transfert. A partir de là, vous pouvez lancer git reset HEAD^
pour placer le commit dans votre répertoire de travail. Ensuite, vous pouvez ajouter et valider vos fichiers dans un ordre différent - en fin de compte, diviser un seul commit en n commits.
Écraser plusieurs commets en un
Supposons que vous ayez fait du travail et que vous ayez plusieurs commits qui, selon vous, pourraient être un simple commit. Pour cela, vous pouvez effectuer git rebase -i HEAD~3
, en remplaçant 3
par une quantité appropriée de commits.
Cette fois, remplacez pick
par squash
place. Au cours du rebase, la validation à laquelle vous avez demandé d'être écrasé sera écrasée par-dessus la validation précédente; les transformer en un seul engagement à la place.
Abandon d'une base de données interactive
Vous avez démarré un rebase interactif. Dans l'éditeur où vous choisissez vos commits, vous décidez que quelque chose ne va pas (par exemple, une validation est manquante ou vous avez choisi la mauvaise destination de rebase) et vous souhaitez abandonner le rebase.
Pour ce faire, supprimez simplement tous les commits et actions (c.-à-d. Toutes les lignes ne commençant pas par le signe #
) et la rebase sera annulée!
Le texte d'aide dans l'éditeur fournit effectivement cette astuce:
# Rebase 36d15de..612f2f7 onto 36d15de (3 command(s))
#
# 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
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Note that empty commits are commented out
Pousser après un rebase
Parfois, vous avez besoin de réécrire l'histoire avec une rebase, mais git push
plaint de le faire parce que vous avez réécrit l'histoire.
Cela peut être résolu avec un git push --force
, mais considérez git push --force-with-lease
, indiquant que vous voulez que le push échoue si la branche de suivi à distance locale diffère de la branche sur la télécommande, par exemple, quelqu'un sinon poussé à la télécommande après la dernière extraction. Cela évite d'écraser par inadvertance la poussée récente de quelqu'un d'autre.
Remarque : git push --force
- et même --force-with-lease
pour cette question - peut être une commande dangereuse car elle réécrit l'historique de la branche. Si une autre personne avait tiré la branche avant la poussée forcée, son / sa git pull
ou git fetch
aurait des erreurs parce que l'histoire locale et l'histoire distante sont divergentes. Cela peut entraîner des erreurs inattendues. Lorsque l’on regarde suffisamment les reflocs, le travail de l’autre utilisateur peut être récupéré, mais cela peut entraîner beaucoup de temps perdu. Si vous devez effectuer une poussée forcée vers une branche avec d'autres contributeurs, essayez de vous coordonner avec eux afin qu'ils n'aient pas à gérer les erreurs.
Rebase à la validation initiale
Depuis Git 1.7.12, il est possible de rebaser à la validation racine. La validation racine est la première validation jamais effectuée dans un référentiel et ne peut normalement pas être modifiée. Utilisez la commande suivante:
git rebase -i --root
Rebasing avant une revue de code
Résumé
Cet objectif est de réorganiser tous vos commits dispersés en des commits plus significatifs pour des revues de code plus faciles. S'il y a trop de couches de changements sur trop de fichiers à la fois, il est plus difficile de faire une révision du code. Si vous pouvez réorganiser vos commits créés chronologiquement en commits d'actualité, le processus de révision du code est plus facile (et peut-être moins de bogues au cours du processus de révision du code).
Cet exemple trop simplifié n'est pas la seule stratégie pour utiliser git pour faire de meilleures révisions de code. C'est comme ça que je le fais, et c'est quelque chose qui inspire les autres à réfléchir à la manière de rendre les révisions de code et l'histoire de Git plus faciles / meilleures.
Cela démontre également pédagogiquement le pouvoir de rebase en général.
Cet exemple suppose que vous connaissez le rebasage interactif.
En supposant:
- vous travaillez sur une branche de fonctionnalités de maître
- votre fonctionnalité comporte trois couches principales: front-end, back-end, DB
- Vous avez fait beaucoup de commits en travaillant sur une branche de fonctionnalités. Chaque validation touche plusieurs couches à la fois
- vous voulez (au final) que trois commits dans votre branche
- un contenant tous les changements frontaux
- un contenant tous les changements de back-end
- un contenant tous les changements de base de données
Stratégie:
- nous allons changer nos engagements chronologiques en engagements "topiques".
- Tout d'abord, divisez tous les commits en plusieurs commits plus petits - chacun ne contenant qu'un seul sujet à la fois (dans notre exemple, les sujets sont les modifications front-end, back-end, DB)
- Réorganisez ensuite nos commits topiques et «écrasez-les» en des engagements uniques
Exemple:
$ git log --oneline master..
975430b db adding works: db.sql logic.rb
3702650 trying to allow adding todo items: page.html logic.rb
43b075a first draft: page.html and db.sql
$ git rebase -i master
Cela sera affiché dans l'éditeur de texte:
pick 43b075a first draft: page.html and db.sql
pick 3702650 trying to allow adding todo items: page.html logic.rb
pick 975430b db adding works: db.sql logic.rb
Changez la en ceci:
e 43b075a first draft: page.html and db.sql
e 3702650 trying to allow adding todo items: page.html logic.rb
e 975430b db adding works: db.sql logic.rb
Ensuite, git appliquera un engagement à la fois. Après chaque validation, il affichera une invite, puis vous pourrez effectuer les opérations suivantes:
Stopped at 43b075a92a952faf999e76c4e4d7fa0f44576579... first draft: page.html and db.sql
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
$ git status
rebase in progress; onto 4975ae9
You are currently editing a commit while rebasing branch 'feature' on '4975ae9'.
(use "git commit --amend" to amend the current commit)
(use "git rebase --continue" once you are satisfied with your changes)
nothing to commit, working directory clean
$ git reset HEAD^ #This 'uncommits' all the changes in this commit.
$ git status -s
M db.sql
M page.html
$ git add db.sql #now we will create the smaller topical commits
$ git commit -m "first draft: db.sql"
$ git add page.html
$ git commit -m "first draft: page.html"
$ git rebase --continue
Ensuite, vous répéterez ces étapes pour chaque validation. Au final, vous avez ceci:
$ git log --oneline
0309336 db adding works: logic.rb
06f81c9 db adding works: db.sql
3264de2 adding todo items: page.html
675a02b adding todo items: logic.rb
272c674 first draft: page.html
08c275d first draft: db.sql
Maintenant, nous exécutons une nouvelle fois rebase pour réorganiser et écraser:
$ git rebase -i master
Cela sera affiché dans l'éditeur de texte:
pick 08c275d first draft: db.sql
pick 272c674 first draft: page.html
pick 675a02b adding todo items: logic.rb
pick 3264de2 adding todo items: page.html
pick 06f81c9 db adding works: db.sql
pick 0309336 db adding works: logic.rb
Changez la en ceci:
pick 08c275d first draft: db.sql
s 06f81c9 db adding works: db.sql
pick 675a02b adding todo items: logic.rb
s 0309336 db adding works: logic.rb
pick 272c674 first draft: page.html
s 3264de2 adding todo items: page.html
AVIS: assurez-vous que vous indiquez à git rebase d'appliquer / écraser les plus petits commits d'actualité dans l'ordre dans lequel ils ont été engagés chronologiquement . Sinon, vous pourriez avoir de faux conflits de fusion inutiles.
Lorsque tout cela est dit et fait, vous obtenez ceci:
$ git log --oneline master..
74bdd5f adding todos: GUI layer
e8d8f7e adding todos: business logic layer
121c578 adding todos: DB layer
résumer
Vous avez maintenant rebaptisé vos commits chronologiques en commits d'actualité. Dans la vraie vie, vous n'avez peut-être pas besoin de le faire à chaque fois, mais quand vous voulez ou devez le faire, vous pouvez le faire maintenant. De plus, j'espère que vous en avez appris plus sur le rebit de Git.
Configuration de git-pull pour effectuer automatiquement une rebase au lieu d'une fusion
Si votre équipe suit un flux de travail basé sur une base de données, il peut être avantageux de configurer git pour que chaque branche nouvellement créée effectue une opération de rebase, au lieu d'une opération de fusion, pendant une git pull
.
Pour configurer chaque nouvelle branche afin qu'elle se réinitialise automatiquement, ajoutez ce qui suit à votre .gitconfig
ou .git/config
:
[branch]
autosetuprebase = always
Ligne de commande: git config [--global] branch.autosetuprebase always
Vous pouvez également configurer la commande git pull
pour toujours vous comporter comme si l'option --rebase
était transmise:
[pull]
rebase = true
Ligne de commande: git config [--global] pull.rebase true
Tester tous les commits pendant le rebase
Avant de faire une demande d'extraction, il est utile de s'assurer que la compilation est réussie et que les tests réussissent pour chaque validation dans la branche. Nous pouvons le faire automatiquement en utilisant le paramètre -x
.
Par exemple:
git rebase -i -x make
effectuera le rebase interactif et s'arrêtera après chaque engagement à exécuter make
. Dans le cas make
échoue, git cessera de vous donner l'occasion de corriger les problèmes et modifier le commit avant de procéder à la cueillette de la suivante.
Configuration de l'autostash
Autostash est une option de configuration très utile lorsque vous utilisez rebase pour des modifications locales. Souvent, vous devrez peut-être importer des commits de la branche en amont, mais vous n'êtes pas encore prêt à vous engager.
Cependant, Git ne permet pas à une rebase de démarrer si le répertoire de travail n'est pas propre. Autostash à la rescousse:
git config --global rebase.autostash # one time configuration
git rebase @{u} # example rebase on upstream branch
L'autostash sera appliqué chaque fois que le rebase est terminé. Peu importe que la réinitialisation se termine avec succès ou qu'elle soit interrompue. De toute façon, l'autostash sera appliqué. Si le rebase a réussi et que la validation de base a donc changé, il peut y avoir un conflit entre l'autostash et les nouveaux commits. Dans ce cas, vous devrez résoudre les conflits avant de vous engager. Ce n'est pas différent que si vous aviez manuellement masqué, puis appliqué, donc il n'y a aucun inconvénient à le faire automatiquement.