将Git钩子放入存储库中

.git/hooks放入项目存储库(例如,使用符号链接)是否被认为是一个坏的做法。如果是,将相同的钩子传递给不同的Git用户的最佳方式是什么?

123716 次浏览

不,把它们放到存储库中就可以了。我甚至建议这样做(如果它们对其他人也有用的话)。用户必须显式地启用它们(例如,如您所说,通过符号链接),这一方面有点麻烦,但另一方面它可以保护用户在未经他们同意的情况下运行任意代码。

我基本上同意的是为了,还有一些额外的建议,足以让它值得一个单独的答案。

首先,您应该编写一个脚本来创建适当的符号链接,特别是当这些钩子是关于执行策略或创建有用的通知时。如果人们只能输入bin/create-hook-symlinks,而不是必须自己输入,他们将更有可能使用钩子。

其次,直接符号链接钩子可以防止用户添加自己的个人钩子。例如,我非常喜欢预提交钩子样本,它可以确保我没有任何空白错误。解决这个问题的一个好方法是在你的存储库中放入一个钩子包装器脚本,并将钩子的所有符号链接到它。

然后包装器可以检查$0(假设它是一个Bash脚本;例如argv[0])来找出它被调用为哪个钩子,然后在存储库中调用相应的钩子,以及相应的用户的钩子,这些钩子必须重命名,并将所有参数传递给每个钩子。简单的例子:

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

安装脚本会将所有已经存在的钩子移到一边(在它们的名称后面附加.local),并将所有已知的钩子名称符号链接到上面的脚本:

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

TEMPLATE DIRECTORY开始,你可以使用这些机制之一来更新每个新创建的Git存储库的. /钩子目录:

模板目录包含文件和目录将

. $GIT_DIR

模板目录将是以下目录之一(按顺序):

  • - - -模板选项给出的参数;

  • GIT_TEMPLATE_DIR美元环境变量的内容;

  • init.templateDir配置变量;或

  • 默认模板目录:/usr/share/git-core/templates

pre-commit npm包很好地处理了这个问题,允许你在package.json文件中指定预提交钩子。

存储在项目中并安装在构建中

正如其他人在他们的答案中所述,如果你的钩子是特定于你的特定项目的,然后将它们包含在项目本身中,由Git管理。我想进一步说,考虑到使用单个脚本或命令构建项目是一种良好的实践,您的钩子应该在构建期间安装。

我写了一篇关于管理Git钩子的文章,如果你有兴趣更深入地阅读这篇文章。

Java和;Maven

< >强完全免责声明;我写了Maven插件

如果您正在使用Maven为您的Java项目处理构建管理,那么下面的Maven插件将处理从项目中的某个位置安装钩子。

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

把你所有的Git钩子放在你项目的一个目录中,然后配置你的pom.xml,以包括以下插件声明、目标和配置。

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

当你运行你的项目版本时,插件会配置Git从指定的目录中运行钩子。这将有效地为项目中的每个人在该目录中设置钩子。

JavaScript和NPM

对于NPM,有一个名为沙哑的的依赖项,它允许你安装钩子,包括用JavaScript编写的钩子。

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

其他人

此外,还有许多不同的钩子管理应用程序/插件,包括用于Python项目的未雨绸缪、用于Ruby项目的过量使用和用于Ruby node . js项目的Lefthook

这里有一个脚本add-git-hook.sh,你可以在存储库中作为常规文件发布,并可以执行它来将Git钩子附加到脚本文件中。调整使用哪个钩子(pre-commit, post-commit, pre-push,等等),并在cat中定义钩子。

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

该脚本具有可执行权限或者用户可以直接运行它。我使用它在提交后自动在其他机器上进行git-pull。

我回答了一个更简单的问题,这个问题不是他们问的,也不是OP想要的。在下面的评论中,我对在存储库中交付钩子脚本与在外部管理它们的用例和参数发表了看法。

现在你可以通过下面的方法来设置一个版本控制下的目录作为你的Git钩子目录,比如MY_REPO_DIR/.githooks

git config --local core.hooksPath .githooks/

它仍然不能直接执行,但是,如果您在README(或其他任何东西)中添加一个注释,这需要每个开发人员付出最小的努力。

你可以使用托管解决方案来进行预提交钩子管理,如未雨绸缪。 或者服务器端git-hook的集中式解决方案,如Datree.io.

它有内置的策略,如:

  1. 检测和防止秘密合并
  2. 强制正确的Git用户配置
  3. 强制Jira票务整合 -在拉请求名称/提交消息中提到票号。

它不会取代所有的钩子,但它可以帮助开发人员使用最明显的钩子,而不必在每个开发人员的计算机/存储库上安装钩子。

免责声明:我是Datrees创始人之一

对于基于__abc0的PHP项目,可以自动分发给工程师。下面是一个pre-commit和commit-msg钩子的例子。

创建一个hooks文件夹,然后在你的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);\"",
],

然后你甚至可以在项目继续时更新它们,因为每个人都在定期运行composer install

看起来很多帖子都过时了,至少如果你在python生态系统中使用预提交(+我发现在稍微旧版本的git中更改git钩子路径会失败,例如2.3)。使用.pre-commit-config。Yaml在你的repo根目录的hooks目录下,最简单的解决方案是运行:

pre-commit install -f --config hooks/.pre-commit-config.yaml