Como é definido o origin / HEAD?

144

Eu tenho um ramo configurado para rastrear uma referência na origem. git checkout <branchname>alterna para esse ramo, e um git statusme mostrará o quão à frente ou atrás do meu ramo é de origem, mas estou surpreso que origin/HEADainda aponte para origin/master, e nãoorigin/<branchname>

Então, minha pergunta é: em que circunstâncias a origem / HEAD é movida?

EDITAR:

Agradeço as respostas sobre como mover a origem / HEAD, mas estou interessado no que "organicamente" a move, fora de mim explicitamente dizendo para fazê-lo.

Por exemplo, quando troco de ramificação, o git faz com que HEAD aponte para a ramificação que estou verificando, então fico surpreso que origem / HEAD não se mova da mesma maneira.

ecoffey
fonte
Observe que esta pergunta é sobre referências simbólicas locais em controles remotos, como refs/origin/HEAD. Não se trata de como a referência simbólica do repositório HEADé definida.
clacke

Respostas:

173

Observe primeiro que sua pergunta mostra um pouco de mal-entendido. origin / HEAD representa o ramo padrão no controle remoto , ou seja, o HEAD que está no repositório remoto que você está chamando de origem. Quando você muda de ramificação no seu repositório, não está afetando isso. O mesmo vale para ramificações remotas; você pode ter mastere origin/masterem seu repositório , onde origin/masterrepresenta uma cópia local da masterramificação no repositório remoto.

O HEAD da origem só mudará se você ou alguém realmente o alterar no repositório remoto , o que basicamente nunca deve acontecer - você deseja que o ramo padrão de um repositório público permaneça constante, no ramo estável (provavelmente mestre). origin / HEAD é uma referência local que representa uma cópia local da HEAD no repositório remoto. (Seu nome completo é refs / remotes / origin / HEAD.)

Eu acho que as respostas acima respondem ao que você realmente queria saber, mas para ir em frente e responder à pergunta que você fez explicitamente ... origin / HEAD é definido automaticamente quando você clona um repositório, e é isso. Estranhamente, que é não definir por comandos como git remote update- Eu acredito que a única maneira que vai mudar é se você alterá-lo manualmente. (Por mudança, quero dizer apontar para um ramo diferente; obviamente, o commit aponta para alterações se esse ramo mudar, o que pode acontecer na busca / retirada / atualização remota.)


Edit : O problema discutido abaixo foi corrigido no Git 1.8.4.3 ; veja esta atualização .


Há uma pequena ressalva, no entanto. HEAD é uma referência simbólica, apontando para uma ramificação em vez de diretamente para uma confirmação, mas os protocolos de transferência remota do git somente confirmam para refs. Portanto, o Git conhece o SHA1 do commit apontado pelo HEAD e todos os outros árbitros; ele deve deduzir o valor de HEAD localizando um ramo que aponte para o mesmo commit. Isso significa que, se dois ramos apontarem para lá, é ambíguo. (Acredito que ele seleciona o mestre, se possível, e volta ao primeiro em ordem alfabética.) Você verá isso relatado na saída de git remote show origin:

$ git remote show origin
* remote origin
  Fetch URL: ...
  Push  URL: ...
  HEAD branch (remote HEAD is ambiguous, may be one of the following):
    foo
    master

Estranhamente, embora a noção de HEAD impressa dessa maneira mude se as coisas mudarem no controle remoto (por exemplo, se o foo for removido), ele não será atualizado refs/remotes/origin/HEAD. Isso pode levar a situações realmente estranhas. Diga que, no exemplo acima, origin / HEAD realmente apontou para foo, e o ramo foo da origem foi removido. Podemos então fazer o seguinte:

$ git remote show origin
...
HEAD branch: master
$ git symbolic-ref refs/remotes/origin/HEAD
refs/remotes/origin/foo
$ git remote update --prune origin
Fetching origin
 x [deleted]         (none)     -> origin/foo
   (refs/remotes/origin/HEAD has become dangling)

