259

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

4

9 回答 9

160

我通常同意Scy,并提出了一些额外的建议,足以值得单独回答。

首先,您应该编写一个脚本来创建适当的符号链接,尤其是当这些挂钩是关于执行策略或创建有用的通知时。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
于 2010-08-12T02:43:29.627 回答
124

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

于 2010-08-11T21:29:11.263 回答
98

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

git config --local core.hooksPath .githooks/

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

于 2019-01-20T22:08:32.343 回答
10

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

正如其他人在他们的回答中所说,如果您的钩子特定于您的特定项目,那么将它们包含在项目本身中,由 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,有一个名为Husky的依赖项,它允许您安装钩子,包括用 JavaScript 编写的钩子。

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

其他

此外,还有许多不同的钩子管理应用程序/插件,包括Python 项目的预提交、Ruby 项目的Overcommit以及 RubyNode.js项目的Lefthook

于 2018-10-17T09:16:58.483 回答
6

TEMPLATE DIRECTORY,您可以使用以下机制之一来更新每个新创建的 Git 存储库的.git/hooks目录:

模板目录包含创建后将被复制到 $GIT_DIR 的文件和目录。

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

  • --template选项给出的参数;

  • $GIT_TEMPLATE_DIR环境变量的内容;

  • init.templateDir配置变量;或者

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

于 2015-08-15T04:35:55.743 回答
3

pre-commit npm包可以优雅地处理这个问题,允许您在package.json文件中指定 pre-commit 钩子。

于 2017-09-26T20:07:53.127 回答
3

对于基于PHP 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在定期运行。

于 2019-08-03T00:57:23.977 回答
1

这是一个脚本add-git-hook.sh,您可以将其作为存储库中的常规文件提供,并且可以执行以将 Git 挂钩附加到脚本文件。调整使用哪个钩子(pre-commit、post-commit、pre-push 等)和 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 想要的。在下面的评论中,我对在存储库中交付钩子脚本而不是在外部管理它们的用例和论点发表了意见。

于 2018-11-18T02:21:25.990 回答
-1

您可以使用托管解决方案进行预提交挂钩管理,例如pre-commit。或者像Datree.io这样的服务器端 git-hooks 的集中式解决方案。

它具有内置策略,例如:

  1. 检测和防止机密合并
  2. 强制执行正确的Git 用户配置
  3. 强制Jira 票证集成- 在拉取请求名称/提交消息中提及票证编号。

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

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

于 2019-03-23T13:58:53.830 回答