Comment concilier HEAD détaché avec maître / origine?

Je suis nouveau aux complexités de twigment de Git. Je travaille toujours sur une seule twig et valide les modifications, puis envoie périodiquement mon origine distante.

Récemment, j’ai effectué une réinitialisation de certains fichiers pour les sortir de la mise en rebase -i des validations, et plus tard, rebase -i effectué une rebase -i pour éliminer quelques commits locaux récents. Maintenant je suis dans un état que je ne comprends pas bien.

Dans mon espace de travail, git log montre exactement ce à quoi je m’attendais: je suis dans le bon train avec les engagements que je ne voulais pas voir partir, et les nouveaux sur place, etc.

Mais je viens juste de pousser vers le repository distant, et ce qu’il y a de différent – quelques-uns des commits que j’ai tués dans le rebase ont été poussés, et les nouveaux commits localement ne sont pas là.

Je pense que “master / origin” est détaché de HEAD, mais je ne sais pas exactement ce que cela signifie, comment le visualiser avec les outils en ligne de commande et comment le réparer.

Tout d’abord, clarifions ce qu’est HEAD 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é (la situation «normale» 1 : vous avez une twig extraite), HEAD pointe en fait vers la «ref» d’une twig et la twig pointe vers la validation. HEAD est ainsi «attaché» à une twig. Lorsque vous effectuez une nouvelle validation, la twig vers laquelle HEAD pointe est mise à jour pour pointer vers la nouvelle validation. HEAD suit automatiquement car il pointe juste sur la twig.

  • git symbolic-ref HEAD produit refs/heads/master
    La twig nommée “master” est extraite.
  • git rev-parse refs/heads/master yield 17a02998078923f2d62811326d130de991d1a95a
    Ce commit est la pointe ou la «tête» actuelle de la twig principale.
  • git rev-parse HEAD cède également 17a02998078923f2d62811326d130de991d1a95a
    C’est ce que signifie être une «référence symbolique». Il pointe vers un object à travers une autre référence.
    (Les références symboliques étaient à l’origine implémentées en tant que liens symboliques, mais plus tard, elles devenaient des fichiers simples avec une interprétation supplémentaire afin de pouvoir être utilisées sur des plates-formes sans lien symbolique.)

Nous avons la refs/heads/master17a02998078923f2d62811326d130de991d1a95a refs/heads/master17a02998078923f2d62811326d130de991d1a95a

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

  • git symbolic-ref HEAD échoue avec fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEAD donne 17a02998078923f2d62811326d130de991d1a95a
    Comme il ne s’agit pas d’une référence symbolique, il doit pointer directement vers le commit lui-même.

Nous avons la 17a02998078923f2d62811326d130de991d1a95a17a02998078923f2d62811326d130de991d1a95a

La chose importante à retenir avec un HEAD détaché est que si le commit sur lequel il pointe est par ailleurs non référencé (aucun autre ref ne peut l’atteindre), alors il deviendra «en suspens» lorsque vous passerez à un autre commit. Éventuellement, de tels commits seront éliminés lors du processus de récupération de la mémoire (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 reflog de HEAD).

1 Il est parfait de faire un travail «normal» avec une tête détachée, il vous suffit de garder une trace de ce que vous faites pour éviter de devoir jeter un historique hors du reflog.


Les étapes intermédiaires d’un rebase interactif se font avec un HEAD détaché (en partie pour éviter de polluer le reflog de la twig active). Si vous terminez l’opération de rebase complète, votre twig d’origine sera mise à jour avec le résultat cumulatif de l’opération de rebase et réattachera HEAD à la twig d’origine. Je suppose que vous n’avez jamais complètement terminé le processus de rebase; Cela vous laissera un HEAD détaché pointant vers le commit le plus récemment traité par l’opération de rebase.

Pour récupérer de votre situation, vous devez créer une twig qui pointe vers la validation actuellement indiquée 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 twig temp .

Ensuite, vous devez comparer le commit actuel (et son historique) avec la twig 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 tester les options du journal: append -p , laisser --pretty=… pour voir le message entier du journal, etc.)

Si votre nouvelle twig temp semble bonne, vous pouvez 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 twig temporaire:

 git branch -d temp 

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

 git push origin master 

