¿Por qué mis referencias/controles remotos/origen no tienen una referencia para dominar?

9 minutos de lectura

En el proceso de explorar el funcionamiento interno de Git, entré al directorio refs/remotes/origin de mi proyecto git y ejecuté el ls mando. Esto es lo que veo.

$ ls
HEAD  sp2013dev

luego corrí cat HEAD y esto es lo que se imprimió.

$ cat HEAD
ref: refs/remotes/origin/master

Sin embargo, no hay ningún archivo o directorio con el nombre de maestro en el directorio refs/remotes/origin. Este directorio solo tiene ‘HEAD’ y ‘sp2013dev’

Me estoy perdiendo de algo ? ¿Por qué HEAD se refiere a algo (por cierto, es ‘ref’ la terminología correcta para este ‘algo’?) que no existe?

avatar de usuario
Torek

Solo para enfatizar: estás hurgando en el interior de git; has encontrado un directorio llamado .git/refs/remotes/origin y contiene dos archivos, HEAD y sp2013dev. Los contenidos de .git/refs/remotes/origin/HEAD están ref: refs/remotes/origin/master.

Una referencia que consta de la cadena literal ref: seguido de otro nombre de referencia es una referencia “simbólica”, en términos de git. Significa “aunque este es un nombre válido, el SHA-1 al que se resuelve esta referencia se encuentra leyendo otra referencia”. Pero, como usted nota, no hay expediente llamado master en el .git/refs/remotes/origin directorio, por lo que se pregunta cómo puede funcionar esto.

La respuesta es que no todas las referencias están necesariamente en archivos. Las referencias pueden estar, y están, “empaquetadas”. Actualmente, las referencias empaquetadas se encuentran en .git/packed-refs, que es un archivo de texto sin formato. Tu propio Git tendrá un refs/remotes/origin/master emparejado con un hash SHA-1 en su .git/packed-refs.

Nota: una referencia puede aparecer tanto en el packed-refs expediente y un archivo en un .git/refs subdirectorio. En este caso, la segunda versión anula la primera. Esto permite git pack-refs (invocado por git gc) para empaquetar todas las referencias y luego permitir que las referencias se “desempaquen” según sea necesario, cuando se actualicen. (Pero este es un detalle de implementación, y se supone que no debes asumir esta; en guiones, utilice git update-ref y git symbolic-ref para leer y actualizar las referencias, y dejar que esos programas hagan cumplir las reglas de actualización).

Actualmente, parece que no existe un formato empaquetado para las referencias simbólicas, por lo que todos viven en “archivos reales” por ahora.

Aparte largo: cómo funciona todo esto (leer solo si es lo suficientemente curioso)

Cuando clona otro repositorio o, para el caso, cada vez que ejecuta git fetch o git pushaunque esos no se ocupan de refs/remotes/origin/HEAD-existen dos repositorios involucrados, con dos conjuntos de reglas aplicadas por dos Gits diferentes que controlan esos dos repositorios. Aparte del comando git remote set-heades sólo git clone que crea el origin/HEAD en primer lugar, para que podamos concentrarnos en git clone sí mismo.

Como hay dos repositorios, vamos a darles nombres. Podemos llamar a su repositorio local L y el depósito en originque está en proceso de clonación, O. Ya que O es un repositorio Git, tiene su propio HEAD. Esta HEAD es normalmente una referencia simbólica: HEAD -> master por ejemplo. Cualquier rama que nombre, sin embargo, es local para O: su refs/heads/branchque es una sucursal local en O. Si tuviera que iniciar sesión en el repositorio de alojamiento de la máquina Oy ver su .git/HEAD archivo, contendría ref: refs/heads/branch. el git en O está haciendo cumplir esta regla, que HEAD siempre nombra un local (local-to-O es decir) sucursal.

Ahora, su propio Git, que se ejecuta localmente en su sistema, está trabajando para crear un repositorio L. tu Git en L quiere crear, en Luna sucursal de seguimiento remoto cuyo nombre completo es refs/remotes/origin/HEAD. Esta será una referencia simbólica, y apuntará a refs/remotes/origin/branch. Pero hay dos complicaciones:

  1. Tu Git, en Ldebe encontrar o averiguar sus Git (en O) simbólico HEAD. En nuestro caso es (su) refs/heads/branch.
  2. Tu Git, en Ldebe entonces crear refs/remotes/origin/branch como una sucursal de seguimiento remoto. (Tu Git almacenará esto en tu .git/packed-refs file.) Tu Git luego crea L‘s refs/remotes/origin/HEAD como una referencia simbólica a refs/remotes/origin/branch.

Algo puede salir mal en cualquiera de estos dos puntos. El paso 2 falla si usa git clone -b otherbranch --single-branch, por ejemplo. Le estás diciendo a tu Git que L no debería tener refs/remotes/origin/branch en absoluto, pero solo refs/remotes/origin/otherbranch. Pero si el paso 2 falla así, tu Git simplemente no crea refs/remotes/origin/HEAD en absoluto. De esa manera no tendrás, en La refs/remotes/origin/HEAD apuntando a la rama de seguimiento remoto inexistente.

