Git 远程/共享 pre-commit 钩子

81

一个官方代码仓库作为远程仓库,多个本地代码仓库从它克隆而来,能否在主仓库上编写并执行预提交钩子,并将其强制应用于所有克隆仓库?


5
如果您需要“执行”,请在中央仓库中使用更新钩子。如果钩子正在进行每个提交的验证,您仍然可以提供一个预提交钩子;开发人员很可能会自愿采用它,这样他们就可以立即发现自己做错了什么,而不必等到推送时才发现。 - Cascabel
1
可能重复:(https://dev59.com/FHA75IYBdhLWcg3wH1RB)和(https://dev59.com/snRC5IYBdhLWcg3wCMrX)。 - blong
8个回答

55
我不这么认为,因为钩子没有被克隆。
也许如果该钩子脚本本身被版本化,然后在克隆服务器中链接到(符号链接)(前提是它们的操作系统支持该链接功能),那么可能会有所改善。

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

但我认为没有任何“集中”的方法来强制执行提交。


正如Jefromi在评论中更清楚地解释的那样(重点是我的):

我认为,强制分发存储库的挂钩真的违反了git存储库的思想。
我的克隆是我的存储库。我应该能够根据自己的喜好使用它上面的git,包括选择是否运行挂钩。
(从安全角度来看,这将非常可怕 - 没有人应该有能力强制我在运行某些git命令时执行某些脚本。)

我同意这个评论,并且只看到了在给定的专业存储库中强制实施规则的方法。
例如,您不会直接推送到中央存储库,而是首先推送到QA存储库,只有在遵循某些规则的情况下,QA存储库才会接受您的提交。如果是这样,则QA存储库将推送您的提交到中央存储库。

另一个直接来源于我刚才提到的例子的插图是 "Serverless Continuous Integration with Git",这是一种在任何地方推送之前强制执行本地私有构建的方法。


9
我认为在git仓库中强制分发钩子(hooks)与git仓库的理念相悖。我的克隆(clone)是我的仓库。我应该可以按照自己的意愿使用它,包括选择是否运行钩子。从安全的角度来看,这将会是一件非常恐怖的事情 - 没有人应该有能力强迫我在运行某些git命令时执行特定的脚本。 - Cascabel
1
@Jefromi:你知道什么很可怕吗?当我在输入评论之前,开始输入“add...”,我的电脑上的FireFox确实建议我:“添加Jefromi的评论”。显然这不是我第一次遇到这种情况了 ;) - VonC
备忘录:另请参阅https://dev59.com/O3A75IYBdhLWcg3wlqSh#3209767。 - VonC
支持符号链接提案。只需确保至少一个钩子更新符号链接,所有用户只需运行一次即可。它仍然是可选的 - 但钩子是有版本控制的 :-) 只适用于某些类型的环境。 - WhyNotHugo

10
你不能强制在别人的本地仓库上使用 pre-commit hook,但是在你的中央仓库中,你仍然可以运行 pre-receive hook。 例如,我需要确保提交信息遵守特定规则(用于 trac 集成等),因此我使用了以下 pre-receive hook,它检查被推送到中央仓库的每个提交消息,并且如果不符合规范,则会拒绝推送。
#!/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

更多信息请参见 https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks

9

两种选择:

1. 使用Husky

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

您可以使用此选项来运行任意脚本。 我通常会使用yarn lintyarn test prepush。

2. 在git.config中设置core/hooksPath,然后在存储库中包含/hooks

如果您没有使用JavaScript,或者您无法使用Husky,则可以将提交挂钩克隆到开发人员机器上并将其检入存储库,但您无法强制开发人员运行它们。

要检入钩子,请在存储库的某个位置创建一个hooks目录。 然后,将您的挂钩放在那里而不是通常的.git/hooks目录中。 这部分是您可以强制执行的。

另一部分取决于开发人员的良心。 每个开发者都必须运行以下命令才能将您的挂钩文件夹设置为hooksPath:

git config core.hooksPath hooks

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


1
不需要大声喊出“是”或“否”。请不要过度格式化以引起注意。话说回来,有一个问题:git配置core.hooksPath可以在post-checkout钩子中设置吗?这样,它将在克隆后运行。 - MS Berends

6

能否在主代码库上编写一个pre-commit hook,并强制执行所有克隆的副本?

来自githooks(5)

    pre-commit
      此挂钩由git commit调用,并可使用--no-verify选项绕过。

由于该挂钩可以轻松绕过,因此似乎答案是否定的。

另外,由于.git/hooks目录未被克隆,因此似乎没有将其推送到客户端的机制。


3

这里的答案很老旧。如今,这绝对是可行的。

自Git 2.9以来,配置core.hooksPath已经可用。根据git文档

core.hooksPath

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

路径可以是绝对或相对的。相对路径被视为相对于运行钩子的目录(请参见githooks[5]的“描述”部分)。

在以下情况下,此配置变量非常有用:您希望集中配置Git钩子,而不是按存储库进行配置;或者作为init.templateDir的更灵活和集中的替代方案,在那里您已更改了默认钩子。

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


但这将需要每个开发人员设置正确的“hooksPath”,这与以前并没有太大区别。 - Christian Vincenzo Traina
是的,没错。现在相关文件都被维护并存储在一个地方,每个开发者只需复制即可。 - MS Berends
同意@ChristianVincenzoTraina的观点。要求用户运行ln -s ../../hooks/pre-commit.sh .git/hooks/pre-commit(据我所知,这一直是可能的)和git config core.hooksPath hooks/之间没有太大区别。用户仍然需要知道他们需要设置它。 - Alexander Klimetschek
由于符号链接在Windows上不受支持,因此git config是可行的。 - MS Berends
Windows支持符号链接。@MSBerends - Dennis

2
假设您的git仓库中有与之关联的构建系统源代码,则可以配置构建系统以设置pre-commit钩子,即通过移动或链接一个被版本控制的pre-commit钩子来实现。
我还没有尝试过这种方法。我在谷歌搜索更好的解决方案时来到了这里。

0

这并不是完全自动化的,但你可以为一个存储库添加钩子脚本,放在一个名为hooks/的目录中,并将其添加到git中。然后要求开发人员在克隆存储库后创建钩子脚本的符号链接:

ln -s ../../hooks/pre-commit.sh .git/hooks/pre-commit

在项目的 README 文件中记录可能已经足够好了。


-2
我创建了一个新文件: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>"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接