Question Comment puis-je réconcilier TÊTE détachée avec maître / origine?


Je suis nouveau dans les complexités embranchées de Git. Je travaille toujours sur une seule branche et je valide les changements, puis j'appuie régulièrement sur mon origine distante.

Quelque part récemment, j'ai fait une réinitialisation de certains fichiers pour les sortir de la mise en scène de validation, et plus tard a fait un rebase -i se débarrasser de quelques commits locaux récents. Maintenant, je suis dans un état que je ne comprends pas très bien.

Dans ma zone de travail, git log montre exactement ce que j'attendrais-- je suis sur le bon train avec les commits je ne voulais pas allé, et les nouveaux là, etc.

Mais j'ai juste poussé vers le dépôt distant, et ce qui est là est différent - un certain nombre de commits que j'ai tué dans la rebase a été poussé, et les nouveaux commis localement ne sont pas là.

Je pense que "master / origin" est détaché de HEAD, mais je ne suis pas sûr à 100% de ce que cela signifie, comment le visualiser avec les outils en ligne de commande, et comment le réparer.


1274
2018-04-24 17:51


origine


Réponses:


D'abord, clarifions ce que HEAD est et ce que cela signifie quand il est détaché.

HEAD est le nom symbolique du commit actuellement extrait. Lorsque HEAD n'est pas détaché (le "normal"1 situation: vous avez une branche extraite), HEAD pointe en fait sur "ref" d'une branche et la branche pointe sur le commit. HEAD est ainsi "attaché" à une branche. Lorsque vous effectuez une nouvelle validation, la branche sur laquelle pointe HEAD est mise à jour pour pointer vers la nouvelle validation. HEAD suit automatiquement puisqu'il pointe juste vers la branche.

  • git symbolic-ref HEAD rendements refs/heads/master
    La branche nommée "master" est extraite.
  • git rev-parse refs/heads/master rendement 17a02998078923f2d62811326d130de991d1a95a
    Ce commit est l'astuce actuelle ou "tête" de la branche master.
  • git rev-parse HEAD rendements également 17a02998078923f2d62811326d130de991d1a95a
    C'est ce que signifie être un «ref symbolique». Il pointe vers un objet à travers une autre référence.
    (Les références symboliques ont été implémentées à l'origine en tant que liens symboliques, mais ont ensuite été remplacées par des fichiers simples avec une interprétation supplémentaire afin de pouvoir être utilisés sur des plates-formes qui ne possèdent pas de lien symbolique.)

Nous avons HEAD → refs/heads/master → 17a02998078923f2d62811326d130de991d1a95a

Lorsque HEAD est détaché, il pointe directement sur un commit au lieu de pointer indirectement sur un via une branche. Vous pouvez penser à une tête détachée comme étant sur une branche sans nom.

  • git symbolic-ref HEAD échoue avec fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEAD rendements 17a02998078923f2d62811326d130de991d1a95a
    Puisque ce n'est pas un ref symbolique, il doit pointer directement sur le commit lui-même.

Nous avons HEAD → 17a02998078923f2d62811326d130de991d1a95a

La chose importante à retenir avec un HEAD détaché est que si le commit pointé vers est autrement non référencé (aucun autre ref ne peut l'atteindre), alors il deviendra "balancé" quand vous extrayez un autre commit. Finalement, ces commits pendants seront élagués à travers le processus de collecte des ordures (par défaut, ils sont conservés pendant au moins 2 semaines et peuvent être conservés plus longtemps en étant référencés par le refog de HEAD).

1 Il est parfaitement possible de faire un travail "normal" avec un HEAD détaché, il vous suffit de suivre ce que vous faites pour éviter d'avoir à passer au fil de l'histoire.


Les étapes intermédiaires d'un rebasage interactif sont effectuées avec un HEAD détaché (partiellement pour éviter de polluer le reflog de la branche active). Si vous terminez l'opération de rebasage complète, elle mettra à jour votre branche d'origine avec le résultat cumulé de l'opération de rebasage et rattachera HEAD à la branche d'origine. Je suppose que vous n'avez jamais complètement terminé le processus de rebasage; cela vous laissera avec un HEAD détaché pointant vers le commit qui a été le plus récemment traité par l'opération de rebasage.

Pour récupérer de votre situation, vous devez créer une branche qui pointe vers le commit actuellement pointé par votre HEAD détaché:

git branch temp
git checkout temp

(Ces deux commandes peuvent être abrégées en git checkout -b temp)

Cela va rattacher votre HEAD à la nouvelle temp branche.

Ensuite, vous devez comparer la validation actuelle (et son historique) avec la branche normale sur laquelle vous vous attendiez à travailler:

git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp

(Vous voudrez probablement expérimenter avec les options du journal: ajouter -p, pars --pretty=… pour voir le message complet, etc.)

Si votre nouveau temp la branche semble bonne, vous pouvez vouloir mettre à jour (par exemple) master pour le désigner:

git branch -f master temp
git checkout master

(Ces deux commandes peuvent être abrégées en git checkout -B master temp)

Vous pouvez ensuite supprimer la branche temporaire:

git branch -d temp

Enfin, vous voudrez probablement pousser l'histoire rétablie:

git push origin master

Vous devrez peut-être ajouter --force à la fin de cette commande pour pousser si la branche distante ne peut pas être "avancée" vers le nouveau commit (c'est-à-dire que vous avez laissé tomber, réécrire un commit existant, ou réécrire un peu d'historique).

Si vous étiez au milieu d'une opération de rebasage, vous devriez probablement le nettoyer. Vous pouvez vérifier si un rebasage était en cours en recherchant le répertoire .git/rebase-merge/. Vous pouvez nettoyer manuellement le rebase en cours en supprimant ce répertoire (par exemple, si vous ne vous souvenez plus du but et du contexte de l'opération de rebasage actif). Habituellement, vous utiliseriez git rebase --abort, mais cela fait une réinitialisation supplémentaire que vous voudrez probablement éviter (elle renvoie HEAD à la branche d'origine et la réinitialise à la validation d'origine, ce qui annulera une partie du travail que nous avons fait ci-dessus).


2160
2018-04-24 19:56



Fais juste ceci:

git checkout master

Ou, si vous avez des changements que vous voulez garder, faites ceci:

git checkout -b temp
git checkout -B master temp

512
2017-09-18 07:23



Je suis tombé sur cette question et quand j'ai lu dans la première réponse votée:

HEAD est le nom symbolique du commit actuellement extrait.

J'ai pensé: Ah-ha! Si HEAD est le nom symbolique de la validation en cours, je peux la réconcilier avec master en le rebasant contre master:

git rebase HEAD master

Cette commande:

  1. vérifie master
  2. identifie les commits parents de HEAD retour au point HEAD divergé de master
  3. joue ces commits au-dessus de master

Le résultat final est que tous les commits qui étaient dans HEAD mais non master sont alors également dans master. master reste vérifié.


En ce qui concerne la télécommande:

un couple des commits que j'avais tués dans le rebase a été poussé, et les nouveaux commis localement ne sont pas là.

L'historique distant ne peut plus être transmis rapidement en utilisant votre historique local. Vous devrez pousser-pousser (git push -f) pour remplacer l'historique distant. Si vous avez des collaborateurs, il est généralement logique de les coordonner avec eux pour que tout le monde soit sur la même page.

Après avoir poussé master enlever origin, votre branche de suivi à distance origin/master sera mis à jour pour pointer vers le même commit que master.


97
2017-08-02 03:10



Regardez ici pour l'explication de base de la tête détachée:

http://git-scm.com/docs/git-checkout

Ligne de commande pour le visualiser:

git branch

ou

git branch -a

vous obtiendrez une sortie comme ci-dessous:

* (no branch)
master
branch1

le * (no branch) montre que vous êtes en tête détachée.

Vous auriez pu venir à cet état en faisant un git checkout somecommit etc. et il vous aurait averti avec ce qui suit:

Vous êtes dans l'état "TÊTE détachée". Toi   peut regarder autour, faire expérimental   changements et les commettre, et vous pouvez   rejeter tous les commits que vous faites dans ce   état sans impact sur les branches   en effectuant une autre vérification.

Si vous voulez créer une nouvelle branche   conserver les commits que vous créez, vous pouvez le faire   donc (maintenant ou plus tard) en utilisant -b avec le   commande de sortie à nouveau. Exemple:

git checkout -b nouveau_nom_branch

Maintenant, pour les amener sur le maître:

Fait une git reflog ou même juste git log et notez vos commits. À présent git checkout master et git merge les commits.

git merge HEAD@{1}

Modifier:

Pour ajouter, utilisez git rebase -i non seulement pour supprimer / tuer les commits dont vous n'avez pas besoin, mais aussi pour les éditer. Il suffit de mentionner "edit" dans la liste de validation et vous pourrez modifier votre commit et ensuite émettre un git rebase --continue aller de l'avant. Cela aurait garanti que vous n'entriez jamais dans une tête détachée.


78
2018-04-24 18:41



Obtenez votre engagement détaché sur sa propre branche

Simplement courir git checkout -b mynewbranch.

Ensuite, courez git log, et vous verrez que commettre est maintenant HEAD sur cette nouvelle branche.


29
2018-05-20 02:44



Si vous avez juste une branche master et que vous voulez revenir à "développer" ou une fonctionnalité, faites ceci:

git checkout origin/develop

Note: vérifier origine / développer.

Tu es dans TETE détachée Etat. Vous pouvez regarder autour de vous, faire des expériences change et les commet, et vous pouvez rejeter tous les commits que vous faites dans ce état sans impact sur les branches en effectuant une autre commande ...

puis

git checkout -b develop

Ça marche :)