Portanto, mesmo que o programa remoto saiba que HEAD é mestre, ele não atualiza nada. O ramo foo obsoleto é podado corretamente e o HEAD fica danificado (apontando para um ramo inexistente), e ainda não o atualiza para apontar para o mestre. Se você deseja corrigir isso, use git remote set-head origin -a, que determina automaticamente o HEAD da origem como acima e, em seguida, defina o origin / HEAD para apontar para o ramo remoto apropriado.

Cascabel
fonte
@jefromi Resposta incrível! Apenas uma observação: você escreve que HEAD é uma referência simbólica, apontando para um ramo em vez de diretamente para um [...] commit , mas vale a pena mencionar "estado HEAD desanexado", para ser completo.
Jb0bs
2
@Jubobs Thanks! No entanto, se minha resposta precisar ser atualizada, fique à vontade para editá-la - certamente economizará tempo para as pessoas lerem um breve resumo de como as coisas realmente funcionam, em vez de precisar analisar o que era verdade há dois anos e o que é verdade agora. .
Cascabel
ter lido este pelo menos 5 vezes e ainda não entendo um pouco dele
krb686
7
git remote set-head origin -afez o trabalho para mim
Shujito 29/05
75

É a sua configuração como proprietário do seu repo local. Altere assim:

git remote set-head origin some_branch

E origin / HEAD apontará para o seu ramo em vez do mestre. Isso se aplicaria apenas ao seu repositório e não a outros. Por padrão, ele apontará para mestre, a menos que algo mais tenha sido configurado no repositório remoto.

A entrada manual para o cabeçote remoto fornece algumas boas informações sobre isso.

Edit: para enfatizar: sem você dizer, a única maneira de "mover" seria um caso como renomear o ramo principal , que eu não acho que seja considerado "orgânico". Então, eu diria organicamente que não se move.

eis
fonte
1
A ênfase da edição não está completamente correta aqui. Também pode mudar se você clonar a partir de uma cópia local que não esteja na ramificação principal.
Mphir
Eu não considero um clone "em movimento", mas acho que podemos discordar disso :)
eis
24

O que move a origem / CABEÇA "organicamente"?

  • git clone define uma vez para o local em que HEAD está na origem
    • serve como o ramo padrão para efetuar o checkout após a clonagem com git clone

O que representa HEAD na origem?

  • em repositórios vazios (geralmente repositórios “em servidores”), ele serve como um marcador para a ramificação padrão, porque a git cloneutiliza de tal maneira
  • em repositórios não vazios (local ou remoto), reflete o checkout atual do repositório

O que define origem / HEAD?

  • git clone busca e define
  • faria sentido se git fetchatualizá-lo como qualquer outra referência, mas não
  • git remote set-head origin -a busca e define
    • útil para atualizar o conhecimento local sobre o que o controle remoto considera "ramificação padrão"

Curiosidades

  • origin/HEAD também pode ser definido para qualquer outro valor sem entrar em contato com o controle remoto: git remote set-head origin <branch>
    • Não vejo nenhum caso de uso para isso, exceto para testes
  • infelizmente nada é capaz de definir HEAD no controle remoto
  • As versões mais antigas do git não sabiam para qual filial o HEAD aponta no controle remoto, apenas qual o hash de confirmação que finalmente possui: portanto, esperamos que apenas escolha um nome de filial apontando para o mesmo hash
Robert Siemer
fonte
Perdi a referência origin/HEADe sua solução ajudou. Obrigado!
Java_dude
Não concordo em git fetchatualizá-lo, pois ele permite configurar um atalho (local). Citando o documento: "Não é necessário ter uma ramificação padrão para um controle remoto, mas permite que o nome do controle remoto seja especificado no lugar de uma ramificação específica". Seria estranho se uma alteração remota atualizasse atalhos configurados localmente.
Micha Wiedenmann
@MichaWiedenmann Por que isso seria um atalho configurado localmente? Para um atalho configurado localmente origin/HEADé um nome ruim. E isso git cloneusa um nome remoto como padrão para uma "ramificação configurada localmente" também contradiz isso. Em repositórios não vazios, nem faz sentido usar a corrente do controle remoto HEAD.
Robert Siemer
10

