Mettre des hooks git dans le référentiel


197

Est-il considéré comme une mauvaise pratique - de mettre .git / hooks dans le référentiel des projets (en utilisant des liens symboliques, par exemple). Si oui, quelle est la meilleure façon de fournir les mêmes hooks à différents utilisateurs de git?

Réponses:


143

Je suis généralement d'accord avec Scytale, avec quelques suggestions supplémentaires, suffisamment pour que cela mérite une réponse distincte.

Tout d'abord, vous devez écrire un script qui crée les liens symboliques appropriés, surtout si ces crochets concernent l'application de la politique ou la création de notifications utiles. Les gens seront beaucoup plus susceptibles d'utiliser les crochets s'ils peuvent simplement taper bin/create-hook-symlinksque s'ils doivent le faire eux-mêmes.

Deuxièmement, les hooks de liaison directe empêchent les utilisateurs d'ajouter leurs propres hooks personnels. Par exemple, j'aime plutôt l'exemple de hook de pré-validation qui garantit que je n'ai pas d'erreurs d'espaces. Un excellent moyen de contourner cela est de déposer un script wrapper de hook dans votre référentiel et de créer un lien symbolique vers tous les hooks. L'encapsuleur peut ensuite examiner $0(en supposant qu'il s'agit d'un script bash; un équivalent comme argv[0]sinon) pour déterminer le hook auquel il a été invoqué, puis appeler le hook approprié dans votre référentiel, ainsi que le hook de l'utilisateur approprié, qui devra être renommé , en passant tous les arguments à chacun. Exemple rapide de mémoire:

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

Le script d'installation déplacerait tous les crochets préexistants sur le côté (ajouter .localà leurs noms), et lierait tous les noms de crochets connus au script ci-dessus:

#!/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

6
J'ai ajouté chmod +x .git/hooks/*à votre bin/create-hook-symlinks travail.
guneysus

6
@guneysus Vous ne devriez pas en avoir besoin, car les hooks doivent déjà être exécutables (ils doivent être vérifiés de cette manière) et les liens n'ont pas besoin d'autorisations spéciales, juste les fichiers vers lesquels ils sont liés.
Cascabel

13
Une meilleure façon d'obtenir le répertoire hook est HOOK_DIR=$(git rev-parse --show-toplevel)/.git/hooks.
Arnold Daniels

2
J'ai mis en place un système simple basé sur cela pour gérer les crochets dans mon projet: ell.io/tt$Paws.js/blob/Master/Scripts/install-git-hooks.sh
ELLIOTTCABLE

6
J'ai pris juste l'essentiel et je l'ai mis dans un repo github.com/sjungwirth/githooks
Scott Jungwirth

111

Non, les placer dans le référentiel est très bien, je suggérerais même de le faire (s'ils sont également utiles pour d'autres). L'utilisateur doit les activer explicitement (comme vous l'avez dit, par exemple par lien symbolique), ce qui est un peu pénible d'une part, mais protège les utilisateurs d'autre part de l'exécution de code arbitraire sans leur consentement.


13
que se passe-t-il s'il s'agit d'une politique d'entreprise, alors le code n'est pas "arbitraire", c'est du code requis, donc cela serait considéré comme une limitation dans GIT, pour ne pas avoir un autre répertoire (prédéfini), qui est suivi, qui obtient également exécuté avec les crochets réguliers
Tobias Hagenbeek

14
La livraison automatique de hooks est un problème de sécurité, je suis heureux que Git ne le fasse pas directement - pour appliquer la politique de l'équipe / entreprise, utiliser des hooks côté serveur ou laisser les utilisateurs décider manuellement de les activer comme @scy le décrit :)
Mark K Cowan

4
"protège les utilisateurs [...] contre l'exécution de code arbitraire sans leur consentement". Si un développeur veut faire ce que vous suggérez (lien symbolique), le crochet peut être modifié par quelqu'un d'autre et exécuter "du code arbitraire sans son consentement"
MiniGod

24
MiniGod: Bien sûr. Si vous êtes suffisamment paranoïaque, vous pouvez copier les crochets au lieu de les créer des liens symboliques, puis les auditer et ensuite les activer. Cependant, la plupart des référentiels Git (citation nécessaire) contiendront du code source qui doit être exécuté sur la machine de l'utilisateur, vous êtes donc susceptible d'exécuter du code non audité en constante évolution. Mais oui, vous avez raison. ;)
scy

46

De nos jours, vous pouvez faire ce qui suit pour définir un répertoire qui est sous contrôle de version pour être votre répertoire git hooks, par exemple, MY_REPO_DIR/.githooksserait

git config --local core.hooksPath .githooks/

Toujours pas directement exécutoire mais, si vous ajoutez une note dans votre fichier README (ou autre), cela nécessite un minimum d'effort de la part de chaque développeur.


3
Une astuce que j'ai trouvée sur viget.com/articles/two-ways-to-share-git-hooks-with-your-team est de définir l'option depuis votre configuration Makefile / CMake / peu importe.
Julius Bullinger le

6

Depuis http://git-scm.com/docs/git-init#_template_directory , vous pouvez utiliser l'un de ces mécanismes pour mettre à jour le répertoire .git / hooks de chaque git repo nouvellement créé:

Le répertoire du modèle contient des fichiers et des répertoires qui seront copiés dans le $ GIT_DIR après sa création.

Le répertoire du modèle sera l'un des suivants (dans l'ordre):

  • l'argument donné avec l'option --template;

  • le contenu de la variable d'environnement $ GIT_TEMPLATE_DIR;

  • la variable de configuration init.templateDir; ou

  • le répertoire de modèles par défaut: / usr / share / git-core / templates.


