¿Cómo se configura el origen / HEAD?

144

Tengo una sucursal configurada para rastrear una referencia en origen. git checkout <branchname>cambia a esa rama, y ​​un git statusme mostrará qué tan adelante o detrás de mi rama es de origen, pero me sorprende que origin/HEADtodavía apunte a origin/master, y noorigin/<branchname>

Entonces mi pregunta es, ¿bajo qué circunstancias se mueve origen / CABEZA?

EDITAR:

Aprecio las respuestas sobre cómo mover origen / CABEZA, pero estoy interesado en lo que lo mueve "orgánicamente", fuera de mí diciéndome explícitamente que lo haga.

Por ejemplo, cuando cambio ramas, git hace que HEAD apunte a la rama que estoy revisando, así que me sorprende que el origen / HEAD no se mueva de la misma manera.

ecoffey
fuente
Tenga en cuenta que esta pregunta trata sobre referencias simbólicas locales en controles remotos, como refs/origin/HEAD. No se trata de cómo HEADse establece la referencia simbólica de un repositorio .
clacke

Respuestas:

173

Tenga en cuenta primero que su pregunta muestra un poco de malentendido. origin / HEAD representa la rama predeterminada en el control remoto , es decir, el HEAD que está en ese repositorio remoto al que está llamando origen. Cuando cambias ramas en tu repositorio, no estás afectando eso. Lo mismo es cierto para las ramas remotas; es posible que tenga mastery origin/masteren su repositorio, donde origin/masterrepresenta una copia local de la masterrama en el repositorio remoto.

HEAD de origen solo cambiará si usted u otra persona realmente lo cambia en el repositorio remoto , lo que básicamente nunca debería suceder: desea que la rama predeterminada un repositorio público permanezca constante, en la rama estable (probablemente maestra). origin / HEAD es una referencia local que representa una copia local de HEAD en el repositorio remoto. (Su nombre completo es refs / remotes / origin / HEAD).

Creo que lo anterior responde a lo que realmente quería saber, pero para seguir adelante y responder la pregunta que hizo explícitamente ... origin / HEAD se configura automáticamente cuando clona un repositorio, y eso es todo. Curiosamente, que está no mediante comandos como git remote update- Creo que la única forma en que va a cambiar es si cambia manualmente. (Por cambio me refiero a apuntar a una rama diferente; obviamente, la confirmación apunta a cambios si esa rama cambia, lo que podría suceder en la búsqueda / extracción / actualización remota).


Editar : El problema discutido a continuación se corrigió en Git 1.8.4.3 ; ver esta actualización .


Sin embargo, hay una pequeña advertencia. HEAD es una referencia simbólica, que apunta a una rama en lugar de directamente a una confirmación, pero los protocolos de transferencia remota de git solo informan confirmaciones para las referencias. Entonces Git conoce el SHA1 del commit señalado por HEAD y todas las demás referencias; luego tiene que deducir el valor de HEAD encontrando una rama que apunte al mismo commit. Esto significa que si dos ramas apuntan allí, es ambiguo. (Creo que elige maestro si es posible, luego vuelve a alfabéticamente primero). Verá esto informado en la salida 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

Curiosamente, aunque la noción de HEAD impresa de esta manera cambiará si las cosas cambian en el control remoto (por ejemplo, si se elimina foo), en realidad no se actualiza refs/remotes/origin/HEAD. Esto puede conducir a situaciones realmente extrañas. Digamos que en el ejemplo anterior origin / HEAD en realidad apuntaba a foo, y luego se quitó la rama foo de origen. Entonces podemos hacer esto:

$ 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)

Entonces, aunque el programa remoto sabe que HEAD es maestro, no actualiza nada. La rama viciada se poda correctamente, y HEAD se cuelga (apuntando a una rama inexistente), y aún no se actualiza para señalar al maestro. Si desea arreglar esto, use git remote set-head origin -a, que determina automáticamente el HEAD del origen como se indica arriba, y luego establece el origen / HEAD para que apunte a la rama remota apropiada.

Cascabel
fuente
@jefromi ¡Impresionante respuesta! Solo una observación: usted escribe que HEAD es una referencia simbólica, apuntando a una rama en lugar de directamente a un commit, [...] pero podría valer la pena mencionar "estado HEAD separado", para completar.
jub0bs
2
@Jubobs ¡Gracias! Sin embargo, si necesita actualizar mi respuesta, simplemente edítela, sin duda, le ahorrará tiempo a la gente leer un breve resumen de cómo funcionan realmente las cosas, en lugar de tener que clasificar lo que era cierto hace dos años y lo que es cierto ahora. .
Cascabel
he leído esto al menos 5 veces y todavía no entiendo un poco
krb686
77
git remote set-head origin -ahizo el trabajo por mí
Shujito
75

Es su configuración como propietario de su repositorio local. Cámbialo así:

git remote set-head origin some_branch

Y origin / HEAD apuntará a su rama en lugar de master. Esto se aplicaría solo a su repositorio y no a otros. Por defecto, apuntará a maestro, a menos que se haya configurado algo más en el repositorio remoto.

La entrada manual para el set-head remoto proporciona buena información al respecto.

Editar: para enfatizar: sin que se lo digas, la única forma en que se "movería" sería un caso como el cambio de nombre de la rama maestra , que no creo que se considere "orgánico". Entonces, yo diría orgánicamente que no se mueve.

