Eu sou novo nas complexidades ramificadas do Git. Eu sempre trabalho em uma única ramificação, confirmo alterações e, em seguida, periodicamente envio à minha origem remota.
Em algum lugar recentemente, fiz uma redefinição de alguns arquivos para tirá-los do teste de consolidação e, mais tarde, resolvi rebase -i
me livrar de algumas confirmações locais recentes. Agora estou em um estado que não entendo direito.
Na minha área de trabalho, git log
mostra exatamente o que eu esperaria - estou no trem certo, com os commits que não queria, e os novos por aí, etc.
Mas acabei de enviar para o repositório remoto e o que há de diferente: alguns dos commits que eu matei no rebase foram enviados e os novos confirmados localmente não estão lá.
Eu acho que "mestre / origem" está separado do HEAD, mas não sou 100% claro sobre o que isso significa, como visualizá-lo com as ferramentas de linha de comando e como corrigi-lo.
I did a reset of some files to get them out of commit staging
parte? pesaroso para as perguntas :)Respostas:
Primeiro, vamos esclarecer o que é HEAD e o que significa quando é desanexado.
HEAD é o nome simbólico para a confirmação de saída no momento. Quando o HEAD não é desanexado (a situação "normal" 1 : você tem uma ramificação com check-out), o HEAD na verdade aponta para o "ref" de um ramo e o ramo aponta para o commit. HEAD é, portanto, "anexado" a um ramo. Quando você faz uma nova confirmação, o ramo que aponta para HEAD é atualizado para apontar para a nova confirmação. HEAD segue automaticamente, uma vez que apenas aponta para o ramo.
git symbolic-ref HEAD
rendimentosrefs/heads/master
O ramo chamado "mestre" é retirado.
git rev-parse refs/heads/master
yield17a02998078923f2d62811326d130de991d1a95a
Esse commit é a dica ou "cabeça" atual do ramo mestre.
git rev-parse HEAD
também produz17a02998078923f2d62811326d130de991d1a95a
Isto é o que significa ser uma "referência simbólica". Aponta para um objeto através de alguma outra referência.
(As referências simbólicas foram originalmente implementadas como links simbólicos, mas posteriormente foram alteradas para arquivos simples com interpretação extra, para que pudessem ser usados em plataformas que não possuem links simbólicos.)
Temos
HEAD
→refs/heads/master
→17a02998078923f2d62811326d130de991d1a95a
Quando o HEAD é desanexado, ele aponta diretamente para um commit - em vez de apontar indiretamente para um através de um branch. Você pode pensar em um HEAD desanexado como estando em um ramo sem nome.
git symbolic-ref HEAD
falha comfatal: ref HEAD is not a symbolic ref
git rev-parse HEAD
yields17a02998078923f2d62811326d130de991d1a95a
Como não é uma referência simbólica, deve apontar diretamente para o próprio commit.
Temos
HEAD
→17a02998078923f2d62811326d130de991d1a95a
O importante a lembrar com um HEAD desanexado é que, se o commit apontado não for referenciado (nenhum outro árbitro pode alcançá-lo), ele ficará "dangling" quando você fizer o checkout de outro commit. Eventualmente, essas confirmações pendentes serão removidas pelo processo de coleta de lixo (por padrão, elas são mantidas por pelo menos 2 semanas e podem ser mantidas por mais tempo, sendo referenciadas pelo reflog da HEAD).
1 É perfeitamente bom fazer um trabalho “normal” com um HEAD separado, basta acompanhar o que você está fazendo para evitar ter que pescar o histórico abandonado do reflog.
As etapas intermediárias de um rebase interativo são realizadas com um HEAD desanexado (parcialmente para evitar poluir o reflog do ramo ativo). Se você concluir a operação de rebase completa, ele atualizará sua ramificação original com o resultado cumulativo da operação de rebase e reconectará HEAD à ramificação original. Meu palpite é que você nunca concluiu completamente o processo de rebase; isso deixará você com um HEAD desanexado apontando para o commit que foi processado mais recentemente pela operação de rebase.
Para se recuperar da sua situação, você deve criar um ramo que aponte para o commit atualmente apontado pelo seu HEAD desanexado:
(esses dois comandos podem ser abreviados como
git checkout -b temp
)Isso conectará novamente seu HEAD ao novo
temp
ramo.Em seguida, você deve comparar o commit atual (e seu histórico) com o branch normal no qual você esperava estar trabalhando:
(Provavelmente, você desejará experimentar as opções de log: adicione
-p
, deixe--pretty=…
para ver toda a mensagem de log etc.)Se o seu novo
temp
ramo parecer bom, convém atualizar (por exemplo)master
para apontar para ele:(esses dois comandos podem ser abreviados como
git checkout -B master temp
)Você pode excluir a ramificação temporária:
Por fim, você provavelmente desejará enviar o histórico restabelecido:
Você pode precisar adicionar
--force
ao final deste comando para enviar por push se a ramificação remota não puder ser "encaminhada rapidamente" para a nova confirmação (ou seja, você eliminou ou reescreveu alguma confirmação existente ou, de outra forma, reescreveu um pouco do histórico).Se você estava no meio de uma operação de rebase, provavelmente deveria limpá-la. Você pode verificar se uma rebase estava em processo procurando o diretório
.git/rebase-merge/
. Você pode limpar manualmente o rebase em andamento apenas excluindo esse diretório (por exemplo, se você não se lembrar mais da finalidade e do contexto da operação de rebase ativa). Geralmente você usariagit rebase --abort
, mas isso faz algumas redefinições extras que você provavelmente deseja evitar (ele move o HEAD de volta para o ramo original e o redefine para o commit original, o que desfará parte do trabalho que fizemos acima).fonte
man git-symbolic-ref
: "No passado,.git/HEAD
havia um link simbólico apontandorefs/heads/master
. Quando queríamos mudar para outro ramo, o fizemosln -sf refs/heads/newbranch .git/HEAD
e quando queríamos descobrir em qual ramo estamos, o fizemosreadlink .git/HEAD
. Mas os links simbólicos não são totalmente portáteis , agora eles estão obsoletos e as referências simbólicas (conforme descrito acima) são usadas por padrão ".git branch -f master HEAD && git checkout master
é suficiente - supondo que seu objetivo seja manter a cabeça atual, mas designá-la comomaster
. Outros objetivos também fazem sentido e exigem outras receitas.Apenas faça o seguinte:
Ou, se você tiver alterações que deseja manter, faça o seguinte:
fonte
git reset
deve vir com um aviso "Se você não tem ideia do que está fazendo, pare". Acabei de me recuperar de uma hora de terror pensando que eu tinha perdido a última semana de trabalho. Obrigado!Encontrei esta questão e quando li a resposta votada no topo:
Eu pensei: Ah-ha! Se
HEAD
é o nome simbólico do commit atual do checkout, posso reconciliá-lo emaster
rebatizá-lo contramaster
:Este comando:
master
HEAD
volta ao pontoHEAD
divergente demaster
master
O resultado final é que todas as confirmações que estavam,
HEAD
mas nãomaster
estão, também estãomaster
.master
permanece em check-out.Em relação ao controle remoto:
O histórico remoto não pode mais ser avançado rapidamente usando o histórico local. Você precisará pressionar (
git push -f
) para sobrescrever o histórico remoto. Se você tem algum colaborador, geralmente faz sentido coordenar isso com eles, para que todos estejam na mesma página.Depois de enviar
master
para remotoorigin
, sua ramificação de rastreamento remotoorigin/master
será atualizada para apontar para o mesmo commit quemaster
.fonte
git reflog
e redefina seu ramo para aquele commit comgit rest —hard $commit
Procure aqui uma explicação básica da cabeça separada:
http://git-scm.com/docs/git-checkout
Linha de comando para visualizá-lo:
ou
você obterá saída como abaixo:
Os
* (no branch)
shows que você está com a cabeça desapegada.Você poderia ter chegado a esse estado fazendo um
git checkout somecommit
etc. e isso o alertaria com o seguinte:Agora, para colocá-los no master:
Faça um
git reflog
ou mesmo apenasgit log
e anote seus commits. Agoragit checkout master
egit merge
os commits.Editar:
Para adicionar, use
git rebase -i
não apenas para excluir / eliminar confirmações que você não precisa, mas também para editá-las. Apenas mencione "edit" na lista de confirmação e você poderá alterar seu commit e, em seguida, emitir umgit rebase --continue
para prosseguir. Isso garantiria que você nunca chegasse a uma CABEÇA desapegada.fonte
Coloque seu commit desanexado em seu próprio ramo
Simplesmente corra
git checkout -b mynewbranch
.Em seguida
git log
, execute e você verá que o commit está agoraHEAD
neste novo ramo.fonte
mynewbranch
anexa a alguma coisa?se você acabou de dominar o ramo e deseja voltar a "desenvolver" ou um recurso, faça o seguinte:
Nota: verificando a origem / desenvolvimento .
Você está no estado HEAD desanexado . Você pode olhar ao redor, fazer alterações experimentais e confirmá-las, e pode descartar quaisquer confirmações feitas nesse estado sem impactar nenhuma ramificação executando outro checkout ...
então
Funciona :)
fonte
Se você deseja enviar seu HEAD desanexado atual (verifique
git log
antes), tente:para enviar seu HEAD desanexado para a ramificação principal na origem. Se o seu envio for rejeitado, tente
git pull origin master
primeiro obter as alterações de origem. Se você não se importa com as alterações de origem e elas são rejeitadas, porque você fez uma nova recuperação intencional e deseja substituir a origem / mestre pela sua ramificação desanexada no momento - você pode forçá-la (-f
). Caso você tenha perdido algum acesso às confirmações anteriores, sempre poderá executargit reflog
para ver o histórico de todas as ramificações.Para voltar a uma ramificação principal, mantendo as alterações, tente os seguintes comandos:
Veja: Git: "Atualmente não está em nenhum ramo." Existe uma maneira fácil de voltar a um ramo, mantendo as alterações?
fonte
Encontrei esta pergunta ao pesquisar
You are in 'detached HEAD' state.
Depois de analisar o que havia feito para chegar aqui, em comparação com o que havia feito no passado, descobri que havia cometido um erro.
Meu fluxo normal é:
Desta vez eu fiz:
O problema é que acidentalmente fiz:
Ao invés de:
A correção (na minha situação) era simplesmente executar o comando acima e continuar o fluxo:
fonte
O seguinte funcionou para mim (usando apenas o mestre da filial):
O primeiro empurra o HEAD desanexado para uma origem remota.
O segundo se move para o mestre da filial.
O terceiro recupera o HEAD que fica anexado ao mestre de ramificação.
Podem surgir problemas no primeiro comando se o envio for rejeitado. Mas isso não seria mais um problema de cabeça desanexada, mas é sobre o fato de que o HEAD desanexado não está ciente de algumas mudanças remotas.
fonte
Acabei de encontrar este problema hoje e tenho certeza de que o resolvi fazendo:
Eu estava no meu computador de trabalho quando descobri como fazer isso e agora estou enfrentando o mesmo problema no meu computador pessoal. Portanto, terei que esperar até segunda-feira, quando voltar ao computador do trabalho para ver exatamente como o fiz.
fonte
Se você tem certeza absoluta de que HEAD é o bom estado:
Você provavelmente não pode avançar para a origem, pois seu mestre divergiu da origem. Se tiver certeza de que mais ninguém está usando o repositório, você pode forçar:
Mais útil se você estiver em um ramo de recurso que ninguém mais está usando.
fonte
Tudo o que você precisa fazer é 'git checkout [branch-name]', onde [branch-name] é o nome da ramificação original da qual você entrou em um estado principal desanexado. O (desanexado do asdfasdf) desaparecerá.
Por exemplo, no ramo 'dev', você faz o checkout do commit asdfasd14314 ->
agora você está em um estado principal desanexado
'git branch' listará algo como ->
mas para sair do estado principal desanexado e voltar ao dev ->
e então 'git branch' listará ->
mas é claro que se você não pretende manter alterações do estado principal desanexado, mas eu me vejo fazendo isso muito, não pretendendo fazer alterações, mas apenas olhando para uma confirmação anterior
fonte
Como apontado por Chris, eu tive a seguinte situação
git symbolic-ref HEAD
falha comfatal: ref HEAD is not a symbolic ref
No entanto,
git rev-parse refs/heads/master
estava apontando para uma boa confirmação de onde eu poderia me recuperar (no meu último caso, você pode ver essa confirmação usandogit show [SHA]
Eu fiz muitas coisas bagunçadas depois disso, mas o que parece ter corrigido é apenas,
git symbolic-ref HEAD refs/heads/master
E a cabeça está presa!
fonte
Em vez de fazer
git checkout origin/master
apenas faça
git checkout master
então
git branch
confirmará sua filial.fonte
Eu tive esse problema hoje, onde atualizei um submódulo, mas não estava em nenhum ramo. Eu já havia cometido, então esconder, fazer check-out, descartar não funcionaria. Acabei escolhendo o commit da cabeça destacada. Então, imediatamente após eu confirmar (quando o push falhou), eu fiz:
Meu pensamento foi: estou com uma cabeça desapegada, mas quero estar no mestre. Supondo que meu estado desanexado não seja muito diferente do mestre, se eu pudesse aplicar meu commit ao mestre, seria definido. É exatamente isso que a escolha da cereja faz.
fonte
Se você fez alguns commits em cima do master e apenas deseja "mesclar para trás"
master
lá (ou seja, você desejamaster
apontar paraHEAD
), o one-liner seria:master
, mesmo que já exista (que é como se movermaster
e é isso que queremos).HEAD
, que é onde você está.master
continue depois.Achei isso especialmente útil no caso de sub-repositórios, que também acontecem frequentemente em um estado desanexado.
fonte
Eu tive o mesmo problema e o resolvi seguindo as etapas a seguir.
Se você precisar manter suas alterações
git checkout master
comando para voltar ao ramo principal.git checkout -b changes
egit checkout -B master changes
Se você não precisar de suas alterações
Para remover todos os arquivos não rastreados da sua ramificação, execute
git clean -df
.Então você precisa limpar todas as alterações não-estágios no seu repositório. Para fazer isso, você precisa executar
git checkout --
Finalmente, você deve colocar seu ramo de volta no ramo mestre usando o
git checkout master
comandofonte
Para mim, foi tão fácil quanto excluir a ramificação local novamente, já que eu não tinha nenhum commit local que queria enviar:
Então eu fiz:
E depois verificando a ramificação novamente:
fonte
Quando eu me encontro pessoalmente em uma situação em que eu fiz algumas alterações enquanto não estou
master
(ouHEAD
seja, desanexado logo acimamaster
e sem compromissos), o armazenamento pode ajudar:fonte
Em palavras simples, o estado HEAD desanexado significa que você não recebeu o check-in do HEAD (ou dica) de nenhum ramo .
Entenda com um exemplo
Uma ramificação na maioria dos casos é uma sequência de vários commits como:
Confirmação 1: master -> branch_HEAD (123be6a76168aca712aea16076e971c23835f8ca)
Confirmação 2: mestre -> 123be6a76168aca712aea16076e971c23835f8ca -> branch_HEAD (100644a76168aca712aea16076e971c23835f8ca)
Como você pode ver acima, no caso de sequência de confirmações, sua ramificação aponta para o último commit. Portanto, nesse caso, se você fizer o checkout para confirmar 123be6a76168aca712aea16076e971c23835f8ca , você estará no estado principal desanexado, pois HEAD do seu ramo aponta para 100644a76168aca712aea16076e971c23835f8ca e, tecnicamente, é verificado no HEAD de nenhum ramo. Portanto, você está no estado HEAD desanexado.
Explicação teórica
Neste Blog , é claro que um repositório Git é uma árvore de consolidação, com cada confirmação apontando para seu ancestral, com cada ponteiro de confirmação atualizado e esses ponteiros para cada ramificação são armazenados nos subdiretórios .git / refs. As tags são armazenadas em .git / refs / tags e as ramificações são armazenadas em .git / refs / heads. Se você olhar para qualquer um dos arquivos, verá que cada tag corresponde a um único arquivo, com um hash de confirmação de 40 caracteres e, conforme explicado acima por @Chris Johnsen e @Yaroslav Nikitenko, você pode conferir essas referências.
fonte
Entrei em um estado realmente bobo, duvido que alguém ache isso útil .... mas apenas no caso
que eu eventualmente consertei
fonte
Isso funcionou para mim perfeitamente:
1.
git stash
para salvar suas modificações locaisSe você deseja descartar as alterações, o
git clean -df
git checkout -- .
git clean remove todos os arquivos não rastreados (aviso: embora não exclua os arquivos ignorados mencionados diretamente em .gitignore, ele pode excluir os arquivos ignorados que residem nas pastas) e o git checkout limpa todas as alterações não apresentadas.
2.
git checkout master
para mudar para o ramo principal (supondo que você queira usar o mestre)3.
git pull
para extrair o último commit do ramo mestre4.
git status
para verificar se tudo está ótimofonte
No meu caso, eu corri
git status
e vi que havia alguns arquivos não rastreados no meu diretório de trabalho.Para fazer o rebase funcionar, eu apenas precisei limpá-los (já que não precisava deles).
fonte
Se você estiver usando o EGit no Eclipse: assuma que seu mestre é seu ramo de desenvolvimento principal
Após isso, você poderá reconectar ao mestre de origem.
fonte
Eu tive o mesmo problema. Eu escondi minhas alterações
git stash
e redefinii a ramificação no local para um commit anterior (eu pensei que isso causou), então fiz umgit pull
e não estou conseguindo desanexar agora. Não se esqueçagit stash apply
de ter suas alterações novamente.fonte
fonte