将git钩子放入存储库

sha*_*unc 189 git hook githooks

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

Cas*_*bel 138

我通常同意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
Run Code Online (Sandbox Code Playgroud)

安装脚本会将所有预先存在的钩子移到一边(附加.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
Run Code Online (Sandbox Code Playgroud)

  • 获取hook目录的更好方法是`HOOK_DIR = $(git rev-parse --show-toplevel)/ .git/hooks`. (13认同)
  • 我将`chmod + x .git/hooks/*`添加到你的`bin/create-hook-symlinks`来实现它. (6认同)
  • @guneysus您不应该需要它,因为钩子应该已经是可执行的(它们应该以这种方式检查)并且链接不需要任何特殊权限,只需要链接到的文件. (6认同)
  • 我只拿了必需品并把它放在回购中https://github.com/sjungwirth/githooks (6认同)
  • 我已经把基于这个简单的系统在我的项目管理挂钩:http://ell.io/tt$Paws.js/blob/Master/Scripts/install-git-hooks.sh (2认同)
  • 通过在重命名时测试文件 (-f) 而不是可执行文件 (-x),可以轻松避免覆盖旧 git 示例文件(或者可能是用户拥有禁用的挂钩!)的风险。无论如何,包装器都会在调用时测试可执行文件,这是测试这一点的最明智的时间。 (2认同)

scy*_*scy 108

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

  • MiniGod:当然.如果你有足够的偏执,你可以复制钩子而不是对它们进行符号化,然后审核它们,然后才启用它们.但是,大多数(需要引用)Git存储库将包含要在用户机器上运行的源代码,因此您可能会运行不断变化的,未经审计的代码.但是,是的,你有一个观点.;) (24认同)
  • 自动发送挂钩是一个安全问题,我很高兴Git不直接执行 - 强制执行团队/公司策略,在服务器端使用挂钩或让用户手动决定启用它们@scy描述:) (13认同)
  • 如果它是公司政策的话,那么代码不是"任意的"这是必需的代码,所以这将被视为GIT的限制,因为没有另一个(预定义的)目录,它被跟踪,这也得到了与常规钩子一起执行 (12认同)
  • "保护用户在未经他们同意的情况下运行任意代码".如果开发人员会像你建议的那样(符号链接),那么其他人就可以更改钩子,并在未经他人同意的情况下运行"任意代码" (4认同)

bba*_*ker 29

现在,你可以做以下设置的一个目录版本控制下的混帐挂钩目录,例如,MY_REPO_DIR/.githooks

git config --local core.hooksPath .githooks/
Run Code Online (Sandbox Code Playgroud)

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

  • 我在https://www.viget.com/articles/two-ways-to-share-git-hooks-with-your-team/上找到的一个窍门是从Makefile / CMake config /进行设置。 (2认同)
  • 请注意,这只适用于 2.9.0 以上的 git 版本。在发帖时这还不是“事情”。 (2认同)

Rud*_*haw 9

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

正如其他人在他们的回答中所述,如果您的挂钩特定于您的特定项目,则将它们包含在由 git 管理的项目本身中。我会更进一步说,鉴于使用单个脚本或命令构建项目是一种很好的做法,因此应该在构建过程中安装钩子。

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

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>
Run Code Online (Sandbox Code Playgroud)

当您运行项目构建时,插件将配置 git 以在指定目录外运行钩子。这将有效地在该目录中为从事项目的每个人设置挂钩。

JavaScript 和 NPM

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

// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "npm test",
      "pre-push": "npm test",
      "...": "..."
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

其他

此外,有许多不同的钩的管理应用程序/插件包括预提交用于Python项目,过量使用用于Ruby项目,和Lefthook为Ruby节点项目。


Dav*_*idN 6

http://git-scm.com/docs/git-init#_template_directory,您可以使用这些机制之一来更新每个新创建的git仓库的.git/hooks目录:

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

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

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

  • $ GIT_TEMPLATE_DIR环境变量的内容;

  • init.templateDir配置变量; 要么

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


Eli*_*ynn 5

对于基于PHP Composer的 PHP 项目,您可以自动分发给工程师。这是预提交和提交消息挂钩的示例。

创建一个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);\"",
     ],
Run Code Online (Sandbox Code Playgroud)

然后,您甚至可以随着项目的继续进行而更新它们,因为每个人都composer install在定期运行。