¿Qué debo hacer en un server para asegurarme de que un repository de Git al principio desnudo actualiza el directory de trabajo cuando lo presiono?

En la máquina remota:

  1. mkdir mlcode.git && cd mlcode.git && git init --bare
  2. Cree un file post-receive en ~/mlcode.git/hooks contenga

     #!/bin/sh GIT_WORK_TREE=/home/ubuntu/mlcode export GIT_WORK_TREE git checkout -f 
  3. chmod +x ~/mlcode.git/hooks/post-receive
  4. mkdir mlcode

Luego, en la máquina local configuré la máquina remota como un repository y lo presioné. Esto parece funcionar (el repository remoto se actualiza como se esperaba, las búsquedas lo confirman, etc.). Pero nada está desprotegido.

Después de experimentar, parece que necesito un paso adicional después (¿después de presionar primero?) En el server donde creo explícitamente la twig y la comprobo con algo como

 GIT_WORK_TREE=/home/ubuntu/mlcode git checkout -f -B thebranch 

Una vez hecho esto, actualiza los contenidos de mlcode como se esperaba. Pero no estoy seguro de que el pago manual y la creación de la sucursal sean suficientes o necesarios (está ausente de muchas instrucciones en línea que he encontrado): Parece que funcionó.

¿Qué debo hacer en mi máquina server para asegurarme de que un repository inicialmente descubierto actualiza el directory de trabajo cuando lo presiono? ¿Es necesario el paso explícito anterior? ¿Lo evitaría una post-receive diferente?

La respuesta corta es sí: una post-recepción diferente (mejor) podría evitar este problema. En particular, si tiene exactamente un tree de trabajo que debe actualizarse si y solo si se actualiza una twig xyz particular, puede extraer explícitamente esa twig cuando esa twig se actualiza:

 #! /bin/sh while read ohash nhash ref; do case "$ref" in refs/heads/xyz) git --work-tree=/path/to/deploy checkout -f xyz;; esac done 

Este no es un gran gancho post-recepción, pero es una ligera mejora. Lea la discusión a continuación para get más información.

Discusión

Primero testing este ejercicio: ¿qué sucede en cualquier repository ordinario , no desnudo, Git cuando ejecutas git checkout sin arguments, o git checkout -f sin nombre de twig? ¿Qué twig se revisa? Siéntase libre de search la respuesta en la documentation de git checkout . Compare esto con la twig que se revisa si le da a git checkout un nombre de twig.

Del mismo modo, ejecute git branch en un repository no desnudo. ¿Qué twig es actual? ¿Cómo lo sabe Git ?

Ahora que has hecho ese ejercicio, ¿qué twig crees que se revisa en un repository simple? (En serio, haz el ejercicio, te ayudará a recordar la respuesta y a explicar todo esto).

Push entrega commits y actualiza references

Cuando un repository es el objective de un git push , lo que realmente ocurre es que el sistema host receptor obtiene una serie de objects (commits y / o tags, y / o treees y / blobs que van con ellos) de algún otro Git. Luego, recibe una o más requestes (push regular) o commands (forzar push) desde ese otro Git: "configure refs/tags/v1.2 a 1234567... " o "configure refs/heads/branchname para feedbee... , y realmente lo digo en serio! " Obtiene un pedido-o-command por refspec , basado en lo que quien ejecutó git push dio como arguments a git push .

Si la reference nombra una twig ( refs/head/whatever ), y se acepta la actualización de la twig (es un avance rápido o forzado), esto actualiza la twig correspondiente en el map de nombres de las twigs del repository a commit-IDs.

Un repository desnudo todavía tiene una twig e índice actual

Como ya se ha dado count, git checkout sin arguments (o con solo -f ) verifica la twig actual .

El gancho post-recepción:

 #!/bin/sh git --work-tree=/path/to/work/tree checkout -f 

