Comment est-ce que je récupère / resynchronise après que quelqu'un a poussé une rebase ou une réinitialisation à une twig publiée?

Nous avons tous entendu que l'on ne devrait jamais rebasquer le travail publié, que c'est dangereux, etc. Cependant, je n'ai vu aucune recette publiée pour savoir comment faire face à la situation en cas de publication d'un rebasage.

Maintenant, notez que ceci n'est vraiment faisable que si le référentiel est seulement cloné par un groupe connu (et de preference petit), de sorte que quiconque pousse le rebasage ou réinitialise peut avertir tout le monde qu'il devra faire attention la prochaine fois qu'il aller chercher (!).

Une solution évidente que j'ai vu fonctionnera si vous n'avez pas de commit local sur foo et qu'il est rebasé:

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

Cela va simplement jeter l'état local de foo en faveur de son histoire selon le référentiel distant.

Mais comment faire face à la situation si l'on a engagé des changements locaux substantiels sur cette twig?

Solutions Collecting From Web of "Comment est-ce que je récupère / resynchronise après que quelqu'un a poussé une rebase ou une réinitialisation à une twig publiée?"

Revenir en synchronisation après un rebasement poussé n'est vraiment pas si 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. vous avez d'abord configuré un signet pour l'location d'origine de la twig distante, puis vous l'utilisez pour rejouer vos commissions locales à partir de ce point sur la twig distante rebasée.

Rebaser est comme la violence: si cela ne résout pas votre problème, vous en avez juste besoin de plus. ☺

Vous pouvez le faire sans le signet, bien sûr, si vous searchz l'ID de pré-rebase origin/foo commit, et l'utilisez.

C'est aussi la façon dont vous gérez la situation où vous avez oublié de créer un signet avant d' aller chercher. Rien n'est perdu – il suffit de vérifier le refog pour la twig distante:

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

Cela affichera l'identifiant de commit que l' origin/foo pointé avant l'extraction la plus récente qui a changé son historique.

Vous pouvez alors simplement

 git rebase --onto origin/foo $commit foo 

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

Ce n'est vraiment pas différent de la récupération de votre propre rebase – vous déplacez une twig, et de rebaser toutes les twigs qui l'ont eu dans leur histoire sur sa nouvelle position.

À partir de git 1.9 / 2.0 Q1 2014, vous n'aurez pas à marquer votre origine de twig précédente avant de la rebaser sur la twig amont réécrite, comme décrit dans la réponse d'Aristote Pagaltzis :
Voir commettre 07d406b et commenter d96855f :

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

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

origin/master utilisé pour pointer sur les commits B3 , B2 , B1 et maintenant il pointe sur B , et votre twig de topic a été démarrée dessus quand origin/master était à B3 .

Ce mode utilise le refog d' origin/master pour find B3 comme sharepoint fork, de sorte que le topic puisse être rebasé au dessus de l' origin/master mis à jour par:

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

C'est pourquoi la command git merge-base a une nouvelle option:

 --fork-point:: 

Trouvez le point où une twig (ou tout autre historique conduisant à <commit> ) est dérivée d'une autre twig (ou de toute reference) <ref> .
Cela ne cherche pas seulement l'ancêtre commun des deux commits, mais prend également en count le refog de <ref> pour voir si l'histoire conduisant à <commit> issue d'une incarnation antérieure de la twig <ref> .


La command " git pull --rebase " calcule le sharepoint fork de la twig en cours de rebasage en utilisant les inputs reflog de la twig " base " (typiquement une twig de remote-tracking) sur laquelle le travail de la twig était basé, pour faire face au cas dans lequel la twig "base" a été rembobinée et reconstruite.

Par exemple, si l'histoire ressemblait à:

  • la pointe courante de la twig " base " est en B , mais on a observé plus tôt que son extrémité était B3 puis B2 , puis B1 avant d'arriver au commit actuel, et
  • la twig rebasée au-dessus de la dernière "base" est basée sur le commit B3 ,

il essaie de find B3 en passant par la sortie de " git rev-list --reflog base " (c'est-à-dire B , B1 , B2 , B3 ) jusqu'à ce qu'il trouve un commit qui est un ancêtre de la pointe actuelle " Derived (topic) " .

En interne, nous avons get_merge_bases_many() qui peut le calculer avec one-go.
Nous voudrions une base de fusion entre Derived et un commit fictif de fusion qui résulterait de la fusion de tous les conseils historiques de " base (origin/master) ".
Quand un tel commit existe, nous devrions get un résultat unique, qui correspond exactement à l'une des inputs reflog de " base ".


Git 2.1 (Q3 2014) appenda cette fonction à plus de robustesse: voir commit 1e0dacd de John Keeping ( 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 B qui n'est pas identique à B avec un patch;
  • C* et D* sont respectivement identiques à C et D et entrent en conflit textuellement s'ils sont appliqués dans le mauvais ordre;
  • E dépend textuellement de D

Le résultat correct du git rebase master dev de git rebase master dev est que B est identifié comme le sharepoint fork de dev et master , de sorte que C , D , E sont les commits qui doivent être rejoués sur master ; mais C et D sont identiques à C* et D* et peuvent donc être supprimés, de sorte que le résultat final est:

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

Si le sharepoint fork n'est pas identifié, alors choisir B sur une twig contenant B' aboutit à un conflit et si les commits de patch-identiques ne sont pas correctement identifiés, alors choisir C sur une twig contenant D (ou D* équivalente) conflit.