Poner ganchos git en el repositorio

197

¿Se considera una mala práctica? Poner .git / hooks en el repositorio de proyectos (usando enlaces simbólicos, por ejemplo). En caso afirmativo, ¿cuál es la mejor manera de entregar los mismos ganchos a diferentes usuarios de git?

shabunc
fuente

Respuestas:

143

Generalmente estoy de acuerdo con Scytale, con un par de sugerencias adicionales, lo suficiente como para que valga una respuesta por separado.

Primero, debe escribir una secuencia de comandos que cree los enlaces simbólicos apropiados, especialmente si estos enlaces son para hacer cumplir la política o crear notificaciones útiles. Es mucho más probable que las personas usen los ganchos si solo pueden escribir bin/create-hook-symlinksque si tienen que hacerlo ellos mismos.

En segundo lugar, los enlaces directos simbólicos evitan que los usuarios agreguen sus propios enlaces personales. Por ejemplo, prefiero el gancho de precompromiso de muestra que garantiza que no tenga ningún error de espacio en blanco. Una excelente forma de evitar esto es colocar un script de contenedor de gancho en su repositorio y vincular todos los ganchos a él. Luego, el contenedor puede examinar $0(suponiendo que es un script bash; un equivalente como lo argv[0]contrario) para averiguar en qué gancho se invocó, y luego invocar el gancho apropiado dentro de su repositorio, así como el gancho del usuario apropiado, que tendrá que renombrarse , pasando todos los argumentos a cada uno. Ejemplo rápido de memoria:

#!/bin/bash
if [ -x $0.local ]; then
    $0.local "$@" || exit $?
fi
if [ -x tracked_hooks/$(basename $0) ]; then
    tracked_hooks/$(basename $0) "$@" || exit $?
fi

El script de instalación movería todos los ganchos preexistentes a un lado (agregar .localsus nombres) y vincularía todos los nombres de gancho conocidos al script anterior:

#!/bin/bash
HOOK_NAMES="applypatch-msg pre-applypatch post-applypatch pre-commit prepare-commit-msg commit-msg post-commit pre-rebase post-checkout post-merge pre-receive update post-receive post-update pre-auto-gc"
# assuming the script is in a bin directory, one level into the repo
HOOK_DIR=$(git rev-parse --show-toplevel)/.git/hooks

for hook in $HOOK_NAMES; do
    # If the hook already exists, is executable, and is not a symlink
    if [ ! -h $HOOK_DIR/$hook -a -x $HOOK_DIR/$hook ]; then
        mv $HOOK_DIR/$hook $HOOK_DIR/$hook.local
    fi
    # create the symlink, overwriting the file if it exists
    # probably the only way this would happen is if you're using an old version of git
    # -- back when the sample hooks were not executable, instead of being named ____.sample
    ln -s -f ../../bin/hooks-wrapper $HOOK_DIR/$hook
done
Cascabel
fuente
66
Agregué chmod +x .git/hooks/*a tu bin/create-hook-symlinks para trabajarlo.
guneysus
66
@guneysus No debería necesitar eso, porque los ganchos ya deberían ser ejecutables (deberían verificarse de esa manera) y los enlaces no necesitan ningún permiso especial, solo los archivos a los que se vinculan.
Cascabel
13
Una mejor manera de obtener el directorio de enlace es HOOK_DIR=$(git rev-parse --show-toplevel)/.git/hooks.
Arnold Daniels
2
He creado un sistema simple basado en esto para administrar los ganchos en mi proyecto: ell.io/tt$Paws.js/blob/Master/Scripts/install-git-hooks.sh
ELLIOTTCABLE
66
Tomé solo lo esencial y lo puse en un repositorio github.com/sjungwirth/githooks
Scott Jungwirth
111

No, ponerlos en el repositorio está bien, incluso sugeriría hacerlo (si también son útiles para otros). El usuario tiene que habilitarlos explícitamente (como dijiste, por ejemplo, mediante simblinking), lo que por un lado es un poco difícil, pero por otro lado protege a los usuarios de ejecutar código arbitrario sin su consentimiento.

guadaña
fuente
13
¿Qué pasa si se trata de una política de la empresa? Entonces, el código no es "arbitrario", este es un código obligatorio, por lo que esto se consideraría una limitación en GIT, por no tener otro directorio (predefinido), que se rastrea, que también obtiene ejecutado junto con los ganchos regulares
Tobias Hagenbeek
14
La entrega automática de ganchos es un problema de seguridad, me alegra que Git no lo haga directamente: para hacer cumplir la política del equipo / empresa, usar ganchos en el lado del servidor o dejar que los usuarios decidan habilitarlos manualmente como @scy describe :)
Marque K Cowan
44
"protege a los usuarios [...] de ejecutar código arbitrario sin su consentimiento". Si un desarrollador quisiera que usted sugiriera (simbología), entonces el enganche podría ser cambiado por otra persona y ejecutar "código arbitrario sin su consentimiento"
MiniGod
24
MiniGod: Por supuesto. Si eres lo suficientemente paranoico, puedes copiar los ganchos en lugar de simularlos, luego auditarlos y solo luego habilitarlos. Sin embargo, la mayoría de los repositorios de Git (cita requerida) contendrán el código fuente que se ejecutará en la máquina del usuario, por lo que es probable que ejecute código no auditado que cambia constantemente. Pero sí, tienes un punto. ;)
scy
46

Hoy en día puede hacer lo siguiente para establecer un directorio que esté bajo control de versiones para que sea su directorio git hooks, por ejemplo, MY_REPO_DIR/.githookssería

git config --local core.hooksPath .githooks/

Todavía no se puede hacer cumplir directamente, pero si agrega una nota en su archivo README (o lo que sea), esto requiere un mínimo esfuerzo por parte de cada desarrollador.

bbarker
fuente
3
Un truco que encontré en viget.com/articles/two-ways-to-share-git-hooks-with-your-team es configurar la opción desde su Makefile / CMake config / lo que sea.
Julius Bullinger el
6

Desde http://git-scm.com/docs/git-init#_template_directory , puede usar uno de estos mecanismos para actualizar el directorio .git / hooks de cada repositorio de git recién creado:

El directorio de plantillas contiene archivos y directorios que se copiarán en $ GIT_DIR después de crearlo.

El directorio de la plantilla será uno de los siguientes (en orden):

  • el argumento dado con la opción --template;

  • el contenido de la variable de entorno $ GIT_TEMPLATE_DIR;

  • la variable de configuración init.templateDir; o

  • el directorio de plantillas predeterminado: / usr / share / git-core / templates.

DavidN
fuente
5

Almacenar en el proyecto e instalar en la compilación

Como otros dicen en su respuesta, si sus ganchos son específicos para sus proyectos particulares, inclúyalos en el proyecto mismo, administrado por git. Llevaría esto aún más lejos y diría que, dado que es una buena práctica tener la compilación de su proyecto utilizando un solo script o comando, sus ganchos deben instalarse durante la compilación.

Escribí un artículo sobre la gestión de git hooks , si está interesado en leer sobre esto con un poco más de profundidad.

Java y Maven

Descargo de responsabilidad completo; Escribí el complemento Maven que se describe a continuación.

Si está manejando la gestión de compilación con Maven para sus proyectos Java, el siguiente complemento Maven maneja la instalación de enlaces desde una ubicación en su proyecto.

https://github.com/rudikershaw/git-build-hook

Coloque todos sus ganchos Git en un directorio en su proyecto, luego configúrelo pom.xmlpara incluir la siguiente declaración, objetivo y configuración del complemento.

<build>
  <plugins>
    <plugin>
      <groupId>com.rudikershaw.gitbuildhook</groupId>
      <artifactId>git-build-hook-maven-plugin</artifactId>
      <configuration>
        <gitConfig>
          <!-- The location of the directory you are using to store the Git hooks in your project. -->
          <core.hooksPath>hooks-directory/</core.hooksPath>
        </gitConfig>
      </configuration>
      <executions>
        <execution>
          <goals>       
            <!-- Sets git config specified under configuration > gitConfig. -->
            <goal>configure</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
      <!-- ... etc ... -->
  </plugins>
</build>

Cuando ejecuta su proyecto, el complemento configurará git para ejecutar enlaces fuera del directorio especificado. Esto configurará efectivamente los ganchos en ese directorio para todos los que trabajen en su proyecto.

JavaScript y NPM

Para NPM hay una dependencia llamada Husky que le permite instalar ganchos, incluidos los escritos en JavaScript.

// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "npm test",
      "pre-push": "npm test",
      "...": "..."
    }
  }
}

Otros

Además, hay pre-commit para proyectos de Python, Overcommit para proyectos de Ruby y Lefthook para proyectos de Ruby o Node.

Rudi Kershaw
fuente
1
Gracias por crear este complemento, hizo que la integración de mi archivo de confirmación previa fuera muy fácil.
Michiel Bugher
1

Aquí hay un script, add-git-hook.sh, que puede enviar como un archivo normal en el repositorio y puede ejecutarse para agregar el gancho git al archivo de script. Ajuste qué gancho usar (pre-commit, post-commit, pre-push, etc.) y la definición del gancho en el cat heredoc.

#!/usr/bin/bash
# Adds the git-hook described below. Appends to the hook file
# if it already exists or creates the file if it does not.
# Note: CWD must be inside target repository

HOOK_DIR=$(git rev-parse --show-toplevel)/.git/hooks
HOOK_FILE="$HOOK_DIR"/post-commit

# Create script file if doesn't exist
if [ ! -e "$HOOK_FILE" ] ; then
        echo '#!/usr/bin/bash' >> "$HOOK_FILE"
        chmod 700 "$HOOK_FILE"
fi

# Append hook code into script
cat >> "$HOOK_FILE" <<EOF

########################################
# ... post-commit hook script here ... #
########################################

EOF

Este script puede tener sentido para tener permisos ejecutables o el usuario puede ejecutarlo directamente. Usé esto para git-pull automáticamente en otras máquinas después de que me comprometí.

EDITAR: respondí la pregunta más fácil que no era lo que se preguntó y no era lo que estaba buscando el OP. Opiné sobre los casos de uso y los argumentos para enviar scripts de gancho en el repositorio en lugar de administrarlos externamente en los comentarios a continuación. Espero que sea más lo que estás buscando.

mathewguest
fuente
Agradezco su esfuerzo y creo que hay una información valiosa aquí, sin embargo, no responde a la pregunta planteada.
shabunc
En mi opinión, si los enlaces son específicos de un repositorio particular o son componentes integrales de los flujos de trabajo utilizados, entonces pertenecen al repositorio como archivos. Es difícil colocarlos en otro lugar sin crear más problemas de los que resuelve. Podría almacenar ganchos generales en un repositorio propio o en una unidad compartida que podría mantener el repositorio del proyecto limpio pero a costa de ser mucho menos práctico. Estoy de acuerdo con los otros usuarios al decir que los ganchos deben ser fáciles de agregar. Los enlaces simbólicos pueden crear una dependencia innecesaria de un sistema o estructura de archivos en particular.
mathewguest
Además, los enlaces simbólicos rompen la capacidad de los usuarios de agregar sus propios ganchos. El directorio .git / hooks no se rastrea, por lo que la fuente debe comenzar en el repositorio y llegar al script de ganchos, no al revés. Creo que el contraargumento sería que los ganchos git están más relacionados con el flujo de trabajo o el equipo en lugar del proyecto y, por lo tanto, no pertenecen al repositorio. Dependiendo de su caso de uso específico, ¿está más de acuerdo con contaminar potencialmente el repositorio git con ganchos menos relacionados o prefiere renunciar a un montón de complejidad al colocarlos en otro lugar?
mathewguest
1

Para proyectos PHP basados ​​en Composer, puede distribuir automáticamente a los ingenieros. Aquí hay un ejemplo para los enlaces pre-commit y commit-msg.

Cree una hookscarpeta, luego en su composer.json:

 },
 "scripts": {
     "post-install-cmd": [
         "cp -r 'hooks/' '.git/hooks/'",
         "php -r \"copy('hooks/pre-commit', '.git/hooks/pre-commit');\"",
         "php -r \"copy('hooks/commit-msg', '.git/hooks/commit-msg');\"",
         "php -r \"chmod('.git/hooks/pre-commit', 0777);\"",
         "php -r \"chmod('.git/hooks/commit-msg', 0777);\"",
     ],

Luego, incluso puede actualizarlos a medida que el proyecto continúa, ya que todos se ejecutan composer installregularmente.

Elijah Lynn
fuente
0

Puede usar una solución administrada para la administración de enlace de precompromiso como precompromiso . O una solución centralizada para git-hooks del lado del servidor como Datree.io . Tiene políticas integradas como:

  1. Detecta y evita la fusión de secretos .
  2. Aplicar la configuración de usuario Git adecuada .
  3. Aplicar la integración de tickets de Jira : mencione el número de ticket en el nombre de solicitud de extracción / mensaje de confirmación.

No reemplazará todos sus ganchos, pero podría ayudar a sus desarrolladores con los más obvios sin la configuración infernal de instalar los ganchos en cada computadora / repositorio de desarrolladores.

Descargo de responsabilidad: soy uno de los fundadores de Datrees

Shimon Tolts
fuente
3
Creo que está haciendo un producto interesante, pero también creo que esto no responde a la pregunta y, básicamente, es una autopromoción y nada más.
shabunc