Isenção de responsabilidade : esta é uma atualização da resposta de Jefromi , que estou escrevendo para poupar algum tempo os curiosos.

Tentei em vão replicar (no Git 2.0.1) a remote HEAD is ambiguousmensagem que Jefromi menciona em sua resposta; então eu pesquisei um pouco (clonando https://github.com/git/git e pesquisando no log). Costumava ser isso

Determining HEAD is ambiguous since it is done by comparing SHA1s.

In the case of multiple matches we return refs/heads/master if it
matches, else we return the first match we encounter. builtin-remote
needs all matches returned to it, so add a flag for it to request such.

(Confirmação 4229f1fa325870d6b24fe2a4c7d2ed5f14c6f771, datada de 27 de fevereiro de 2009, encontrada com git log --reverse --grep="HEAD is ambiguous")

No entanto, a ambiguidade em questão foi levantada desde então :

One long-standing flaw in the pack transfer protocol used by "git
clone" was that there was no way to tell the other end which branch
"HEAD" points at, and the receiving end needed to guess.  A new
capability has been defined in the pack protocol to convey this
information so that cloning from a repository with more than one
branches pointing at the same commit where the HEAD is at now
reliably sets the initial branch in the resulting repository.

(Confirmação 9196a2f8bd46d36a285bdfa03b4540ed3f01f671, 8 de novembro de 2013, encontrada com git log --grep="ambiguous" --grep="HEAD" --all-match)

Editar (graças a torek ):

$ git name-rev --name-only 9196a2f8bd46d36a285bdfa03b4540ed3f01f671
tags/v1.8.4.3~3

Isso significa que, se você estiver usando o Git v1.8.4.3 ou posterior , não deverá encontrar nenhum problema ambíguo-remoto-HEAD.

jub0bs
fonte
1
Com base nas tags na fonte git, essa correção se aplica à versão 1.8.4.3 e posterior do git.
torek
@RobertSiemer Não tenho certeza, mas acho que sim.
Jb0bs
8

Lembre-se de que estamos falando de dois repositórios git independentes. Seu repositório local com seu código e o controle remoto sendo executado em outro lugar.

Você está certo, quando você altera uma ramificação, HEAD aponta para sua ramificação atual. Tudo isso está acontecendo no seu repositório git local. Não o repositório remoto, que poderia pertencer a outro desenvolvedor, ou localização em um servidor no seu escritório, ou github, ou outro diretório no sistema de arquivos, etc.

Seu computador (repositório local) não pode alterar o ponteiro HEAD no repositório remoto do git. Poderia pertencer a um desenvolvedor diferente, por exemplo.

Mais uma coisa, o que o computador chama de origem / XXX é o entendimento do computador sobre o estado do controle remoto no momento da última busca.

Então, o que "organicamente" atualizaria a origem / HEAD? Seria atividade no repositório remoto do git. Não é o seu repo local.

As pessoas mencionaram

git symbolic-ref HEAD refs / head / my_other_branch

Normalmente, isso é usado quando há um repositório git central compartilhado em um servidor para ser usado pela equipe de desenvolvimento. Seria um comando executado no computador remoto. Você veria isso como atividade no repositório remoto do git.

Pablo Maurin
fonte
1
Desculpe, se eu sou um pouco repetitivo. Eu só quero ressaltar o fato de que o git é um sistema de controle de versão distribuído e, como tal, os dois repositórios são independentes.
Pablo Maurin
3

Execute os seguintes comandos no git CLI:

# move to the wanted commit
git reset --hard <commit-hash> 

# update remote
git push --force origin <branch-name> 
Yakir GIladi Edry
fonte
1
Ótimo, foi isso que me ajudou!
Shay Zambrovski