web-dev-qa-db-fra.com

Je ne comprends pas le comportement de git rebase --onto

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.

126
Xmanoux

tl; dr

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.

Le Quick: git rebase

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.

The Precise: git rebase --onto avec 2 arguments

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 est D au-dessus de F.

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.

Le chirurgien: git rebase --onto avec 3 arguments

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 de F.

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.

329
Enrico Campidoglio

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).

39
sEver

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.

8
Gauthier

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.

Cas d'OP

    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.

Explication supplémentaire et utilisation applicable de 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

Paiement automatique après rebase.

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.

Omettre les commits primaires divergents.

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".

Évitez les caisses explicites.

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.
7
WloHu

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)
2
Michael Mairegger