Vous devrez peut-être append --force à la fin de cette commande pour pousser si la twig distante ne peut pas être «transférée rapidement» vers le nouveau commit (c.-à-d. ).

Si vous étiez au milieu d’une opération de rebase, vous devriez probablement la nettoyer. Vous pouvez vérifier si une rebase était en cours en recherchant le répertoire .git/rebase-merge/ . Vous pouvez nettoyer manuellement le rebase en cours en supprimant simplement ce répertoire (par exemple, si vous ne vous souvenez plus du but et du contexte de l’opération de rebase active). Habituellement, vous utiliseriez git rebase --abort , mais cela git rebase --abort une réinitialisation supplémentaire que vous souhaiterez probablement éviter (il ramène HEAD dans la twig d’origine et le remet à la validation d’origine, ce qui annulera une partie du travail effectué ci-dessus). ).

Faites ceci:

 git checkout master 

Ou, si vous souhaitez conserver des modifications, procédez comme suit:

 git checkout -b temp git checkout -B master temp 

Je suis tombé sur ce problème et quand j’ai lu dans le top voté réponse:

HEAD est le nom symbolique du commit actuellement extrait.

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

 git rebase HEAD master 

Cette commande:

  1. vérifie le master
  2. identifie le parent engage de HEAD nouveau au point que HEAD divergé de master
  3. joue ces commits au dessus du master

Le résultat final est que tous les commits qui étaient dans HEAD mais pas master sont aussi dans master . master rest extrait.


En ce qui concerne la télécommande:

quelques-uns des commits que j’ai tués lors de la rebase ont été poussés, et les nouveaux commis localement ne sont pas là.

L’historique distant ne peut plus être transmis rapidement à l’aide de votre historique local. Vous devez forcer ( git push -f ) pour écraser l’historique distant. Si vous avez des collaborateurs, il est généralement judicieux de les coordonner avec eux pour que tout le monde soit sur la même page.

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

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 une git checkout somecommit etc., et cela vous aurait prévenu de ce qui suit:

Vous êtes en état détaché. Vous pouvez regarder autour de vous, apporter des modifications expérimentales et les valider, et vous pouvez ignorer les commits que vous effectuez dans cet état sans affecter les twigs en effectuant une autre extraction.

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

git checkout -b nouveau_nom_branch

Maintenant, pour les mettre en maître:

Faire un git reflog ou même simplement git log et noter vos commits. Maintenant, git checkout master et git merge les commits.

 git merge HEAD@{1} 

Modifier:

Pour append, 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 puis émettre un git rebase --continue à avancer. Cela aurait assuré que vous ne soyez jamais entré dans une tête détachée.

Faites en sorte que votre détachement s’engage sur sa propre twig

git checkout -b mynewbranch simplement git checkout -b mynewbranch .

Ensuite, lancez git log , et vous verrez que commit est maintenant HEAD sur cette nouvelle twig.

Si vous venez de maîsortingser une twig et que vous voulez revenir à “développer” ou à une fonctionnalité, faites ceci:

 git checkout origin/develop 

Note: vérification de l’ origine / développement .

Vous êtes en état détaché HEAD . Vous pouvez regarder autour de vous, apporter des modifications expérimentales et les valider, et vous pouvez ignorer les commits que vous faites dans cet état sans affecter les twigs en effectuant une autre vérification …

puis

 git checkout -b develop 

Ça marche 🙂

Si vous voulez pousser votre HEAD détaché actuel (vérifiez le git log avant), essayez:

 git push origin HEAD:master 

d’envoyer votre HEAD détaché dans la twig maîtresse à l’origine. Si votre demande est rejetée, essayez d’abord d’ git pull origin master pour obtenir les modifications d’origine. Si vous ne vous souciez pas des modifications d’origine et que celles-ci sont rejetées, parce que vous avez effectué un rebasage intentionnel et que vous souhaitez remplacer l’origine / maître par votre twig actuellement détachée, vous pouvez le forcer ( -f ). Si vous avez perdu un access aux commits précédents, vous pouvez toujours lancer git reflog pour voir l’historique de toutes les twigs.


Pour revenir sur une twig principale, tout en conservant les modifications, essayez les commandes suivantes:

 git rebase HEAD master git checkout master 

Voir: Git: “Pas actuellement sur une twig.” Existe-t-il un moyen simple de revenir sur une succursale tout en conservant les modifications?

