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
git rev-parse refs/heads/master
yield 17a02998078923f2d62811326d130de991d1a95a
git rev-parse HEAD
cède également 17a02998078923f2d62811326d130de991d1a95a
Nous avons la refs/heads/master
→ 17a02998078923f2d62811326d130de991d1a95a
refs/heads/master
→ 17a02998078923f2d62811326d130de991d1a95a
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
Nous avons la 17a02998078923f2d62811326d130de991d1a95a
→ 17a02998078923f2d62811326d130de991d1a95a
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:
master
HEAD
nouveau au point que HEAD
divergé de master
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.
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
git checkout master
pour vous remettre dans la twig principale. git checkout -b changes
et git checkout -B master changes
Si vous n’avez pas besoin de vos modifications
Pour supprimer tous les fichiers non suivis de votre twig, exécutez git clean -df
.
Ensuite, vous devez effacer toutes les modifications non planifiées dans votre référentiel. Pour ce faire, vous devez exécuter git checkout --
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
master
, même si elle existe déjà (ce qui revient à déplacer le master
et c’est ce que nous voulons). HEAD
, où vous vous trouvez. 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 .
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é.
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
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