Git 远程/共享预提交钩子

使用一个官方存储库作为远程存储库,并从中克隆多个本地存储库,预提交钩子能够在该主存储库上编写脚本并在所有克隆的存储库上执行吗?

34514 次浏览

预提交钩子是否可以在该主存储库上编写脚本,并在其所有克隆上执行?

来自 githooks(5):

pre-commit
This hook is invoked by git commit, and can be bypassed with
--no-verify option.

因为钩子很容易被绕过,所以你的问题的答案似乎是“不”。

还有,自从。Git/hooks 目录没有被克隆,似乎没有将其推送到客户机的机制。

我不这么认为,因为钩子不是克隆的。
如果钩子脚本本身已经进行了版本控制,那么可以在克隆服务器中链接到(符号链接)(如果他们的操作系统支持该链接特性的话)。

或者,如果钩子是用于创建克隆的 Git 模板目录的一部分(这只能确保它们在克隆回购中的存在,不能保证它们实际上被使用和执行)。

但是我不认为有任何“中心”方式来强制执行提交。


正如杰夫罗米在评论中更清楚地解释的那样(强调我的观点) :

我认为它实际上违背了 git 存储库将强制挂钩与回购一起分发的想法。
我的克隆是我的存储库。我应该能够使用 git,无论我喜欢它,包括选择是否运行钩子。
(从安全的角度来看,这真的有点吓人——没有人应该有能力在我运行某些 git 命令时强迫我执行某些脚本。)

我同意这种说法,并且只看到了在给定的专门回购中执行本地应用规则的方法。
例如,你不会直接推到中央回购,但会首先推到一个质量保证回购,将接受你的提交,只有当它遵循某些规则。如果是这样,那么质量保证回购将推动您对中央回购的承诺。

另一个直接来源于我刚才提到的例子是“ 与 Git 的无服务器连续集成”,一种强制 本地私有构建的方法,在将它们推到任何地方之前都可以工作。

你不能强制预提交钩子 在人们的本地仓库,但在你的中央回购你仍然可以运行预接收钩子。

ExI 需要确保提交消息遵守某些规则(用于 trac 集成等) 所以我使用了下面的 pre-Receivehook,它检查被推送到中央存储库的每个提交消息,如果没有受到良好格式的保护,它将拒绝这个推送。

#!/bin/sh
while read rev_old rev_new ref
do
MALFORMED="$(git rev-list --oneline $rev_old..$rev_new | egrep -v '#[0-9]+' |  awk '{print $1}' )"
if [ x"$MALFORMED" != x ]
then
echo Invallid commit message on $MALFORMED
exit 1
fi
done


欲了解更多信息,请参见 f.exhttps://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks

假设您的 git repo 中有源代码,并且有一个与之相关的构建系统,那么您可以将构建系统配置为设置 pre-commit 钩子,也就是说,通过移动或链接一个已经版本化的 pre-commit 钩子。

我还没有试过这个,我来这里是为了找到一个更好的解决方案。

两个选择:

1. 使用哈士奇

如果您正在编写 JavaScript ,最好的方法是使用 Husky。Husky 有一个 postInstall 脚本,可以设置和管理你的 githooks。然后,您可以在 package.json 或者 husky dotfile 中配置 precommit 和 prepush 脚本。

你可以用它来运行任意的脚本。我通常 yarn lintyarn test预推。

2. 在 git.config 中设置 core/hooksPath,然后在回购中包含/hook

如果你不使用 JavaScript ,或者你不能使用 Husky,你可以在开发者机器上克隆提交钩子并将它们签入回购协议,但是你不能强迫开发者运行它们。

要检入挂钩,请在回购文件中创建一个 hooks目录。然后将您的钩子放在那里,而不是通常的 .git/hooks目录。这是你可以强制执行的部分。

另一部分取决于开发人员的好感。要将挂钩文件夹设置为 hooksPath,每个开发人员必须运行:

git config core.hooksPath hooks

现在钩子文件夹中的所有钩子都将按预期运行。

我创建了一个新文件: pre-commit-hook.sh

#!/usr/bin/env bash
CHANGES=$(git whatchanged ..origin)


if [ ! -z "${CHANGES}" ]; then
echo "There are changes in remote repository. Please pull from remote branch first."
exit 1;
fi


exit 0;

这就是我对 Git 的承诺:

bash pre-commit-hook.sh && git commit -m "<Commit message>"

非常 非常的老答案在这里。这是绝对可能的这些天。

从 Git 2.9左右开始,配置 core.hooksPath就可以使用了:

core.hooksPath

默认情况下,Git 将在 $GIT_DIR/hooks目录中查找钩子。将其设置为不同的路径,例如 /etc/git/hooks,Git 将尝试在该目录中查找钩子,例如 /etc/git/hooks/pre-receive而不是 $GIT_DIR/hooks/pre-receive

路径可以是绝对的,也可以是相对的。相对路径被视为相对于运行挂钩的目录(参见 Githooks [5]的“ DESCRIPTION”部分)。

如果您希望集中配置 Git 钩子,而不是在每个存储库的基础上配置它们,或者作为更加灵活和集中的 init.templateDir替代方案(在 init.templateDir中更改了默认钩子) ,那么这个配置变量非常有用。

这意味着你可以在客户端机器之间共享 Git 挂钩(可能使用项目中的非 .git文件夹,或者使用本地克隆的专用 Git 存储库,或者使用同步软件,如 OneDrive 或 Dropbox) ,只需将 core.hooksPath配置设置为该(共享)文件夹。