El paso 1 “falla” (en cierto modo) si su Git, el edificio Lo su Git, sirviendo O a tu Git, es demasiado viejo. Existe un protocolo definido para buscar nombres de referencia durante estas “llamadas telefónicas” de conexión a Internet que copian confirmaciones (git fetch, git push) y ver nombres de ramas y etiquetas (git ls-remote) y así. los clone El comando utiliza el mismo protocolo definido. Al principio de la conexión, su Git y su Git negocian las opciones de protocolo a usar. Los Gits más antiguos no tienen opción para expresar y resolver una referencia simbólica, por lo que si Git no admite la opción, O solo afirma que O‘s HEAD es una identificación SHA-1 particular. El Git construyendo el clon L tiene que adivinar que rama es en realidad HEAD en O. Lo hace escaneando a través de la descanso de los nombres de rama que obtiene para O. Si O‘s HEAD es 1234567y hay una rama que también es 1234567bueno, eso debe ser donde su HEAD ¡puntos!

Esto puede ser incorrecto, es decir, su Git puede adivinar mal. Pero si es así, su Git simplemente procede con la suposición incorrecta y continúa preocupándose por el paso 2.

El paso 1 puede fallar de manera bastante diferente si su (O‘s) HEAD está separado. En este caso, es posible que no haya una rama coincidente. Si es así, su Git no adivinará mal, solo sabrá que no hay una rama registrada en el repositorio O. Si tanto su Git como su Git no son demasiado antiguos, su Git negociará la opción de protocolo correcta y su Git sabrá con certeza si O tiene una CABEZA desprendida, y si no, en qué rama está desprotegida O.

Es fácil hacer que el paso 2 falle deliberadamente: simplemente clone algún repositorio cuyo HEAD sabes se refiere a alguna rama en particular (como master) mientras usa ambos --single-branch y -b para hacer tu clon L evitar esa rama Es un poco más difícil hacer que el paso 1 falle deliberadamente, pero puede hacerlo iniciando sesión en el sistema que exporta O y separando Ode la CABEZA.

Sin embargo, si hace esto, entonces, de vuelta en su propio sistema, use git clone para hacer Lsimplemente descubres que tu clon L posee no origin/HEAD. Esto mantiene las reglas normales, que incluyen estas tres (no estoy seguro de si hay más):

  1. Todas las referencias ordinarias (no simbólicas) contienen un identificador hash válido.
  2. Todas las referencias simbólicas (con una excepción de caso especial que se detalla a continuación) contienen el nombre de una referencia existente.
  3. La referencia especial HEADque normalmente (pero no siempre) es simbólico, contiene solo una referencia a un local rama, es decir, un nombre en el refs/heads/ espacio de nombres.

La excepción del caso especial es que el nombre de referencia especial HEAD mayo contener el nombre de una sucursal local que aún no existe. Esto (llamado, de diversas maneras, una “rama no nacida” o una “rama huérfana”) es cómo master nace en un repositorio nuevo y vacío: HEAD puntos a master aunque master todavía no existe. Una confirmación que realiza cuando está en este estado hace que la rama comience a existir, apuntando a la confirmación que acaba de realizar; y el compromiso recién hecho tiene no padres, es decir, es una confirmación de raíz.

Podrías pensar que podrías romper estas reglas usando git remote set-headpero de hecho, no te permitirá:

Utilizar <branch> para establecer la referencia simbólica refs/remotes/<name>/HEAD
explícitamente. por ejemplo, “git remote set-head origin master” establecerá la referencia simbólica refs/remotes/origin/HEAD para
refs/remotes/origin/master. Esto solo funcionará si
refs/remotes/origin/master ya existe; si no, debe buscarse primero.

(énfasis mío). Para más información git remote set-headver los git remote documentación.

lata romper estas reglas utilizando el acceso directo a la .git directorio, o con git symbolic-ref. Obviamente, si hurgas dentro .gitpuede arruinar las cosas bastante bien, 🙂 por lo que requiere cuidado. Los bordes afilados con git symbolic-ref son un poco más sorprendentes, pero ahora sabes que también debes tener cuidado con eso.

  • ¿No hay una explicación mucho más simple? Es decir, que el buscado HEAD sobre el origin el control remoto está apuntando a un remoto rama nombrada master que el OP no ha obtenido?

    – jpaugh

    07/02/2017 a las 19:00


  • @jpaugh: No, o al menos no normalmente, porque el HEAD local no puede señalar nada más que un nombre de rama local o una confirmación. (Es posible romper esto escribiendo el archivo usted mismo, pero Git internamente no le permitirá “entrarse” en una rama de seguimiento remoto: obtiene un HEAD separado, con HEAD que contiene una ID de hash sin procesar, en su lugar). es completamente normal para un seguimiento remoto HEAD ser una referencia simbólica a un seguimiento remoto origin/master mientras que el seguimiento remoto origin/master esta empacado.

    – torek

    7 febrero 2017 a las 22:38

  • no estamos hablando de HEAD aquí, pero remotes/origin/HEAD. (Lamento traerlo a un hilo antiguo). Por lo tanto, la segunda parte de su comentario parece confirmar mi sospecha, a saber, que el control remoto HEAD está apuntando a una rama que aún no se ha obtenido localmente, ¿verdad?

    – jpaugh

    10 de febrero de 2017 a las 20:57


  • @jpaugh: Eliminé dos comentarios largos y los reemplacé con este. Sé lo que quieres decir, pero está mal: mira la nueva sección “Largo aparte”. Tenga en cuenta particularmente el “paso 2”: su Git crea origin/HEADpero solo si también crea la rama de seguimiento remoto correspondiente.

    – torek

    11 de febrero de 2017 a las 1:51


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad