将git钩子放入存储库


197

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

Answers:


143

我通常同意Scytale,并提供一些其他建议,足以值得单独回答。

首先,您应该编写一个脚本来创建适当的符号链接,尤其是在这些挂钩与执行策略或创建有用的通知有关的情况下。如果人们能够打字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

6
我添加chmod +x .git/hooks/*到您的bin/create-hook-symlinks 工作了。
guneysus 2014年

6
@guneysus您不需要,因为这些钩子应该已经是可执行的(应该以这种方式检查),并且链接不需要任何特殊权限,只需链接到它们的文件即可。
卡斯卡贝尔2014年

13
获取钩子目录的更好方法是HOOK_DIR=$(git rev-parse --show-toplevel)/.git/hooks
阿诺德·丹尼尔斯

2
我已经基于此构建了一个简单的系统来管理项目中的挂钩:ell.io/tt$Paws.js/blob/Master/Scripts/install-git-hooks.sh
ELLIOTTCABLE 2014年


111

不,将它们放入存储库中很好,我什至建议这样做(如果它们对其他人也有用)。用户必须显式地启用它们(如您所说的,例如通过符号链接),这一方面让人感到有些痛苦,但另一方面却可以保护用户免于未经他们的同意运行任意代码。


13
如果这是公司政策,该代码不是“任意”的,这是必需的代码,因此,由于没有另一个被跟踪的(预定义)目录,这也被认为是GIT的局限性,该目录也可以与常规钩子一起执行
Tobias Hagenbeek 2014年

14
自动交付挂钩是一个安全问题,我很高兴Git不会直接这样做-为了实施团队/公司策略,在服务器端使用挂钩,或者让用户手动决定启用它们,如@scy描述的那样:)
标记K Cowan

4
“保护用户未经他们的同意而运行任意代码”。如果开发人员愿意按照您的建议(符号链接)进行操作,则挂钩可能会被其他人更改,并运行“未经他们同意的任意代码”
MiniGod15

24
MiniGod:当然可以。如果您有足够的偏执狂,则可以复制这些钩子而不是对其进行符号链接,然后对其进行审核,然后再启用它们。但是,大多数(需要引用)Git存储库将包含要在用户计算机上运行的源代码,因此无论如何您都可能运行不断变化的未经审核的代码。但是,是的,你有意思。;)
scy 2015年

46

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

git config --local core.hooksPath .githooks/

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


3
我在viget.com/articles/two-way-to-share-git-hooks-with-your-team上找到的一个窍门是从Makefile / CMake配置/任何位置设置选项。
朱利叶斯·布林格

6

http://git-scm.com/docs/git-init#_template_directory中,您可以使用以下一种机制来更新每个新创建的git repo的.git / hooks目录:

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

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

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

  • $ GIT_TEMPLATE_DIR环境变量的内容;

  • init.templateDir配置变量;要么

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


5

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

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

我写了一篇有关管理git hook的文章,如果您有兴趣深入了解这一点。

Java和Maven

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

如果您正在使用Java项目的Maven处理构建管理,则以下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项目的过量提交和针对Ruby Node项目的Lefthook


1
感谢您创建此插件,它使集成我的预提交文件变得非常容易。
Michiel Bugher


1

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


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想要的东西。我选择了在仓库中运送钩子脚本的用例和参数,而不是在下面的评论中从外部进行管理。希望这就是您想要的。


我感谢您的努力,并且确实相信这里有有价值的信息-它不能回答所陈述的问题。
shabunc

我认为,如果挂钩是特定于特定存储库的,或者是所使用工作流的组成部分,那么它们将作为文件属于存储库。很难将它们放置在其他地方而不会产生超出其解决范围的问题。您可以将通用的钩子存储在它自己的存储库中或共享驱动器上,这可以使项目存储库保持干净整洁,但代价是实用性降低。我同意其他用户的看法,即挂钩必须易于添加。符号链接可能会导致对特定系统或文件结构的不必要依赖。
mathewguest '18

此外,符号链接使用户无法添加自己的挂钩。没有跟踪.git / hooks目录,因此源应从存储库中启动,并使其进入hooks脚本,而不是相反。我认为反驳是git钩子与工作流或团队而不是项目更相关,因此不属于存储库。根据您的特定用例,您是否可以通过不太相关的钩子潜在地污染git存储库,还是宁愿放弃将它们放置在其他地方的繁琐操作,还可以吗?
mathewguest

0

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

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

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

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


3
我认为您正在制作有趣的产品,但我也认为这不能回答问题,基本上是一种自我宣传,仅此而已。
shabunc
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.