Les éléments suivants ont fonctionné pour moi (en utilisant uniquement le maître de twig):

 git push origin HEAD:master git checkout master git pull 

Le premier pousse le HEAD détaché à l’origine distante.

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

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

Des problèmes peuvent survenir lors de la première commande si le rejet est rejeté. Mais ce ne serait plus un problème de tête détachée, mais plutôt le fait que le HEAD détaché n’a pas connaissance de certains changements à distance.

Si vous êtes tout à fait 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 êtes sur une twig technique que personne d’autre n’utilise.

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

Ainsi, par exemple, dans la twig ‘dev’, vous cochez la commande asdfasd14314 ->

 'git checkout asdfasd14314' 

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

‘git branch’ listera 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’ listera ->

 * dev prod stage 

mais c’est bien sûr si vous n’avez pas l’intention de conserver les changements par rapport à l’état de tête détaché, mais je me trouve souvent en train de le faire, sans avoir à faire de changements, mais simplement à regarder un engagement précédent.

Comme l’a souligné Chris, j’ai eu la situation suivante

git symbolic-ref HEAD échoue avec fatal: ref HEAD is not a symbolic ref

Cependant, git rev-parse refs/heads/master indiquait une bonne validation à partir de laquelle je pourrais récupérer (dans mon cas, la dernière validation et vous pouvez voir que la validation se fait en utilisant git show [SHA]

J’ai fait beaucoup de choses désordonnées après cela, mais ce qui semble avoir été corrigé est juste,

git symbolic-ref HEAD refs/heads/master

Et la tête est attachée!

Je viens de rencontrer ce problème aujourd’hui et je suis presque certain de l’avoir résolu en:

 git branch temp git checkout master git merge temp 

J’étais sur mon ordinateur de travail quand j’ai compris comment faire, et maintenant je rencontre le même problème sur mon ordinateur personnel. Il faudra donc attendre lundi que je suis de retour à l’ordinateur de travail pour voir exactement comment je l’ai fait.

J’ai eu le même problème et je l’ai résolu en suivant les étapes suivantes.

Si vous devez conserver vos modifications

  1. Vous devez d’abord exécuter la git checkout master pour vous remettre dans la twig principale.
  2. Si vous devez conserver vos modifications, lancez simplement git checkout -b changes et git checkout -B master changes

Si vous n’avez pas besoin de vos modifications

  1. Pour supprimer tous les fichiers non suivis de votre twig, exécutez git clean -df .

  2. Ensuite, vous devez effacer toutes les modifications non planifiées dans votre référentiel. Pour ce faire, vous devez exécuter git checkout --

  3. Enfin, vous devez remettre votre twig dans la twig principale en utilisant la git checkout master .

J’ai eu ce problème aujourd’hui, où j’avais mis à jour un sous-module, mais je n’étais sur aucune twig. Je m’étais déjà engagé, alors le fait de se cacher, de passer à la caisse, de se désengager ne fonctionnerait pas. Je me suis retrouvé à cueillir la tête de la mission détachée. Donc, immédiatement après que j’ai commis (quand la poussée a échoué), j’ai fait:

 git checkout master git cherry-pick 99fe23ab 

Je pensais: je suis détaché, mais je veux être maître. En supposant que mon état détaché ne soit pas très différent de celui de maître, si je pouvais appliquer mon engagement au maître, je serais prêt. C’est exactement ce que fait le choix des cerises.

Au lieu de faire l’ git checkout origin/master

il suffit de faire git checkout master

alors git branch confirmera votre twig.

Si vous vous êtes engagé sur le master et que vous souhaitez simplement “fusionner” le master (c.-à-d. Que vous voulez que le master pointe vers HEAD ), le one-liner serait:

 git checkout -B master HEAD 
  1. Cela crée une nouvelle twig nommée master , même si elle existe déjà (ce qui revient à déplacer le master et c’est ce que nous voulons).
  2. La twig nouvellement créée est définie pour pointer sur HEAD , où vous vous trouvez.
  3. La nouvelle twig est extraite, vous êtes donc master après.

J’ai trouvé cela particulièrement utile dans le cas des sous-répertoires, qui se trouvent également souvent dans un état détaché.

Pour moi, c’était aussi simple que de supprimer la twig locale, car je n’avais pas de commits locaux que je voulais lancer:

Donc j’ai fait:

 git branch -d branchname 

Et puis en vérifiant à nouveau la twig:

 git checkout branchname 

En termes simples, l’état HEAD détaché signifie que vous n’êtes pas extrait de HEAD (ou tip) d’une twig .

Comprendre avec un exemple

Une twig dans la plupart des cas est une séquence de plusieurs commits comme:

Commit 1: master -> branch_HEAD (123be6a76168aca712aea16076e971c23835f8ca)

Commit 2: master -> 123be6a76168aca712aea16076e971c23835f8ca -> branch_HEAD (100644a76168aca712aea16076e971c23835f8ca)

Comme vous pouvez le voir ci-dessus en cas de séquence de commits, votre twig pointe vers votre dernier commit. Donc, dans ce cas, si vous validez pour valider 123be6a76168aca712aea16076e971c23835f8ca, vous êtes en état détaché puisque HEAD de votre twig pointe vers 100644a76168aca712aea16076e971c23835f8ca et que techniquement vous êtes extrait de HEAD sans succursale. Par conséquent, vous êtes dans l’état HEAD détaché.

Explication théorique

Dans ce blog, il est clairement indiqué qu’un repository Git est une arborescence de commits, chaque validation pointant vers son ancêtre avec chaque pointeur de validation est mise à jour et ces pointeurs vers chaque twig sont stockés dans les sous-répertoires .git / refs. Les tags sont stockés dans des fichiers .git / refs / tags et les twigs sont stockées dans .git / refs / heads. Si vous regardez l’un des fichiers, vous verrez que chaque tag correspond à un fichier unique, avec un hash de commit de 40 caractères et comme expliqué ci-dessus par @Chris Johnsen et @Yaroslav Nikitenko, vous pouvez consulter ces références.

Je suis entré dans un état vraiment idiot, je doute que quelqu’un d’autre trouvera cela utile… mais juste au cas où

 git ls-remote origin 0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b HEAD 6f96ad0f97ee832ee16007d865aac9af847c1ef6 refs/heads/HEAD 0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b refs/heads/master 

que j’ai finalement fixé avec

 git push origin :HEAD 

Cela a fonctionné pour moi parfaitement:

1. git stash pour enregistrer vos modifications locales

Si vous souhaitez ignorer les modifications
git clean -df
git checkout -- .
git clean supprime tous les fichiers non suivis (attention: s’il ne supprime pas les fichiers ignorés mentionnés directement dans .gitignore, il peut supprimer les fichiers ignorés résidant dans les dossiers) et git checkout supprime tous les changements non planifiés.

2. git checkout master pour passer à la twig principale (en supposant que vous voulez utiliser master)
3. git pull pour tirer le dernier commit de la twig master
4. git status pour vérifier que tout a l’air génial

 On branch master Your branch is up-to-date with 'origin/master'. 

Lorsque je me trouve personnellement dans une situation où il s’est avéré que j’ai fait des changements alors que je ne suis pas en master ( HEAD est détaché juste au-dessus du master et qu’il n’y a pas de commits entre-temps)

 git stash # HEAD has same content as master, but we are still not in master git checkout master # switch to master, okay because no changes and master git stash apply # apply changes we had between HEAD and master in the first place 

Dans mon cas, j’ai exécuté le git status , et j’ai vu que j’avais quelques fichiers non suivis dans mon répertoire de travail.

Pour que le rebase fonctionne, je devais simplement les nettoyer (car je n’en avais pas besoin).

Si vous utilisez EGit dans Eclipse: supposez que votre maître est votre principale twig de développement

  • vous engagez à modifier une twig, normalement une nouvelle
  • puis tirez de la télécommande
  • puis faites un clic droit sur le nœud du projet, choisissez une équipe, puis choisissez l’historique du spectacle
  • puis cliquez avec le bouton droit sur le maître, choisissez la caisse
  • si Eclipse vous le dit, il y a deux maîtres un local, choisissez la télécommande

Après cela, vous devriez pouvoir vous rattacher au maître d’origine.

 git checkout checksum # You could use this to peek previous checkpoints git status # You will see HEAD detached at checksum git checkout master # This moves HEAD to master branch