Les scripts de hook Git peuvent-ils être gérés avec le référentiel?

337

Nous aimerions créer quelques scripts de hook de base que nous pouvons tous partager - pour des choses comme le pré-formatage des messages de commit. Git a des scripts de hook pour cela qui sont normalement stockés sous <project>/.git/hooks/. Cependant, ces scripts ne sont pas propagés lorsque les gens font un clone et ils ne sont pas contrôlés par la version.

Existe-t-il un bon moyen d'aider tout le monde à obtenir les bons scripts de hook? Puis-je simplement faire pointer ces scripts de hook vers des scripts contrôlés par version dans mon référentiel?

Pat Notz
la source
5
Une bonne question. Je souhaite seulement qu'il y ait une meilleure réponse (sans se plaindre à @mipadi, je souhaite juste que git ait un moyen de le faire de manière plus automatique - même si seulement avec une option spécifiée pour git clone.)
lindes
Je suis d'accord, @lindes! Mais peut-être restreindre ce partage d'hameçons en intentionnel? Les choses deviendraient désordonnées pour les utilisateurs de Windows, je suppose.
kristianlm
@kristianlm: Il y a toutes sortes de raisons pour lesquelles cela peut être parfois salissant ... et aussi quand c'est agréable de l'avoir là-bas. Je souhaite juste qu'il y ait une option ou quelque chose qui copierait les crochets. Je suppose que je vais devoir vérifier le code git-core un jour et créer un patch. :) (Ou j'espère que quelqu'un d'autre le fera ... ou vivra avec la solution de contournement dans la réponse de mipadi , ou peu importe.)
lindes
pre-commitrend cela facile pour les hooks de pré-validation. Ne répond pas à la question de l'OP concernant la gestion d'un hook git arbitraire, mais les hooks de pré-validation sont probablement les plus fréquemment utilisés à des fins de qualité de code.
ericsoco

Réponses:

144

Théoriquement, vous pouvez créer un hooksrépertoire (ou le nom que vous préférez) dans le répertoire de votre projet avec tous les scripts, puis les lier de manière symbolique .git/hooks. Bien sûr, chaque personne qui a cloné le référentiel devrait configurer ces liens symboliques (bien que vous puissiez vraiment devenir fantaisiste et avoir un script de déploiement que le cloneur pourrait exécuter pour les configurer semi-automatiquement).

Pour faire le lien symbolique sur * nix, il vous suffit de:

root="$(pwd)"
ln -s "$root/hooks" "$root/.git/hooks"

utiliser ln -sfsi vous êtes prêt à remplacer ce qui se trouve.git/hooks

mipadi
la source
38
ce n'était pas anodin, donc j'inclus un lien pour savoir comment créer un lien symbolique correctement: stackoverflow.com/questions/4592838/…
David T.
17
git version 2.9 a maintenant une option de configuration pour core.hooksPathconfigurer un fichier en dehors de .git pour le lier au dossier hooks.
Aaron Rabinowitz
216

Dans Git 2.9 , l'option de configuration core.hooksPathspécifie un répertoire de hooks personnalisé.

Déplacez vos hooks vers un hooksrépertoire suivi dans votre référentiel. Ensuite, configurez chaque instance du référentiel pour utiliser le suivi hooksau lieu de $GIT_DIR/hooks:

git config core.hooksPath hooks

En général, le chemin peut être absolu ou relatif au répertoire dans lequel les hooks sont exécutés (généralement la racine de l'arborescence de travail; voir la section DESCRIPTION de man githooks).

Max Shenfield
la source
15
... et le répertoire des hooks vers lequel pointer peut être un référentiel de hooks séparé;)
René Link
10
Eh bien, ce paramètre de configuration est-il défini automatiquement lorsque vous faites un clone git?
Anneau
4
En règle générale, les variables de configuration git ne peuvent pas être définies par le référentiel que vous clonez. Je pense que c'est pour empêcher l'exécution de code arbitraire. git config contrôle l'exécution du code via des hooks, le nom d'utilisateur sur les messages de commit et d'autres fonctions importantes.
Max Shenfield
1
Que se passe-t-il si un membre de l'équipe effectue une commande git dans une autre succursale? Ils doivent l'inclure dans chaque branche ..
jokerster
1
C'est vrai. D'un autre côté, si vous mettez à jour les hooks dans des commits plus récents, les repos clonés les obtiendront automatiquement lorsque vous travaillez sur des branches construites au-dessus de ce commit. Les deux façons ont leurs avantages et leurs inconvénients.
fabb
15

