gancho post-recepción con commands de implementación que no funcionan correctamente

Tengo un git en un control remoto y he agregado un gancho de post-recepción. El gancho posterior a la recepción debe hacer lo siguiente.

Si [composer] está presente en el post de confirmación, actualice el compositor
Si [deploy] está presente en el post de confirmación, revise la twig que se ha enviado (por ejemplo, feature/test , master , etc.)
Si [migrate] está presente en el post de confirmación, php artisan migrate un php artisan migrate

Desafortunadamente, esto no funciona. Se llama al gancho, pero las acciones son "incorrectas".

Esta es la secuencia de commands

 #!/bin/sh MESSAGE=$(git log -1 HEAD --pretty=format:%s) if [[ "$MESSAGE" == *\[composer\]* ]]; then composer --working-dir=/var/www/feedev/ update fi if [[ "$MESSAGE" == *\[deploy\]* ]]; then while read oldrev newrev ref do branch=`echo $ref | cut -d/ -f3` git --work-tree=/var/www/feeddev/ --git-dir=/home/feeddev/staging.git checkout -f $branch done else git --work-tree=/var/www/feedev/ --git-dir=/home/feeddev/staging.git checkout -f fi if [[ "$MESSAGE" == *\[migrate\]* ]]; then php /var/www/feedev/artisan migrate fi 

Esto no funciona, porque, para fines de testing, agregué esas líneas

 touch /home/ezidev/ezidev.git/$MESSAGE.lock 

después de leer la variable del post, y también si el segundo caso es falso, agregue esto

 touch /home/ezidev/ezidev.git/nodeploy.lock 

Así que ahora me estoy comprometiendo y tengo el post de confirmación [implementar], pero no se ha comprobado ninguna nueva twig, y ​​también se generan dos files nuevos

touch /home/ezidev/ezidev.git/$MESSAGE.lock genera /home/ezidev/ezidev.git/static.lock

y

touch /home/ezidev/ezidev.git/nodeploy.lock genera /home/ezidev/ezidev.git/nodeploy.lock

¿Por qué el $ MESSAGE = static.lock? No escribí esto en mis posts de compromiso. ¿Cuál podría ser el problema y cómo soluciono esto?

Recuerde que se ejecuta un enlace posterior a la recepción después de que git haya recostackdo objects nuevos y haya actualizado algunas references, como refs/heads/master , refs/heads/bra/nch y / o refs/tags/v1.3 . (Las "references" son el nombre general de las twigs, las tags, la reference especial de ocultación, etc.) Las dos que normalmente se actualizan en una operación de "recepción" son twigs y tags, y la actualización de la label normalmente es la creación de una Sin embargo, son posibles otras actualizaciones, dependiendo de lo que permita en sus ganchos de pre-recepción y actualización. Además, si usa las "notas" de git, verá nombres que comienzan con refs/notes/ ).

Con eso en mente, veamos el primer command en tu script:

 MESSAGE=$(git log -1 HEAD --pretty=format:%s) 

Esto usa HEAD . ¿A qué compromiso (s) se refiere HEAD ?

Esta no es solo una pregunta retórica. La reference HEAD es normalmente una reference indirecta a una bifurcación: especifica qué bifurcación está "encendida" el depósito, en términos del check-out actual. Al ejecutar git checkout $branch cambian los contenidos de HEAD . Esto es cierto incluso en un repository HEAD : HEAD refiere a alguna twig, inicialmente master pero modificable, y en su caso probablemente cambie ya que hay algunos commands de git checkout en la secuencia de commands.

No hay forma de que yo sepa lo que estaba en HEAD en el momento en que se ejecutó tu script (y, en general, si el script se ejecutó, puede haber cambiado HEAD , por lo que puede ser difícil o incluso imposible que lo descubras). Pero eso determinaría qué commit git log examinó: HEAD probablemente contenga un nombre de twig, y ​​el nombre de la twig indicará una confirmación específica, y esa será la confirmación (única) que utiliza el git log .

Ahora volvamos a lo que realmente significa un gancho post-recepción, nuevamente. Se ejecuta después de recibir algunos objects (quizás incluso miles de confirmaciones) y actualizar algunas references (quizás incluso docenas de references). Luego está mirando una confirmación en una twig, que puede ser o no una de las muchas que se actualizaron, y la usa para decidir cómo manejar todas las actualizaciones de tal vez muchas confirmaciones en muchas twigs.

Esto parece poco probable que sea correcto.

Realmente no puedo escribir tu gancho para ti, pero echemos un vistazo más a parte de lo que ya tienes, que tiene un código correcto dentro de él (y también algún código iffy-at-best):

 while read oldrev newrev ref do branch=`echo $ref | cut -d/ -f3` git --work-tree=/var/www/feeddev/ --git-dir=/home/feeddev/staging.git checkout -f $branch done 