5

Stocker dans le projet et installer dans la build

Comme d'autres l'affirment dans leur réponse, si vos crochets sont spécifiques à vos projets particuliers, incluez-les dans le projet lui-même, géré par git. Je voudrais aller encore plus loin et dire que, étant donné que c'est une bonne pratique de faire construire votre projet en utilisant un seul script ou une seule commande, vos hooks devraient être installés pendant la construction.

J'ai écrit un article sur la gestion des hooks git , si vous souhaitez en savoir plus à ce sujet.

Java et Maven

Clause de non-responsabilité complète; J'ai écrit le plugin Maven décrit ci-dessous.

Si vous gérez la gestion de build avec Maven pour vos projets Java, le plug-in Maven suivant gère l'installation des crochets à partir d'un emplacement de votre projet.

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

Placez tous vos hooks Git dans un répertoire de votre projet, puis configurez votre pom.xmlpour inclure la déclaration, l'objectif et la configuration du plugin suivants.

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

Lorsque vous exécutez votre build de projet, le plugin configurera git pour exécuter des hooks à partir du répertoire spécifié. Cela configurera efficacement les crochets dans ce répertoire pour tous ceux qui travaillent sur votre projet.

JavaScript et NPM

Pour NPM, il existe une dépendance appelée Husky qui vous permet d'installer des hooks, y compris ceux écrits en JavaScript.

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

Autres

De plus, il existe une pré-validation pour les projets Python, une sur- validation pour les projets Ruby et un Lefthook pour les projets Ruby ou Node.


1
Merci d'avoir créé ce plugin, cela a rendu l'intégration de mon fichier de pré-validation super facile.
Michiel Bugher


1

Voici un script, add-git-hook.sh, que vous pouvez expédier sous forme de fichier normal dans le référentiel et qui peut être exécuté pour ajouter le hook git au fichier de script. Ajustez le hook à utiliser (pré-commit, post-commit, pre-push, etc.) et la définition du hook dans le heredoc du chat.

#!/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

Ce script peut être logique d'avoir des autorisations exécutables ou l'utilisateur peut l'exécuter directement. Je l'ai utilisé pour git-pull automatiquement sur d'autres machines après m'être engagé.

EDIT-- J'ai répondu à la question la plus simple qui n'était pas ce qui était demandé et ce n'était pas ce que le PO recherchait. J'ai exprimé mon opinion sur les cas d'utilisation et les arguments pour l'expédition de scripts de hook dans le référentiel par rapport à leur gestion externe dans les commentaires ci-dessous. J'espère que c'était plus ce que vous cherchiez.


J'apprécie vos efforts et je crois cependant qu'il y a une information précieuse ici - elle ne répond pas à la question posée.
shabunc

À mon avis, si les hooks sont spécifiques à un référentiel particulier ou font partie intégrante des workflows utilisés, ils appartiennent au référentiel en tant que fichiers. Il est difficile de les placer ailleurs sans créer plus de problèmes qu'il n'en résout. Vous pouvez stocker les hooks généraux dans un référentiel qui lui est propre ou sur un lecteur partagé, ce qui pourrait garder le dépôt du projet propre, mais au prix d'être beaucoup moins pratique. Je suis d'accord avec les autres utilisateurs pour dire que les crochets doivent être faciles à ajouter. Les liens symboliques peuvent créer une dépendance inutile à l'égard d'un système ou d'une structure de fichiers particulier.
mathewguest

De plus, les liens symboliques empêchent les utilisateurs d'ajouter leurs propres crochets. Le répertoire .git / hooks n'est pas suivi, la source doit donc commencer dans le référentiel et pénétrer dans le script hooks, et non l'inverse. Je pense que le contre-argument serait que les hooks git sont plus liés au workflow ou à l'équipe plutôt qu'au projet et n'appartiennent donc pas au référentiel. En fonction de votre cas d'utilisation spécifique, êtes-vous plus à l'aise de potentiellement polluer le référentiel git avec des hooks moins liés ou préférez-vous renoncer à un tas de complexité pour les mettre ailleurs?
mathewguest

1

Pour les projets PHP basés sur Composer, vous pouvez distribuer automatiquement aux ingénieurs. Voici un exemple pour les hooks pré-commit et commit-msg.

Créez un hooksdossier, puis dans votre 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);\"",
     ],

Ensuite, vous pouvez même les mettre à jour à mesure que le projet se poursuit, car tout le monde s'exécute composer installrégulièrement.


0

Vous pouvez utiliser une solution gérée pour la gestion des hooks avant validation, comme la pré-validation . Ou une solution centralisée pour les hooks git côté serveur comme Datree.io . Il a des politiques intégrées comme:

  1. Détectez et empêchez la fusion de secrets .
  2. Appliquez la configuration utilisateur Git appropriée .
  3. Appliquez l' intégration du ticket Jira - mentionnez le numéro du ticket dans le nom de la requête de tirage / le message de validation.

Il ne remplacera pas tous vos hooks, mais cela pourrait aider vos développeurs avec les plus évidents sans l'enfer de configuration d'installer les hooks sur chaque ordinateur / référentiel de développeurs.

Avertissement: je suis l'un des fondateurs de Datrees


3
Je pense que vous fabriquez un produit intéressant mais je pense aussi que cela ne répond pas à la question et qu'il s'agit essentiellement d'une auto-promotion et rien de plus.
shabunc
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.