18
2017-11-08 13:24



Si vous voulez pousser votre TETE détachée actuelle (vérifiez git log avant), essayez:

git push origin HEAD:master

envoyer votre TÊTE détachée dans la branche maîtresse à l'origine. Si votre poussée est rejetée, essayez git pull origin master d'abord pour obtenir les changements de l'origine. Si vous ne vous souciez pas des changements depuis l'origine et qu'ils sont rejetés, parce que vous avez fait un rebasement intentionnel et que vous voulez remplacer origin / master par votre branche actuellement détachée - alors vous pouvez le forcer (-f). Au cas où vous perdiez un accès aux commits précédents, vous pouvez toujours exécuter git reflog pour voir l'histoire de toutes les branches.


Pour revenir à une branche principale, tout en conservant les modifications, essayez les commandes suivantes:

git rebase HEAD master
git checkout master

Voir: Git: "Pas actuellement sur une branche." Y at-il un moyen facile de revenir sur une succursale, tout en gardant les changements?


16
2017-09-17 20:35



Si vous êtes complètement sûr que HEAD est le bon état:

git branch -f master HEAD
git checkout master

Vous ne pouvez probablement pas pousser à l'origine, puisque votre maître a divergé de l'origine. Si vous êtes sûr que personne d'autre n'utilise le repo, vous pouvez forcer:

