J'ai remarqué que les deux blocs de commandes suivantes git ont des comportements différents et je ne comprends pas pourquoi.
J'ai une A
et une B
branche qui divergent avec un commit
---COMMIT--- (A)
\
--- (B)
Je veux rebaser B
branche sur la dernière A
(et avoir le commit sur la branche B
)
---COMMIT--- (A)
\
--- (B)
Pas de problème si je le fais:
checkout B
rebase A
Mais si je le fais:
checkout B
rebase --onto B A
Cela ne fonctionne pas du tout, rien ne se passe. Je ne comprends pas pourquoi les deux comportements sont différents.
Le client phpstorm git utilise la deuxième syntaxe, et me semble donc complètement cassé, c'est pourquoi je demande ce problème de syntaxe.
La syntaxe correcte pour rebaser B
au-dessus de A
à l'aide de git rebase --onto
est dans votre cas:
git checkout B
git rebase --onto A B^
ou rebase B
au-dessus de A
à partir de la validation qui est le parent de B
référencé avec B^
ou B~1
.
Si vous êtes intéressé par la différence entre git rebase <branch>
et git rebase --onto <branch>
lisez la suite.
git rebase <branch>
va rebaser la branche que vous avez actuellement extraite, référencée par HEAD
, en plus de le dernier commit accessible de <branch>
mais - not de HEAD
.
Il s’agit du cas le plus courant de changement de base et est sans doute celui qui nécessite moins de planification au départ.
Before After
A---B---C---F---G (branch) A---B---C---F---G (branch)
\ \
D---E (HEAD) D---E (HEAD)
Dans cet exemple, F
et G
sont des validations accessibles depuis branch
mais pas depuis HEAD
. Dire git rebase branch
prendra D
, c'est-à-dire le premier commit après le point de branchement, et le rebase (c'est-à-dire change son parent) au-dessus de le dernier commit accessible de branch
mais pas de HEAD
, c’est G
.
git rebase --onto
vous permet de rebaser à partir d'un commit spécifique. Cela vous donne le contrôle exact sur ce qui est rebasé et où. Ceci est pour les scénarios où vous devez être précis.
Par exemple, imaginons qu'il soit nécessaire de rebaser HEAD
précisément au-dessus de F
à partir de E
. Nous ne souhaitons importer que F
dans notre branche de travail tout en évitant de conserver D
, car il contient des modifications incompatibles.
Before After
A---B---C---F---G (branch) A---B---C---F---G (branch)
\ \
D---E---H---I (HEAD) E---H---I (HEAD)
Dans ce cas, nous dirions git rebase --onto F D
. Ça signifie:
Rebase le commit accessible de
HEAD
dont le parent estD
au-dessus deF
.
En d'autres termes, change le parent de E
de D
à F
. La syntaxe de git rebase --onto
est alors git rebase --onto <newparent> <oldparent>
.
Un autre scénario dans lequel cela est pratique est lorsque vous souhaitez supprimer rapidement certains commits de la branche actuelle sans avoir à faire un rebase interactive:
Before After
A---B---C---E---F (HEAD) A---B---F (HEAD)
Dans cet exemple, pour supprimer C
et E
de la séquence, vous devez indiquer git rebase --onto B E
ou rebase HEAD
au-dessus de B
où l'ancien parent était E
.
git rebase --onto
peut aller encore plus loin en termes de précision. En fait, cela vous permet de rebaser un plage arbitraire de commits sur un autre.
Voici un exemple:
Before After
A---B---C---F---G (branch) A---B---C---F---G (branch)
\ \
D---E---H---I (HEAD) E---H (HEAD)
Dans ce cas, nous voulons redéfinir la plage exacte E---H
au-dessus de F
, sans tenir compte de l'endroit où HEAD
pointe actuellement. Nous pouvons le faire en disant git rebase --onto F D H
, ce qui signifie:
Rebasez la plage des commits dont le parent est
D
jusqu'àH
au-dessus deF
.
La syntaxe de git rebase --onto
avec un plage de commits devient alors git rebase --onto <newparent> <oldparent> <until>
. Le truc ici est de rappeler que la validation référencée par <until>
est incluse dans la plage et deviendra la nouvelle HEAD
une fois la base refaite.
C'est tout ce que vous devez savoir pour comprendre --onto
:
git rebase --onto <newparent> <oldparent>
Vous changez de parent pour un commit, mais vous ne fournissez pas le sha du commit, mais seulement le sha de son parent actuel (ancien).
Autrement dit, git rebase --onto
sélectionne une plage de validations et les rebase sur la validation donnée en paramètre.
Lisez les pages de manuel de git rebase
, recherchez "sur". Les exemples sont très bons:
example of --onto option is to rebase part of a branch. If we have the following situation:
H---I---J topicB
/
E---F---G topicA
/
A---B---C---D master
then the command
git rebase --onto master topicA topicB
would result in:
H'--I'--J' topicB
/
| E---F---G topicA
|/
A---B---C---D master
Dans ce cas, vous dites à git de redéfinir les commits de topicA
à topicB
au-dessus de master
.
Mettez sous peu, étant donné:
Before rebase After rebase
A---B---C---F---G (branch) A---B---C---F---G (branch)
\ \ \
D---E---H---I (HEAD) \ E'---H' (HEAD)
\
D---E---H---I
git rebase --onto F D H
Ce qui est identique à (parce que --onto
prend un argument):
git rebase D H --onto F
Signifie que la base est validée dans la plage (D, H] au-dessus de F. Notez que la plage est exclusive à gauche. C'est exclusif car il est plus facile de spécifier la 1ère validation en tapant, par exemple, branch
à laisser git
trouve le premier commit divergé de branch
c'est-à-dire D
, ce qui conduit à H
.
o---o (A)
\
o (B)(HEAD)
git checkout B
git rebase --onto B A
Peut être changé en une seule commande:
git rebase --onto B A B
Ce qui ressemble à une erreur ici est le placement de B
qui signifie "déplace quelques commits qui mènent à une branche B
au-dessus de B
". La question est ce que "certains commet" sont. Si vous ajoutez le drapeau -i
, vous verrez qu'il s'agit d'un commit unique pointé par HEAD
. La validation est ignorée car elle est déjà appliquée à --onto
cible B
et il ne se passe donc rien.
La commande est absurde dans tous les cas où le nom de la branche est répété de la sorte. Cela est dû au fait que la gamme de commits sera composée de certains commits qui sont déjà dans cette branche et lors de la création d'une nouvelle base, tous seront ignorés.
git rebase <upstream> <branch> --onto <newbase>
.git rebase
par défaut.git rebase master
Se développe soit:
git rebase --onto master master HEAD
git rebase --onto master master current_branch
Lorsqu'il est utilisé de manière standard, comme:
git checkout branch
git rebase master
Vous ne remarquerez pas qu'après rebase git
déplace branch
vers la dernière validation validée et fait git checkout branch
(voir l'historique git reflog
). Ce qui est intéressant lorsque le deuxième argument est commit hash à la place, rebase nom de branche fonctionne toujours, mais il n’ya pas de branche à déplacer, vous vous retrouvez donc dans "UNAD HEAD" au lieu d’être extrait pour une branche déplacée.
La master
dans --onto
est extraite du premier argument git rebase
.
git rebase master
/ \
git rebase --onto master master
Si pratique, cela peut être n'importe quel autre commit ou branche. De cette façon, vous pouvez limiter le nombre de commits de réabonnement en prenant les plus récents et en laissant les commits primaires divergents.
git rebase --onto master HEAD~
git rebase --onto master HEAD~ HEAD # Expanded.
Réabaissera un simple commit pointé par HEAD
en master
et se terminera par "en tête".
L'argument par défaut HEAD
ou current_branch
est pris contextuellement à partir de l'endroit où vous vous trouvez. C'est pourquoi la plupart des gens choisissent de passer à la branche qu'ils souhaitent rebasonner. Mais lorsque le second argument de base est donné explicitement, vous n'avez pas besoin de valider votre compte avant de le transmettre de manière implicite.
(branch) $ git rebase master
(branch) $ git rebase master branch # Expanded.
(branch) $ git rebase master $(git rev-parse --abbrev-ref HEAD) # Kind of what git does.
Cela signifie que vous pouvez réinitialiser les commits et les branches à partir de l'endroit n'importe lequel. Ainsi, en même temps que la validation automatique après rebase. , vous n’avez pas à vérifier séparément la branche rebasée avant ou après la rebase.
(master) $ git rebase master branch
(branch) $ # Rebased. Notice checkout.
Pour onto
vous avez besoin de deux branches supplémentaires. Avec cette commande, vous pouvez appliquer des validations de branchB
basées sur branchA
sur une autre branche, par exemple. master
. Dans l'exemple ci-dessous, branchB
est basé sur branchA
et vous souhaitez appliquer les modifications de branchB
à master
sans appliquer les modifications de branchA
.
o---o (master)
\
o---o---o---o (branchA)
\
o---o (branchB)
en utilisant les commandes:
checkout master
rebase --onto branchA branchB
vous obtiendrez la hiérarchie suivante de validation.
o'---o' (branchB)
/
o---o (master)
\
o---o---o---o (branchA)