88 votes

Comment est-ce que je récupère / resynchronise après que quelqu'un pousse une base ou une réinitialisation à une branche publiée?

Nous avons tous entendu dire que l'on ne doit jamais rebase travaux publiés, que c'est dangereux, etc. Cependant, je n'ai pas vu toutes les recettes posté pour savoir comment faire face à la situation dans le cas d'un rebase est publié.

Maintenant, notez que ce n'est réellement possible que si le référentiel n'est cloné par un (et, de préférence, petit groupe de personnes, de sorte que celui qui pousse le rebase ou réinitialiser peut notifier à tout le monde qu'ils ont besoin de prêter attention à la prochaine fois ils fetch(!).

Une solution évidente que j'ai vu fonctionnera si vous n'avez pas de local s'engage sur foo , et elle devient de relocalisée:

git fetch
git checkout foo
git reset --hard origin/foo

Ce sera tout simplement jeter de l'état local de l' foo en faveur de son histoire que par le dépôt distant.

Mais comment faire face à la situation si l'on a engagé d'importants changements locaux sur cette branche?

75voto

Aristotle Pagaltzis Points 43253

Se remettre en phase, après une poussée de rebase est vraiment pas compliqué dans la plupart des cas.

git checkout foo
git branch old-foo origin/foo # BEFORE fetching!!
git fetch
git rebase --onto origin/foo old-foo foo
git branch -D old-foo

C'est à dire. d'abord vous avez configuré un signet pour le cas où la distance n'était à l'origine, puis que vous utilisez pour la relecture de votre région s'engage à partir de ce moment-là sur relocalisée à distance.

La relocalisation est comme la violence: si ça ne résout pas votre problème, vous avez juste besoin d'un plus grand nombre.

Vous pouvez le faire sans le signet bien sûr, si vous regardez en haut de la pré-rebase origin/foo commettre ID, et l'utiliser.

C'est aussi la façon dont vous traitez avec la situation où vous avez oublié de faire un signet avant l'extraction. Rien n'est perdu, vous avez juste besoin de vérifier le reflog pour la branche distante:

git reflog show origin/foo | awk '
    PRINT_NEXT==1 { print $1; exit }
    /fetch: forced-update/ { PRINT_NEXT=1 }'

Cela permettra d'imprimer le commettre ID origin/foo a souligné devant la plus récente de chercher qui a changé son histoire.

Vous pouvez alors simplement

git rebase --onto origin/foo 

11voto

Jefromi Points 127932

Je dirais que la section de la page de manuel git-rebase relative à la récupération d'une base en amont couvre à peu près tout cela.

Ce n'est vraiment pas différent de récupérer de votre propre base - vous déplacez une branche et rebasonnez toutes les branches qui l'avaient dans leur historique sur sa nouvelle position.

11voto

VonC Points 414372

Départ avec git 1.9/2.0 T1 2014, vous n'aurez pas à marquer votre branche précédents origine avant le changement d'année de base sur le réécrit en amont de la branche, comme décrit dans Aristote Pagaltzis's réponse:
Voir commettre 07d406b et s'engager d96855f :

Après avoir travaillé sur l' topic de la branche créé avec git checkout -b topic origin/master, l'histoire de la distance de suivi de la succursale origin/master peut avoir été rembobinée et reconstruit, conduisant à une histoire de cette forme:

                   o---B1
                  /
  ---o---o---B2--o---o---o---B (origin/master)
          \
           B3
            \
             Derived (topic)

origin/master utilisé pour point s'engage B3, B2, B1 et maintenant il points de B, et votre topic de la branche a été démarré sur le haut du dos lors de l' origin/master a été à l' B3.

Ce mode utilise le reflog d' origin/master trouver B3 comme le point de branchement, de sorte que l' topic peut être relocalisée sur le dessus de la mise à jour de origin/master par:

$ fork_point=$(git merge-base --fork-point origin/master topic)
$ git rebase --onto origin/master $fork_point topic

C'est pourquoi l' git merge-base commande dispose d'une nouvelle option:

--fork-point::

Trouver le point à une branche (ou de toute l'histoire qui conduit à l' <commit>) fourche d'une autre branche (ou la référence) <ref>.
Ce n'est pas il suffit de regarder pour l'ancêtre commun des deux commits, mais prend également en compte le reflog d' <ref> pour voir si l'histoire menant à l' <commit> fourche à partir d'une version antérieure de la branche <ref>.


Le "git pull --rebase" commande calcule le point de branchement de la branche être relocalisée à l'aide de la reflog entrées de l'base" de la branche (généralement à une distance de suivi de la succursale) la direction générale du travail a été basé sur, afin de faire face aux cas dans lesquels la "base" de la branche a été rembobinée et reconstruit.

Par exemple, si l'histoire ressemblait où:

  • la pointe de courant de le "base" de la branche est à l' B, mais plus tôt d'aller chercher observé que son embout utilisé pour être B3 puis B2 puis B1 avant d'arriver à l'commit courant, et
  • la branche être relocalisée sur le dessus de la dernière de "base" est basé sur les commettre B3,

il essaie de trouver des B3 en passant par la sortie de "git rev-list --reflog base" ( B, B1, B2, B3) jusqu'à ce qu'il trouve un commit qui est un ancêtre de l'actuel conseil "Derived (topic)".

En interne, nous avons get_merge_bases_many() qui peuvent calculer ce avec un aller.
Nous voulons une fusion de base entre Derived et un fictifs de fusion s'engager à ce que le résultat serait par la fusion de tous les historiques des conseils de "base (origin/master)".
Quand un tel commettre existe pas, nous devrions obtenir un résultat unique, qui correspondent exactement à l'un des reflog entrées de "base".


Git 2.1 (T3 2014) permettra d'ajouter que cette fonction soit plus robuste: voir commettre 1e0dacd par Jean-Observance (johnkeeping)

gérer correctement le scénario où nous avons la topologie suivante:

    C --- D --- E  <- dev
   /
  B  <- master@{1}
 /
o --- B' --- C* --- D*  <- master

où:

  • B' est une version corrigée de l' B qui n'est pas de patch-identique à l' B;
  • C* et D* sont des patch-identique à C et D , respectivement, et les conflits textuellement si elle est appliquée dans le mauvais ordre;
  • E dépend textuellement sur D.

Le résultat correct de git rebase master dev que B est identifié comme la fourche points de dev et master, de sorte qu' C, D, E sont les commits qui ont besoin d'être relus sur master; mais C et D sont des patch-identique à C* et D* et peut donc être supprimée, de sorte que le résultat final est:

o --- B' --- C* --- D* --- E  <- dev

Si la fourche-point n'est pas identifié, puis la cueillette B sur une branche contenant B' résultats dans un conflit et si le patch-identique s'engage ne sont pas correctement identifiés en choissant C sur une branche contenant D (ou, de manière équivalente, D*) entraîne un conflit.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X