git push -f

Plus utile si vous utilisez une branche d'entités que personne d'autre n'utilise.


7
2018-03-01 09:31



Ce qui suit a fonctionné pour moi (en utilisant seulement le maître de la succursale):

git push origin HEAD:master
git checkout master        
git pull

Le premier pousse la TETE détachée vers l'origine distante.

Le second se déplace vers le maître de la branche.

Le troisième récupère la tête qui devient attachée au maître de la branche.

Des problèmes peuvent survenir lors de la première commande si la poussée est rejetée. Mais ce ne serait plus un problème de tête détachée, mais c'est le fait que le détaché HEAD n'a pas conscience de quelques changements lointains.


7
2018-01-07 12:13



Tout ce que vous avez à faire est 'git checkout [nom de la branche]' où [nom de la branche] est le nom de la branche d'origine à partir de laquelle vous êtes entré dans un état de tête détaché. Le (détaché de asdfasdf) disparaîtra.

Ainsi, par exemple, dans la branche «dev», vous pouvez récupérer le commit asdfasd14314 ->

'git checkout asdfasd14314'

vous êtes maintenant dans un état de tête détaché

'git branch' va lister quelque chose comme ->

* (detached from asdfasdf)
  dev
  prod
  stage

mais pour sortir de l'état de tête détaché et revenir à dev ->

'git checkout dev'

et ensuite 'git branch' va lister ->

* dev
  prod
  stage

mais c'est bien sûr si vous n'avez pas l'intention de garder les changements de l'état de tête détaché, mais je me retrouve à faire cela beaucoup pas l'intention de faire des changements, mais juste pour regarder un commit précédent


4
2017-10-17 19:49