no está mal , precisamente. Pero es rápido y sucio, y un poco descuidado. La recepción recibió algo, probablemente algunos commit (s), tal vez una label también o en su lugar, y los puso en el repository desnudo. ¿Eso cambió la identificación hash almacenada en la twig actual ? ¿Quién sabe? ¿Cuál es la twig actual de todos modos?

Esa parte, al less, es fácil de responder. La twig actual es la que está almacenada en HEAD . Use git symbolic-ref HEAD para verlo. Si esto dice refs/heads/master , la twig actual es master .

¿Acabamos de get una actualización para esa twig? ¿Quién sabe? Bueno, el gancho posterior a la recepción podría saberlo. Se supone que debe leer toda la input estándar, que le indica , una línea a la vez, qué references (twigs, tags o lo que sea) se actualizaron, y cuáles son sus identificaciones hash antiguas y nuevas. Este gancho post-recepción no molesta. Simplemente vuelve a verificar la twig actual , actualizada o no.

Si la twig actual se actualizó, Git sabrá qué files replace (o agregar o eliminar) en function del índice , que es un seguimiento de lo que Git escribió en el tree de trabajo. Si la twig actual no se actualizó, Git hace un montón de trabajo ocupado y nada realmente cambia (esta es la "opción glorificada" en la documentation).

Esto es cierto incluso en un repository simple. Normalmente, no existiría ningún tree de trabajo, pero el --work-tree o $GIT_WORK_TREE que usted proporciona aquí anula la configuration core.bare durante todo el process de git checkout .

Pero la twig que está desprotegida es la sucursal actual . Sigue siendo la twig actual después, porque no hay un nombre de twig en este command de git checkout .

… donde explícitamente … reviso [una twig] con algo como

 GIT_WORK_TREE=/home/ubuntu/mlcode git checkout -f -B thebranch 

Cuando revisa con un nombre de sucursal, obtiene esa sucursal en particular, y Git cambia la sucursal actual a la que usted especificó. Un git checkout futuro sin nombre de sucursal echará un vistazo … a la sucursal actual , es decir, la que acaba de especificar aquí (suponiendo que no haya ningún cambio intermedio).

La twig actual de cualquier repository también afecta clones

Cuando se git clone desde un repository, desnudo o no, el nuevo clon comienza con una twig actual. Muy a menudo, eso es master pero esto se debe a que, con mucha frecuencia, clonas un repository existente cuya twig actual es master . El nuevo clon comienza con la misma twig actual, por defecto. (Puede usar -b branch-or-tag-name para cambiar este comportamiento en el lado del clone ).

Esto significa que cada vez que cambie la twig actual de un repository vacío que se usa tanto para clonar como para empujar, cambia la twig que alguien obtendrá cuando clonen ese repository. Probablemente no sea un gran problema, pero debes ser consciente de ello.

Solo hay un índice

Un repository desnudo normalmente no tiene tree de trabajo. Como tal, tampoco necesita un índice, ya que un índice restring lo que está en el tree de trabajo y se usa para build el siguiente compromiso, ninguno de los cuales tiene ningún significado en este repository sin tree de trabajo.

Una vez que empiezas a darle un tree de trabajo temporal con git --work-tree=... checkout , de repente, el índice (único) importa. Ese índice es lo que hace un seguimiento de lo que hay en el tree de trabajo. Si siempre le das a este repository el mismo tree de trabajo siempre, el hecho de que solo exista un índice no es un problema: un tree de trabajo, un índice, todo coincide.

Pero si alguna vez le das un segundo tree de trabajo temporal diferente … bueno, ahora tienes un índice tratando de hacer un seguimiento de dos treees de trabajo diferentes. Esto no funciona tan bien. Git es un poco listo, y en ocasiones se da count de que el índice es incorrecto para los treees de trabajo y hace que todo funcione. Pero no siempre funciona. Ahora necesita al less dos files de índice para sus dos treees de trabajo (o alternativamente puede borrar el file de índice y el tree de trabajo cada vez, para que no haya nada desajustado, pero esto anula el aspecto de caching / velocidad de un índice que realiza un seguimiento del tree de trabajo).