将git钩子放入存储库

时间:2010-08-11 21:22:05

标签: git hook githooks

将.git / hooks放入项目存储库(例如,使用符号链接)是否被认为是一种不好的做法。如果是,那么向不同的git用户提供相同钩子的最佳方法是什么?

8 个答案:

答案 0 :(得分:132)

我普遍认同Scytale,还有一些额外的建议,足以值得单独回答。

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

其次,直接符号链接钩子可以防止用户添加自己的个人钩子。例如,我更喜欢示例预提交钩子,它确保我没有任何空格错误。一个很好的解决方法是在你的repo中放入一个钩子包装器脚本,并将符号链接挂钩的所有。然后包装器可以检查$0(假设它是一个bash脚本;否则类似于argv[0])以找出它被调用的钩子,然后调用repo中的相应钩子,以及适当的用户钩子,必须重命名,将所有参数传递给每个。内存中的快速示例:

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

答案 1 :(得分:98)

不,将它们放入存储库是可以的,我甚至建议这样做(如果它们对其他人也有用)。用户必须明确启用它们(如您所说,例如通过符号链接),这一方面有点痛苦,但另一方面保护用户在未经他们同意的情况下运行任意代码。

答案 2 :(得分:13)

现在,您可以执行以下操作将受版本控制的目录设置为您的git hooks目录,例如MY_REPO_DIR/.githooks

git config --local core.hooksPath .githooks/

仍然不能直接执行,但是,如果您在自述文件(或其他内容)中添加注释,则每个开发人员都需要付出最小的努力。

答案 3 :(得分:3)

https://www.npmjs.com/package/pre-commit npm包可以优雅地处理这个问题,允许你在package.json中指定预提交挂钩。

答案 4 :(得分:3)

存储在项目中并在内部版本中安装

就像其他人在他们的答案中指出的那样,如果您的钩子是特定于您的特定项目的,则将它们包括在项目本身中,由git管理。我会更进一步地说,鉴于优良作法是使用单个脚本或命令来构建项目,因此应在构建过程中安装挂钩。

Java和Maven

完整免责声明;我写了下面描述的Maven插件。

如果要使用Maven为Java项目处理构建管理,则以下Maven插件可以处理从项目中某个位置的安装挂钩。

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

<build>
  <plugins>
    <plugin>
      <groupId>com.rudikershaw.gitbuildhook</groupId>
      <artifactId>git-build-hook-maven-plugin</artifactId>
      <version>2.0.2</version>
      <configuration>
        <!-- The locations of a variety of different hooks to install in the local project. -->
        <preCommit>path/to/hook.sh</preCommit>
      </configuration>
      <executions>
        <execution>
          <goals>
            <!-- Inititalise a Git repository if one does not already exist. -->
            <goal>initialize</goal>          
            <!-- Install Git hooks. -->
            <goal>install</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  <!-- ... etc ... -->
  </plugins>
</build>

JavaScript和NPM

对于NPM,有一个名为Husky的依赖项,它允许您安装包含用JavaScript编写的钩子的钩子。

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

答案 5 :(得分:0)

这是一个脚本add-git-hook.sh,您可以将其作为常规文件发送到存储库中,并且可以执行以将git hook附加到脚本文件中。调整要使用的钩子(提交前,提交后,推送前等),以及在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

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

编辑-我回答了一个更简单的问题,不是问什么,也不是OP想要的东西。我选择了在仓库中运送钩子脚本的用例和参数,而不是在下面的评论中从外部进行管理。希望这就是您想要的。

答案 6 :(得分:0)

您可以使用托管解决方案来进行预提交的挂钩管理,例如pre-commit。 或针对Datree.io之类的服务器端git-hooks的集中式解决方案。 它具有内置策略,例如:

  1. 检测并阻止merging of secrets
  2. 强制执行适当的Git user configuration
  3. 强制执行Jira ticket integration-在请求请求名称/提交消息中提及票证编号。

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

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

答案 7 :(得分:-2)

对于基于Composer的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的项目继续进行时更新它们。