Je suis nouveau à la complexité des branches de Git. Je travaille toujours sur une seule branche et valide les modifications, puis répète périodiquement la transmission à mon origine distante.
Quelque part, récemment, j'ai réinitialisé certains fichiers pour les sortir de la mise en place des validations. Plus tard, j'ai fait un rebase -i
pour supprimer deux ou trois commits locaux récents. Maintenant, je suis dans un état que je ne comprends pas très bien.
Dans mon espace de travail, git log
montre exactement ce à quoi je m'attendais - je suis dans le bon train avec les commits que je ne voulais pas, et les nouveaux là-bas, etc.
Mais j'ai juste poussé vers le référentiel distant, et ce qui existe est différent - deux commits que j'ai tués dans la base ont été poussés, et les nouveaux commis localement ne sont pas là.
Je pense que "maître/origine" est détaché de HEAD, mais je ne suis pas tout à fait sûr de ce que cela signifie, comment le visualiser avec les outils de ligne de commande et comment le corriger.
Tout 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 paramètre “normal”1 situation: vous avez une branche extraite), HEAD pointe en fait sur le “ref” d’une branche et la branche pointe vers le commit. HEAD est donc "attaché" à une branche. Lorsque vous effectuez une nouvelle validation, la branche vers laquelle HEAD pointe est mise à jour pour pointer vers la nouvelle validation. HEAD suit automatiquement puisqu'il pointe juste sur la branche.
git symbolic-ref HEAD
_ donne _refs/heads/master
_git rev-parse refs/heads/master
_ rendement _17a02998078923f2d62811326d130de991d1a95a
_git rev-parse HEAD
_ donne également _17a02998078923f2d62811326d130de991d1a95a
_Nous avons HEAD
→ _refs/heads/master
_ → _17a02998078923f2d62811326d130de991d1a95a
_
Lorsque HEAD est détaché, il pointe directement vers un commit, au lieu de pointer indirectement vers un commit à travers une branche. Vous pouvez imaginer un détaché HEAD sur une branche non nommée.
git symbolic-ref HEAD
_ échoue avec _fatal: ref HEAD is not a symbolic ref
_git rev-parse HEAD
_ donne _17a02998078923f2d62811326d130de991d1a95a
_Nous avons HEAD
→ _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é (aucune autre référence ne peut l'atteindre), alors il deviendra "suspendu" lorsque vous extrayerez un autre commit. À terme, ces commits pendants seront supprimés via le processus de récupération de place (par défaut, ils sont conservés pendant au moins deux semaines et peuvent être conservés plus longtemps en étant référencés par le préfog de HEAD).
1 C’est parfaitement bien de faire un travail "normal" avec un HEAD détaché, il vous suffit de garder une trace de ce que vous faites pour éviter d’avoir à pêcher l’histoire laissée de côté.
Les étapes intermédiaires d’une rebase interactive 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 refonte complète, il mettra à jour votre branche d'origine avec le résultat cumulatif de l'opération de refonte et rattachera HEAD à la branche d'origine. J'imagine que vous n'avez jamais complètement terminé le processus de rebase; cela vous laissera avec un HEAD détaché qui pointe vers le commit qui a été le plus récemment traité par l'opération de rebase.
Pour sortir de votre situation, vous devez créer une branche qui pointe vers le commit actuellement indiqué 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 rattachera votre HEAD à la nouvelle branche temp
.
Ensuite, vous devriez comparer le commit actuel (et son historique) avec la branche normale sur laquelle vous espériez 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: ajoutez _-p
_, laissez _--pretty=…
_ pour voir le message complet du journal, etc.)
Si votre nouvelle branche temp
semble bonne, vous pouvez mettre à jour (par exemple) master
pour y pointer:
_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'historique rétabli:
_git Push Origin master
_
Vous devrez peut-être ajouter _--force
_ à la fin de cette commande en Push si la branche distante ne peut pas être "renvoyée rapidement" vers le nouveau commit (c’est-à-dire que vous avez supprimé, réécrit un commit existant, ou autrement, un bit de l'histoire).
Si vous êtes au milieu d’une opération de rebasement, vous devriez probablement le nettoyer. Vous pouvez vérifier si une base était en cours en recherchant le répertoire _.git/rebase-merge/
_. Vous pouvez nettoyer manuellement la base en cours en supprimant simplement ce répertoire (par exemple, si vous ne vous souvenez plus de l'objectif et du contexte de l'opération de base active). Habituellement, vous utiliseriez _git rebase --abort
_, mais cela réinitialisera de manière supplémentaire ce que vous voudrez probablement éviter (cela ramènera HEAD dans la branche d'origine et le réinitialisera à la livraison initiale, ce qui annulera certaines modifications. du travail que nous avons fait ci-dessus).
Faites juste ceci:
git checkout master
Ou, si vous souhaitez conserver des modifications, procédez comme suit:
git checkout -b temp
git checkout -B master temp
J'ai rencontré ce problème et quand j'ai lu dans la réponse votée en haut:
HEAD est le nom symbolique du commit actuellement extrait.
J'ai pensé: ah-ha! Si HEAD
est le nom symbolique de la validation actuelle, je peux le réconcilier avec master
en le rebasonnant contre master
:
git rebase HEAD master
Cette commande:
master
HEAD
vers le point HEAD
divergé de master
master
Le résultat final est que tous les commits qui étaient dans HEAD
mais pas master
sont alors aussi dans master
. master
reste extrait.
En ce qui concerne la télécommande:
quelques commits que j'avais tués dans la base ont été poussés, et les nouveaux commis localement ne sont pas là.
L'historique distant ne peut plus être transféré rapidement à l'aide de votre historique local. Vous aurez besoin de forcer Push (git Push -f
) pour écraser l'historique à distance. Si vous avez des collaborateurs, il est généralement logique de coordonner cela avec eux pour que tout le monde soit sur la même page.
Après avoir poussé master
vers la télécommande Origin
, votre branche de suivi à distance Origin/master
sera mise à jour pour indiquer le même commit que 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)
indique que vous êtes en tête détachée.
Vous auriez pu arriver à cet état en faisant un git checkout somecommit
etc., qui vous aurait averti de ce qui suit:
Vous êtes dans l'état 'détaché HEAD'. Vous pouvez regarder autour de vous, apporter des modifications expérimentales et les valider. Vous pouvez également supprimer les commits que vous avez effectués dans cet état sans affecter les branches en effectuant une autre vérification.
Si vous souhaitez créer une nouvelle branche 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 new_branch_name
Maintenant, pour les amener sur le maître:
Faites un git reflog
ou même simplement git log
et notez vos commits. Maintenant, git checkout master
et git merge
les validations.
git merge HEAD@{1}
Modifier:
Pour ajouter, utilisez git rebase -i
non seulement pour supprimer/supprimer les commits dont vous n’avez pas besoin, mais également pour les éditer. Il vous suffit de mentionner "edit" dans la liste de validation pour pouvoir modifier votre commit, puis émettre un git rebase --continue
pour continuer. Cela aurait fait en sorte que vous ne veniez jamais dans une tête détachée.
Il suffit de lancer git checkout -b mynewbranch
.
Puis exécutez git log
et vous verrez que la validation est maintenant HEAD
sur cette nouvelle branche.
si vous venez de maitriser la branche et que vous voulez revenir à "développer" ou à une fonctionnalité, procédez comme suit:
git checkout Origin/develop
Remarque: vérification Origin/develop.
Vous êtes dans l'état HEAD détaché. Vous pouvez regarder autour de vous, faire des modifications expérimentales et les valider, et vous pouvez supprimer tous les commits que vous avez effectués dans cet état sans affecter les branches en effectuant une autre vérification ...
ensuite
git checkout -b develop
Ça marche :)
Si vous voulez pousser votre détachement actuel HEAD (vérifiez git log
avant), essayez:
git Push Origin HEAD:master
envoyer votre HEAD détaché dans la branche principale d’Origin. Si votre diffusion est rejetée, essayez d’abord git pull Origin master
pour obtenir les modifications depuis Origin. Si vous ne vous souciez pas des modifications apportées par Origin et que celles-ci sont rejetées, car vous avez modifié intentionnellement votre base et que vous souhaitez remplacer Origin/master par votre branche actuellement isolée, vous pouvez le forcer (-f
). Au cas où vous perdriez un accès aux validations précédentes, vous pouvez toujours exécuter git reflog
pour voir l'historique de toutes les branches.
Pour revenir sur une branche principale tout en conservant les modifications, essayez les commandes suivantes:
git rebase HEAD master
git checkout master
Je viens de rencontrer ce problème aujourd'hui et je suis sûr de l'avoir résolu en procédant comme suit:
git branch temp
git checkout master
git merge temp
J'étais sur mon ordinateur de travail quand j'ai compris comment faire cela, et maintenant je rencontre le même problème sur mon ordinateur personnel. Il faudra donc attendre lundi, quand je serai de retour à l'ordinateur de travail, pour voir exactement comment je l'ai fait.
Ce qui suit a fonctionné pour moi (en utilisant uniquement le maître de branche):
git Push Origin HEAD:master
git checkout master
git pull
Le premier pousse le détaché HEAD vers l'Origine distant.
Le second passe au maître de branche.
Le troisième récupère le HEAD qui devient attaché au maître de branche.
Des problèmes peuvent survenir lors de la première commande si le Push est rejeté. Mais cela ne serait plus un problème de tête détachée, mais plutôt le fait que le détaché HEAD ne soit pas au courant de certains changements distants.
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 vers Origin, car votre maître s’est écarté d’Origin. Si vous êtes certain que personne n'utilise le référentiel, vous pouvez forcer:
git Push -f
Le plus utile si vous êtes sur une branche de fonctionnalité que personne d'autre n'utilise.
J'ai trouvé cette question lors de la recherche de You are in 'detached HEAD' state.
Après avoir analysé ce que j'avais fait pour arriver ici, par rapport à ce que j'avais fait dans le passé, j'ai découvert que j'avais commis une erreur.
Mon flux normal est:
git checkout master
git fetch
git checkout my-cool-branch
git pull
Cette fois j'ai fait:
git checkout master
git fetch
git checkout Origin/my-cool-branch
# You are in 'detached HEAD' state.
Le problème est que j'ai accidentellement fait:
git checkout Origin/my-cool-branch
Plutôt que:
git checkout my-cool-branch
Le correctif (dans ma situation) consistait simplement à exécuter la commande ci-dessus, puis à poursuivre le flux:
git checkout my-cool-branch
git pull
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ée. Le (détaché de asdfasdf) va disparaître.
Ainsi, par exemple, dans la branche "dev", vous extrayez le commit asdfasd14314 ->
'git checkout asdfasd14314'
vous êtes maintenant dans un état de tête détachée
'git branch' listera quelque chose comme ->
* (detached from asdfasdf)
dev
prod
stage
mais pour sortir de l'état de tête détachée et revenir à dev ->
'git checkout dev'
puis 'git branch' listera ->
* dev
prod
stage
mais c’est bien sûr si vous n’avez pas l’intention de garder les changements de l’état de la tête détachée, mais je me trouve souvent en train de le faire.
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 un bon commit d'où je pouvais récupérer (dans mon cas, le dernier commit et vous pouvez le voir en utilisant git show [SHA]
J'ai fait beaucoup de choses en désordre après cela, mais ce qui semble avoir été corrigé est juste,
git symbolic-ref HEAD refs/heads/master
Et la tête est re attachée!
J'ai eu ce problème aujourd'hui, où j'avais mis à jour un sous-module, mais pas sur une branche. J'avais déjà commis, donc dissimulation, caisse, dépose ne fonctionnait pas. J'ai fini par choisir le pion de la tête détachée. Donc tout de suite après que j'ai commis (quand la poussée a échoué), j'ai fait:
git checkout master
git cherry-pick 99fe23ab
Ma pensée est allé: je suis sur une tête détachée, mais je veux être sur le maître. En supposant que mon état détaché ne soit pas très différent de maître, si je pouvais appliquer mon engagement à maître, je serais réglé. C'est exactement ce que fait cherry-pick.
Au lieu de faire git checkout Origin/master
il suffit de faire git checkout master
alors git branch
confirmera votre succursale.
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 ramener à la branche principale.git checkout -b changes
et git checkout -B master changes
Si vous n'avez pas besoin de vos changements
Pour supprimer tous les fichiers non suivis de votre branche, exécutez git clean -df
.
Ensuite, vous devez effacer toutes les modifications non mises en scène dans votre référentiel. Pour ce faire, vous devez exécuter git checkout --
Enfin, vous devez remettre votre branche dans la branche principale en utilisant la commande git checkout master
.
Pour moi, cela a été aussi simple que de supprimer à nouveau la branche locale, car je n'avais pas d'engagement local que je veuille pousser:
Alors j'ai fait:
git branch -d branchname
Et puis vérifiant à nouveau la branche:
git checkout branchname
Si vous avez fait des commits en plus du maître et que vous voulez juste "fusionner en arrière" master
ici (c’est-à-dire que vous voulez que master
pointe sur HEAD
), le une ligne serait:
git checkout -B master HEAD
master
, même si elle existe déjà (ce qui revient à déplacer 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-dépôts, qui se trouvent également assez souvent dans un état isolé.
Lorsque je me trouve personnellement dans une situation où il s'avère que j'ai apporté des modifications alors que je ne suis pas dans master
(c.-à-d. HEAD
est détaché juste au-dessus de master
et il n'y a pas de commits dans entre) peut aider:
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
En termes simples, l'état HEAD détaché signifie que vous n'êtes pas extrait de HEAD (ou de la pointe) d'une branche .
Une branche dans la plupart des cas est une séquence de commits multiples 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 validations, votre branche pointe sur votre dernier validateur. Donc, dans ce cas, si vous passez à la caisse 123be6a76168aca712aea16076e971c23835f8ca alors vous seriez dans l’état de la tête détachée puisque HEAD de votre branche pointe sur 100644a76168aca712aea16076e971c23835f8ca à HEAD d'aucune branche. Par conséquent, vous êtes dans l'état détaché HEAD.
Dans ce blog il est clairement indiqué qu'un référentiel Git est une arborescence de validations, chaque validation pointant vers son ancêtre avec chaque pointeur de validation est mise à jour et ces pointeurs vers chaque branche sont stockés dans le fichier .git/refs sous-répertoires. Les balises sont stockées dans .git/refs/tags et les branches sont stockées dans .git/refs/head. Si vous examinez l'un des fichiers, vous constaterez que chaque balise correspond à un fichier unique, avec un hachage de validation de 40 caractères et, comme expliqué ci-dessus par @Chris Johnsen et @Yaroslav Nikitenko, vous pouvez consulter ces références.
Cela a fonctionné pour moi parfaitement:
1 .git stash
pour sauvegarder vos modifications locales
Si vous souhaitez ignorer les modificationsgit clean -df
git checkout -- .
git clean supprime tous les fichiers non suivis (avertissement: s'il ne supprime pas les fichiers ignorés mentionnés directement dans .gitignore, il peut supprimer les fichiers ignorés résidant dans des dossiers) et git checkout efface toutes les modifications non mises en scène.
2 .git checkout master
pour basculer vers la branche principale (en supposant que vous souhaitiez utiliser le maître)
3 .git pull
extraire le dernier commit de la branche master
4 .git status
afin de tout vérifier
On branch master
Your branch is up-to-date with 'Origin/master'.
Dans mon cas, j'ai exécuté git status
et j'ai constaté que j'avais quelques fichiers non suivis dans mon répertoire de travail.
Pour que le rebase fonctionne, il me suffisait de les nettoyer (car je n'en avais pas besoin).
Je suis tombé dans un état vraiment stupide, je doute que quelqu'un d'autre trouve 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
Si vous utilisez EGit dans Eclipse: supposez que votre maître est votre branche de développement principale
Après cela, vous devriez pouvoir vous reconnecter au maître d’origine.