Si votre projet est un projet JavaScript et que vous l'utilisez npmcomme gestionnaire de packages, vous pouvez utiliser shared-git-hooks pour appliquer les githooks npm install.

kilianc
la source
5
Maintenant, je sais à qui sont ajoutées ces conneries .git/hooks.
gavenkoa
Avertissement - ne prend pas en charge Windows (sauf s'il est exécuté en tant qu'administrateur dans git bash). Une solution simple consiste à ajouter "préinstallation": "git config core.hooksPath hooks" comme script dans package.json. ie Where hooks est un dossier contenant vos scripts git.
Shane Gannon
8

Pour les utilisateurs de Nodejs , une solution simple consiste à mettre à jour package.json avec

{
  "name": "name",
  "version": "0.0.1",
  ......
  "scripts": {
    "preinstall": "git config core.hooksPath hooks", 

La préinstallation s'exécutera avant

installation de npm

et redirige git pour rechercher des hooks dans le répertoire. \ hooks (ou le nom que vous choisissez). Ce répertoire doit imiter . \. Git \ hooks en termes de nom de fichier (moins le .sample) et de structure.

Imaginez Maven et les autres outils de construction auront un équivalent à préinstaller .

Il devrait également fonctionner sur toutes les plateformes.

Si vous avez besoin de plus d'informations, consultez https://www.viget.com/articles/two-ways-to-share-git-hooks-with-your-team/

Shane Gannon
la source
5

Que diriez -vous de git-hooks , il route .git/hooksinvoquer dans le script sous le répertoire du projet githooks.

Il existe également de nombreuses fonctionnalités pour vous permettre de minimiser la copie et le lien symbolique partout.

quenouille
la source
5

La plupart des langages de programmation modernes, ou plutôt leurs outils de construction, prennent en charge les plugins pour gérer les hooks git. Cela signifie que tout ce que vous devez faire est de configurer votre package.json, pom.xml, etc., et tout membre de votre équipe n'aura d'autre choix que de se conformer à moins qu'il ne modifie le fichier de construction. Le plugin ajoutera du contenu dans le répertoire .git pour vous.

Exemples:

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

https://github.com/olukyrich/githook-maven-plugin

https://www.npmjs.com/package/git-hooks

yuranos
la source
J'ai essayé de réaliser cela de manière générique, à utiliser dans mes projets, alors j'ai écrit cet outil: pypi.org/project/hooks4git
Lovato
3

Nous utilisons des solutions Visual Studio (et donc des projets) qui ont des événements avant et après la construction. J'ajoute un projet supplémentaire nommé «GitHookDeployer». Le projet modifie lui-même un fichier dans l'événement post-génération. Ce fichier est configuré pour être copié dans le répertoire de génération. Ainsi, le projet est généré à chaque fois et n'est jamais ignoré. Dans l'événement de génération, il s'assure également que tous les crochets git sont en place.

Notez que ce n'est pas une solution générale, car certains projets, bien sûr, n'ont rien à construire.

Mike de Klerk
la source
2

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 git-hooks 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 d'extraction / message de validation.

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

Avertissement: je suis l'un des fondateurs de Datrees

Shimon Tolts
la source
1

Vous pouvez faire de votre dossier hooks un autre dépôt git et le lier en tant que sous-module ... Je suppose que cela ne vaut la peine que si vous avez beaucoup de membres et de hooks changés régulièrement.

Do-do-new
la source
1

Idéalement, les hooks sont écrits en bash, si vous suivez les exemples de fichiers. Mais vous pouvez l'écrire dans n'importe quelle langue disponible, et assurez-vous simplement qu'il a le drapeau exécutable.

Ainsi, vous pouvez écrire un code Python ou Go pour atteindre vos objectifs et le placer sous le dossier hooks. Cela fonctionnera, mais il ne sera pas géré avec le référentiel.

Deux options

a) Multi-scripts

Vous pouvez coder vos hooks dans votre aide et ajouter un petit fragment de code aux hooks, pour appeler votre script parfait, comme ceci:

$ cat .git/hooks/pre-commit
#!/bin/bash
../../hooks/myprecommit.js

b) Script unique