eis
fuente
1
El énfasis de edición no es completamente correcto aquí. También puede cambiar si clona desde una copia local que no está en la rama maestra.
mphair
No me considero un clon "en movimiento", pero creo que podemos estar de acuerdo en que :)
EIS
24

¿Qué mueve origen / CABEZA "orgánicamente"?

  • git clone lo establece una vez en el lugar donde está HEAD en origen
    • sirve como la rama predeterminada para pagar después de la clonación con git clone

¿Qué representa HEAD en origen?

  • en repositorios desnudos (a menudo repositorios "en servidores") sirve como un marcador para la rama predeterminada, porque lo git cloneusa de tal manera
  • en repositorios no desnudos (locales o remotos), refleja la comprobación actual del repositorio

¿Qué establece origen / CABEZA?

  • git clone busca y lo establece
  • Tendría sentido si lo git fetchactualiza como cualquier otra referencia, pero no
  • git remote set-head origin -a busca y lo establece
    • útil para actualizar el conocimiento local de lo que el control remoto considera la "rama predeterminada"

Trivialidades

  • origin/HEAD También se puede establecer en cualquier otro valor sin contactar con el control remoto: git remote set-head origin <branch>
    • No veo ningún caso de uso para esto, excepto para las pruebas
  • desafortunadamente, nada es capaz de configurar HEAD en el control remoto
  • las versiones anteriores de git no sabían a qué rama HEAD apunta en el control remoto, solo qué commit hash finalmente tiene: por lo que es de esperar que solo haya elegido un nombre de rama que apunta al mismo hash
Robert Siemer
fuente
Había perdido referencias origin/HEADy su solución ayudó. ¡Gracias!
java_dude
No estoy de acuerdo con git fetchactualizarlo, ya que permite configurar un acceso directo (local). Citando el documento: "No es necesario tener una rama predeterminada para un control remoto, pero permite que se especifique el nombre del control remoto en lugar de una rama específica". Sería extraño que un cambio remoto actualizara los accesos directos configurados localmente.
Micha Wiedenmann
@MichaWiedenmann ¿Por qué sería un acceso directo configurado localmente? Para un acceso directo configurado localmente origin/HEADes un mal nombre. Y eso que git cloneusa un nombre remoto como predeterminado para una "rama configurada localmente" también lo contradice. En repositorios no desnudos, ni siquiera tiene sentido usar la corriente remota HEAD.
Robert Siemer
10

Descargo de responsabilidad : esta es una actualización de la respuesta de Jefromi , que estoy escribiendo para salvar a los curiosos algún tiempo.

Intenté en vano replicar (en Git 2.0.1) el remote HEAD is ambiguousmensaje que Jefromi menciona en su respuesta; así que hice un poco de excavación (clonando https://github.com/git/git y buscando en el registro). Solía ​​ser eso

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.

(Commit 4229f1fa325870d6b24fe2a4c7d2ed5f14c6f771, de fecha 27 de febrero de 2009, encontrado con git log --reverse --grep="HEAD is ambiguous")

Sin embargo, la ambigüedad en cuestión se ha eliminado desde entonces :

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.

(Commit 9196a2f8bd46d36a285bdfa03b4540ed3f01f671, con fecha del 8 de noviembre de 2013, encontrado con git log --grep="ambiguous" --grep="HEAD" --all-match)

Editar (gracias a torek ):

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

Esto significa que, si está utilizando Git v1.8.4.3 o posterior , no debería encontrarse con ningún problema ambiguo-remoto-HEAD.

jub0bs
fuente
1
Según las etiquetas en la fuente de git, esta corrección se aplica a la versión de git 1.8.4.3 y posterior.
torek
@RobertSiemer No estoy seguro, pero creo que sí.
jub0bs
8

Recuerde que hay dos repositorios de git independientes de los que estamos hablando. Su repositorio local con su código y el control remoto ejecutándose en otro lugar.

Tienes razón, cuando cambias una rama, HEAD apunta a tu rama actual. Todo esto está sucediendo en su repositorio local de git. No el repositorio remoto, que podría ser propiedad de otro desarrollador, o ubicarse en un servidor en su oficina, o github, u otro directorio en el sistema de archivos, o etc.

Su computadora (repositorio local) no tiene por qué cambiar el puntero HEAD en el repositorio git remoto. Podría ser propiedad de un desarrollador diferente, por ejemplo.

Una cosa más, lo que su computadora llama origen / XXX es su comprensión del estado del control remoto en el momento de la última búsqueda.

Entonces, ¿qué actualizaría "orgánicamente" origen / CABEZA? Sería actividad en el repositorio remoto de git. No es tu repositorio local.

La gente ha mencionado

git symbolic-ref HEAD refs / head / my_other_branch

Normalmente, eso se usa cuando hay un repositorio central compartido de git en un servidor para uso del equipo de desarrollo. Sería un comando ejecutado en la computadora remota. Vería esto como actividad en el repositorio remoto de git.

Pablo Maurin
fuente
1
Lo siento, si soy un poco repetitivo. Solo quiero señalar el hecho de que git es un sistema de control de versiones distribuido y, como tal, los dos repositorios son independientes.
Pablo Maurin
3

Ejecute los siguientes comandos desde git CLI:

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

# update remote
git push --force origin <branch-name> 
Yakir GIladi Edry
fuente
1
¡Genial, eso es lo que me ayudó!
Shay Zambrovski