El gancho posterior a la recepción recibe las references que se actualizaron y de qué manera, como un set de líneas en la input estándar. Este ciclo while lee esas líneas. Eso significa que la parte while es correcta.

Sin embargo, el primer command dentro del ciclo está algo roto. Después de leer una línea de stdin, $ref será algo como refs/heads/master , refs/heads/bra/nch , y refs/heads/bra/nch refs/tags/v1.3 . La secuencia de eco y corte simplemente toma la tercera palabra de cada uno: master , bra y v1.3 . El primero es correcto: es la forma abreviada del nombre completo refs/heads/master , es decir, branch master . El segundo no está bien: es parte de la forma corta de branch bra/nch , pero es solo una parte , y no funcionará bien. El tercero también probablemente no está bien: es la forma abreviada del nombre refs/tags/v1.3 , es decir, la label v1.3 , pero es una label, no una twig . Parece probable que algo diferente sea apropiado para esto.

A continuación, el script ignora $oldrev y $newrev después de leerlos. Esto funciona para la mayoría, pero no para todas, las acciones posteriores a la recepción: si $ref ya existe, $oldrev es el SHA-1 que solía apuntar, y $newrev es el SHA-1 al que ahora apunta después de las actualizaciones . Por ejemplo, si acaba de enviar algunos nuevos commit (s) a branch feat/ure para que la twig se actualice en avance rápido, $ref es refs/heads/feat/ure y usando git rev-list $oldrev..$newrev te proporcionará los SHA-1 para cada uno de los nuevos commits. (Si se trata de un impulso de fuerza, por ejemplo, git push -f o git push +sha1:refs/heads/feat/ure en el cliente, algunos commits pueden ser "quitados", y puedes encontrarlos con git rev-list $newrev..$oldrev )

Pero hay dos casos más a considerar: primero, ese $ref se acaba de crear. Este es el caso normal para las tags, ya que las tags normalmente nunca deberían cambiarse, solo crearse. En este caso $oldrev será todo ceros (cuarenta 0 caracteres). En el caso general, es imposible encontrar qué compromiso (s), si alguno, están en esta reference (aunque hay algunos trucos que se pueden usar, por ejemplo, agregar un gancho previo a la recepción para prohibir las actualizaciones que son imposibles de descifrar , de modo que te quedan solo los casos especiales manejables). El último caso es que $ref se está eliminando , por ejemplo, alguien ejecutó git push origin :bra/nch para eliminar git push origin :bra/nch refs/heads/bra/nch del repository vacío en el server. En este caso $oldrev le dirá qué SHA-1 refs/heads/bra/nch fue, y $newrev será el especial 40 0 s "nulo SHA-1". No podrá verificar esa twig ya que simplemente se eliminó.

Finalmente, hay una git checkout -f que especifica un tree de trabajo en particular y un directory de git (este último reemplaza el $GIT_DIR que se establece en un $GIT_DIR posterior a la recepción). Estas son probablemente las routes correctas, pero $branch podría no ser un nombre de twig: en nuestro caso de ejemplos aquí, es master , luego bra , luego v1.3 por turno, en cada uno de los tres viajes a través del ciclo while.


En resumen (lo sé, "demasiado tarde" :-)) este gancho post-recepción particular es bastante defectuoso. Tendrá que averiguar qué casos desea realmente manejar y escribir uno nuevo que comience ejecutando el ciclo while:

 while read oldrev newrev ref; do ... done 

Dentro del ciclo, inspecciona las tres variables. Compruebe $oldrev y $newrev frente a 40- 0 s null-SHA1 para determinar si la operación es una creación, eliminación o actualización. Luego verifique los primeros componentes de $ref para encontrar el espacio de nombre de la reference; si se trata de una twig, comenzando con refs/heads/ , puede quitar la parte refs/heads/ para get el nombre de la twig; si es otra cosa, quizás puedas simplemente continue el ciclo para ignorar el cambio.

Si va a usar cut para quitar refs/heads/ , asegúrese de usar -f3- y no solo -f3 . (Prefiero usar la capacidad incorporada del intérprete de commands para eliminar cadenas, ${ref#refs/heads/} mismo, pero echo ${ref} | cut -d/ -f3- funciona).

Luego, si se trata de una actualización de sucursal (no una creación, ni una eliminación, solo una actualización), puede usar git rev-list $oldrev..$newrev para encontrar las confirmaciones agregadas a esa sucursal. Use git log en cada uno (o por eficiencia, git log $oldrev..$newrevgit log ejecutará git rev-list ) para inspeccionar sus líneas de asunto de compromiso y / o asignar cuerpos de post para las palabras key. Actúe de manera apropiada, sea lo que sea "apropiado", en la (s) confirmación (es) y / o sucursal en function de las palabras key (tal vez múltiples) que figuran en cada confirmación.