Annuler La Commande Git Rebase

j'ai exécuté un git rebase master sur ma branche et je n'ai pas réalisé que ce n'était pas ce que je voulais jusqu'à ce que je l'ai poussé à la télécommande. Il n'y a que moi et une autre personne qui travaille sur le projet, donc je sais qu'ils n'ont pas fait les derniers changements.

en lisant d'autres questions sur StackOverflow, il a dit d'utiliser git reflog et puis git reset --hard HEAD@{n} avant le rebase. J'ai fait ça pour un commit que j'ai créé avant le rebase, mais ça n'a pas restauré les choses comme avant.

est-ce que je manque un pas? Y a-t-il un moyen de forcer l'autre personne à repousser sa prise de position pour rétablir les choses telles qu'elles étaient?

Merci

23
demandé sur user1960364 2015-09-10 01:41:12

3 réponses

comme Makoto déjà noté , vous ne devriez probablement pas prendre la peine de défaire cette rebase: c'est probablement ce que vous vouliez. Néanmoins, n'hésitez pas à lire pour savoir comment l'annuler.


utilisez le refrog pour la branche , car il sera plus facile à lire. (Le HEAD reflog a la même information, mais il y a beaucoup plus de choses dedans, donc il est plus difficile de trouver ce que vous cherchez.)

par exemple si j'avais juste rebasé mybranch , je verrais:

$ git reflog mybranch
nnnnnnn mybranch@{0}: rebase finished: refs/heads/mybranch onto biguglysha1
ooooooo mybranch@{1}: commit: some sort of commit message
...

le nom mybranch@{1} est donc synonyme (à l'heure actuelle) de ooooooo , l'ancienne abréviation SHA-1. Chaque fois que vous faites quelque chose à la branche (comme git reset ) le nombre à l'intérieur de la partie @{...} va changer, alors que les SHA-1 sont permanents pour toujours, il est donc un peu plus sûr d'utiliser le SHA-1 (complet ou abrégé) pour couper-coller.

si vous alors:

$ git checkout mybranch # if needed

et:

$ git reset --hard ooooooo  # or mybranch@{1}

vous devez avoir l'original du dos. C'est parce que rebase tout simplement copie commet puis déplace l'étiquette. Après le rebase, mais avant la réinitialisation, le graphe de propagation ressemble à quelque chose comme ceci, où A à C sont" votre "commits:

          A - B - C              <-- (only in reflog now)
        /
... - o - o - o - A' - B' - C'   <-- mybranch (after rebase)

et git reset simplement 1 efface l'étiquette actuelle de la branche et la colle sur le SHA-1 fourni (transformant un nom reflog en SHA-1 d'abord si nécessaire). Ainsi, après le reset :

          A - B - C              <-- mybranch, plus older reflog
        /
... - o - o - o - A' - B' - C'   <-- (only in reflog now)

notez que maintenant, post- reset , les copies de propagation faites par rebase sont celles" abandonnées " qui ne se trouvent que dans les entrées de reflog. Les originaux, qui avaient été abandonnés, sont maintenant revendiqués sous mybranch à nouveau.

la façon de penser à ce genre de choses est pour dessiner la validation graphique (avec les nouveaux commits renvoyant à leur parent s'engage), puis tirer en direction des étiquettes avec de longues flèches pointant vers le commit graphique. Le graphique ne change jamais 2 sauf en ajouter nouveau commits, qui ont de nouveaux et différents Gros laid SHA-1s (c'est pourquoi j'utilise des lettres comme A B et C à la place, et tack sur les additifs comme A' pour les copies). Les SHA-1 sont garantis d'être unique 3 et sont permanents, mais les étiquettes avec leurs longues flèches, effacer et re-pointé tout le temps. (Si vous faites cela sur un tableau blanc, vous devriez généralement utiliser le noir pour le graphique de propagation et une couleur, ou plusieurs couleurs, pour les étiquettes.)


1 eh bien, git reset ne fait pas que déplacer le label, à moins que vous n'ajoutiez des options en ligne de commande. Par défaut, il se déplace de la label et réinitialise l'index; avec --hard , il déplace l'étiquette et réinitialise l'index et nettoie votre travail-de l'arbre. Avec --soft il juste déplace l'étiquette, laissant l'index et le travail de l'arbre-seul. Avec git étant ce qu'il est, il y a un tas plus de drapeaux qui déforment le sens encore plus loin, mais ce sont les trois grands: --soft , rien aka --mixed , et --hard .

2 si git n'ajoutait que des choses, votre pension de retraite serait énorme au fil du temps. Ainsi, finalement," unreachable "commits-ceux qui n'ont pas d'étiquettes, et même pas n'importe quels restes d'entrées de reflog, pointant vers eux, et qui ne sont pas pointés-à par certains commit que does ont une étiquette, ou d'autres pointés-à commit-éventuellement ces commits unreachable (et n'importe quels autres objets unreachable) sont enlevés quand git exécute git gc pour vous automatiquement. Vous pouvez les forcer à être retirés plus tôt, mais il y a rarement une bonne raison de s'en préoccuper.

3 Git lui-même dépend de la garantie. Il est mathématiquement possible, mais extrêmement improbable, que deux objets différents se retrouvent avec le même SHA-1. Si cela se produit, git casse. 4 si la distribution est assez bonne la probabilité est de 1 sur 2 160 , ce qui est vraiment minuscule. C'est une bonne chose que le "paradoxe de L'anniversaire" soulève la possibilité assez rapidement, mais parce qu'il a commencé si minuscule, il reste minuscule et dans la pratique, il n'a jamais été un problème.

4 par conception, le "bris" est que git arrête simplement d'ajouter des objets, de sorte que tout-jusqu'à présent est encore bon. Vous devez ensuite vous déplacer vers n'importe quel nouveau système qui a été conçu pour gérer des milliards de dépôts d'objets., la" nouvelle génération " git ou Je ne sais quoi.

52
répondu torek 2017-05-23 12:02:51

j'ai de bonnes nouvelles et de mauvaises nouvelles pour vous.

la bonne nouvelle, c'est que vous êtes dans l'état que vous exprimez que vous voulez ! Le dernier commit sur master est en effet maintenant dans votre branche, et tout va bien avec l'univers.

La mauvaise nouvelle est que maintenant, avec votre rebase opération, que vous avez déplacé votre branche à l'extrémité de maître, de sorte que la branche de développement est maintenant dans le même état que si vous aviez simplement ramifié à partir de la pointe du maître.

mais c'est [considéré comme] une bonne chose: à condition que vous n'ayez pas eu de conflits de fusion, vous n'avez pas perdu de données dans ce processus, et vous n'avez pas non plus de commit de fusion sans valeur sur votre branche.

le livre fait un excellent travail expliquant ce qu'est un rebase , donc je ne vais pas le répéter. D'après les opérations que vous décrivez, vous n'auriez pas dû perdre de travail.


si vous voulez recréer votre histoire originale avant que vous ne poussiez de force, alors quelqu'un avec une histoire non-tirée peut pousser de force sa branche vers le dépôt à distance. Cela fera que l'état de votre pension sera ce qui était sur leur boîte au moment où ils ont poussé.

3
répondu Makoto 2017-05-23 12:18:14

si vous prenez le hash de commit à partir du refrog (aussi la queue de l'entrée dans un journal git normal) vous pouvez faire réinitialiser --hard COMMIT et puis git push-F origin master qui est habituellement une mauvaise chose . Je recommande de vérifier l'historique complet à un répertoire séparé et propre avant de faire une poussée de force.

-1
répondu Keefe Roedersheimer 2015-09-09 22:49:51