Une option plus intéressante consiste à ajouter un seul script pour les gouverner tous, au lieu de plusieurs. Donc, vous créez un hooks / mysuperhook.go et pointez chaque hook que vous voulez y avoir.

$ cat .git/hooks/pre-commit
#!/bin/bash
../../hooks/mysuperhook.go $(basename $0)

Le paramètre fournira à votre script quel hook a été déclenché, et vous pouvez le différencier dans votre code. Pourquoi? Parfois, vous voudrez peut-être exécuter la même vérification pour commit et push, par exemple.

Puis?

Ensuite, vous voudrez peut-être avoir d'autres fonctionnalités, comme:

  • Déclenchez le crochet manuellement pour vérifier si tout va bien avant même un commit ou un push. Si vous appelez simplement votre script (option a ou b) ferait l'affaire.
  • Déclenchez les hooks sur CI, vous n'avez donc pas besoin de réécrire les mêmes vérifications pour CI, ce serait simplement appeler les déclencheurs de validation et de poussée, par exemple. La même chose que ci-dessus devrait le résoudre.
  • Appelez des outils externes, comme un validateur de démarque ou un validateur YAML. Vous pouvez effectuer des appels système et devez gérer STDOUT et STDERR.
  • Assurez-vous que tous les développeurs ont un moyen simple d'installer les hooks, donc un bon script doit être ajouté au référentiel pour remplacer les hooks par défaut par les bons
  • Ayez des assistants globaux, comme une vérification pour bloquer les validations pour développer et maîtriser les branches, sans avoir à l'ajouter à chaque référentiel. Vous pouvez le résoudre en ayant un autre référentiel avec des scripts globaux.

Cela peut-il être plus simple?

Oui, il existe plusieurs outils pour vous aider à gérer les git-hooks. Chacun d'eux est conçu pour s'attaquer au problème sous un angle différent, et vous devrez peut-être les comprendre tous pour obtenir celui qui vous convient le mieux, à vous ou à votre équipe. GitHooks.com offre beaucoup de lecture sur le crochet et plusieurs outils disponibles aujourd'hui.

À ce jour, 21 projets y sont répertoriés avec différentes stratégies pour gérer les git hooks. Certains ne le font que pour un seul crochet, certains pour une langue spécifique, etc.

Un de ces outils, écrit par moi et offert gratuitement en tant que projet open source , s'appelle hooks4git . Il est écrit en Python (parce que j'aime ça) mais l'idée est de gérer tous les éléments répertoriés ci-dessus dans un seul fichier de configuration appelé .hooks4git.ini, qui vit à l'intérieur de votre référentiel et peut appeler n'importe quel script que vous souhaitez appeler, dans n'importe quelle langue .

L'utilisation de git hooks est absolument fantastique, mais la façon dont ils sont proposés ne fait que l'éloigner des gens.

Lovato
la source
J'avais posté une version très courte il y a quelque temps, et comme convenu avec les modérateurs, cela apporte des explications à l'intérieur, et un bref lien vers un outil que j'ai écrit moi-même qui, je pense, peut aider d'autres développeurs.
Lovato
1

Pour les utilisateurs gradle

J'ai trouvé ces scripts très utiles pour les projets Gradle.

build.gradle

apply from: rootProject.file('gradle/install-git-hooks.gradle')

gradle / install-git-hooks.gradle

tasks.create(name: 'gitExecutableHooks') {
    doLast {
        Runtime.getRuntime().exec("chmod -R +x .git/hooks/");
    }
}
task installGitHooks(type: Copy) {
    from new File(rootProject.rootDir, 'pre-commit')
    into { new File(rootProject.rootDir, '.git/hooks') }
}
gitExecutableHooks.dependsOn installGitHooks
clean.dependsOn gitExecutableHooks

pré-commit

.... your pre commit scripts goes here
a3765910
la source