将 Git 挂钩放入存储库

发布于 2024-09-14 07:14:24 字数 87 浏览 5 评论 0 原文

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

Is it considered to be a bad practice - to put .git/hooks into the projects repository (using symlinks, for example). If yes, what is the best way to deliver same hooks to different Git users?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

ㄖ落Θ余辉 2024-09-21 07:14:24

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

git config --local core.hooksPath .githooks/

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

Nowadays you can do the following to set a directory that is under version control to be your Git hooks directory, e.g., MY_REPO_DIR/.githooks would be

git config --local core.hooksPath .githooks/

It is still not directly enforceable but, if you add a note in your README (or whatever), this requires a minimum of effort on each developer's part.

缺⑴份安定 2024-09-21 07:14:24

我总体上同意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"
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

I generally agree with Scy, with a couple of additional suggestions, enough that it's worth a separate answer.

First, you should write a script which creates the appropriate symlinks, especially if these hooks are about enforcing policy or creating useful notifications. People will be much more likely to use the hooks if they can just type bin/create-hook-symlinks than if they have to do it themselves.

Second, directly symlinking hooks prevents users from adding in their own personal hooks. For example, I rather like the sample pre-commit hook which makes sure I don't have any white space errors. A great way around this is to drop in a hook wrapper script in your repository, and symlink all of the hooks to it.

The wrapper can then examine $0 (assuming it's a Bash script; an equivalent like argv[0] otherwise) to figure out which hook it was invoked as, then invoke the appropriate hook within your repository, as well as the appropriate user's hook, which will have to be renamed, passing all the arguments to each. Quick example:

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

The installation script would move all pre-existing hooks to the side (append .local to their names), and symlink all known hook names to the above script:

#!/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"
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
情何以堪。 2024-09-21 07:14:24

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

No, putting them into the repository is fine. I’d even suggest doing so (if they are useful for others as well). The user has to explicitly enable them (as you said, for example, by symlinking), which is on one hand a bit of a pain, but it protects users on the other hand from running arbitrary code without their consent.

2024-09-21 07:14:24

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

正如其他人在回答中所述,如果您的挂钩特定于您的特定项目,那么将它们包含在由 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>

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

JavaScript 和NPM

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

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

其他

此外,还有许多不同的挂钩管理应用程序/插件,包括 预提交对于 Python 项目,过度提交 对于 Ruby 项目,以及 Leftthook for Ruby Node.js 项目。

Store in the project and install in the build

As others state in their answer, if your hooks are specific for your particular projects then include them in the project itself, managed by Git. I would take this even further and say that, given that it is good practice to have your project build using a single script or command, your hooks should be installed during the build.

I wrote an article about managing Git hooks, if you are interested in reading about this in a little more depth.

Java & Maven

Full disclosure; I wrote the Maven plugin described below.

If you are handling build management with Maven for your Java projects, the following Maven plugin handles installing hooks from a location in your project.

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

Put all your Git hooks in a directory in your project, and then configure your pom.xml to include the following plugin declaration, goal, and configuration.

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

When you run your project build, the plugin will configure Git to run hooks out of the directory specified. This will effectively set up the hooks in that directory for everyone working on your project.

JavaScript & NPM

For NPM there is a dependency called Husky which allows you to install hooks including ones written in JavaScript.

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

Others

Additionally, there are a number of different hook management applications/plugins including pre-commit for Python projects, Overcommit for Ruby projects, and Lefthook for Ruby or Node.js projects.

淡淡绿茶香 2024-09-21 07:14:24

模板目录,您可以使用以下之一这些机制用于更新每个新创建的 Git 存储库的 .git/hooks 目录:

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

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

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

  • $GIT_TEMPLATE_DIR 环境变量的内容;

  • init.templateDir 配置变量;或

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

From TEMPLATE DIRECTORY, you could use one of these mechanisms to update the .git/hooks directory of each newly created Git repository:

The template directory contains files and directories that will be
copied to the $GIT_DIR after it is created.

The template directory will be one of the following (in order):

  • the argument given with the --template option;

  • the contents of the $GIT_TEMPLATE_DIR environment variable;

  • the init.templateDir configuration variable; or

  • the default template directory: /usr/share/git-core/templates.

内心激荡 2024-09-21 07:14:24

对于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);\"",
     ],

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

For PHP Composer-based PHP projects, you can automatically distribute to engineers. Here is an example for pre-commit and commit-msg hooks.

Create a hooks folder, and then in your composer.json file:

 },
 "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);\"",
     ],

Then you can even update them as the project continues as everyone is running composer install on a regular basis.

吖咩 2024-09-21 07:14:24

预提交 npm 包可以优雅地处理这个问题,允许您在 package.json 中指定预提交钩子 em> 文件。

The pre-commit npm package handles this elegantly, allowing you to specify pre-commit hooks in your package.json file.

抱着落日 2024-09-21 07:14:24

这是一个脚本 add-git-hook.sh,您可以将其作为存储库中的常规文件发送,并且可以执行该脚本以将 Git 挂钩附加到脚本文件。调整要使用的钩子(预提交、后提交、预推送等)以及 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想要的问题。我在下面的评论中对在存储库中传送钩子脚本与在外部管理它们的用例和参数发表了意见。

Here's a script, add-git-hook.sh, which you can ship as a regular file in the repository and can be executed to append the Git hook to the script file. Adjust which hook to use (pre-commit, post-commit, pre-push, etc.) and the definition of the hook in the 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

This script might make sense to have executable permissions or the user can run it directly. I used this to automatically git-pull on other machines after I committed.

I answered the easier question which wasn't what was asked and wasn't what the OP was looking for. I opined on the use cases and arguments for shipping hook scripts in the repository versus managing them externally in the comments below.

和我恋爱吧 2024-09-21 07:14:24

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

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

Looks like a lot of the posts are out of date, at least if you're using pre-commit in the python ecosystem (+ I found that changing the git hook path fails with slightly older versions of git, e.g. 2.3). With a .pre-commit-config.yaml in a hooks dir in the root of your repo, the easiest solution is to run:

pre-commit install -f --config hooks/.pre-commit-config.yaml
兮子 2024-09-21 07:14:24

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

它具有内置策略,例如:

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

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

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

You could use a managed solution for pre-commit hook management like pre-commit.
Or a centralized solution for server-side git-hooks like Datree.io.

It has built-in policies like:

  1. Detect and prevent merging of secrets.
  2. Enforce proper Git user configuration.
  3. Enforce Jira ticket integration - mention ticket number in pull request name / commit message.

It won't replace all of your hooks, but it might help your developers with the most obvious ones without the configuration hell of installing the hooks on every developer's computer/repository.

Disclaimer: I am one of Datrees founders

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文