我怎么能强制从prod用户提交--author <the_real_author>

sta*_*ant 4 git github bitbucket bitbucket-server

在我的工作场所中,我们使用git在Linux(centos 7风味)下进行版本控制。我们有用户ID,但也有一些我们可以模拟的产品ID。

因为我们很虚弱,所以我们允许提交产品ID并推送存储库,通常是出于实用性考虑,当我们热修复问题时。我们应该在这样做时使用--author,但我们有时会忘记。

使用特定的prod用户时,是否可以强制使用--author?

tor*_*rek 5

提交后,将永远无法更改。但是您确实可以选择不发送提交,还有另一个选择:拒绝接受提交。因此,这里有三个选择:

  • 始终正确地进行提交,方法是在将要进行的提交时进行一些检查,以确保正确执行了提交,否则将不会继续进行。例如,不要使用命令进行提交,而是git commit编写自己的程序。或者,编写一个预提交的挂钩并在那里进行检查,切勿绕过挂钩。

  • 发送前检查。如果您git push用于将提交从Git存储库A发送到Git存储库B,则发送 Git(Git A)将在给Git B打电话后但在将提交转移到Git B之前运行其预推钩子。这时,您可以在预推钩中检查提交:如果提交不是您喜欢的形式,请不要发送。

  • 在接收之前,请在预先接收或更新挂钩中进行检查。这需要对服务器本身进行操作。既然您提到了Bitbucket,请在服务器端挂钩上查看其页面。预先接收的钩子可以拒绝git push(整个事情);更新挂钩可以拒绝git push(一个名称更新)的一部分。

客户端挂钩-预提交和预推送-的优点是它们在您的控制之下。这也是它们的缺点:每个使用git commitgit push必须将钩子安装到自己的存储库中的人,这使他们有机会忘记安装钩子。他们可以故意绕过钩子或将其卸载。

服务器端挂钩的优势在于,没有客户端(即您的用户均无)可以意外或有意绕过它。服务器强制执行它。同样,这也是其缺点。实施完全取决于服务器,因此,除非您控制服务器-或控制服务器的人将这个权限委托给您- 否则您根本无法安装挂钩。

由于我不使用Bitbucket,因此我无法真正详细介绍如何对服务器端挂钩使用Bitbucket的客户端控制,但是如果您通读了我链接的页面并关注更多链接,则应该能够阅读有关如何使用他们提供的内容的信息。

编写一个预提交的钩子

预提交钩子相对简单:Git将在内部.git/hooks/查找名为的文件pre-commit。如果此文件存在并且可执行git commit将运行它。该文件只是一个程序,可以用您喜欢的任何语言编写:Python,Perl,sh / bash,C,C ++,Java,Go等。如果使用解释性语言编写,请确保操作系统的exec系统调用将调用解释器。也就是说,对于/bin/sh脚本,将文件的第一行读取为#! /bin/sh,以便exec系统调用可以直接运行它,然后运行chmod +x该文件。

程序的工作是检查将要提交的内容(例如,命令行选项,如果可以通过某种方式找出它们的内容),并且如果应允许提交,则以零(成功)状态退出,或者如果提交应被拒绝,则返回非零(例如1)退出状态。

对于您的特定情况,您在某种程度上很幸运:该钩子是 Git设置了Git GIT_AUTHOR_NAME和其他Git环境变量之后运行的(这是基于对Git 2.21的测试;请注意,默认的CentOS Git可能是古老的,因此请检查一下)您的Git版本,并验证它是否适用于您的版本,或者根据需要进行升级)。例如,这是我为了测试而编写的一个有点愚蠢的预提交钩子:

$ cat .git/hooks/pre-commit
#! /bin/sh
env | grep GIT | sed 's/@/ /'
exit 1
Run Code Online (Sandbox Code Playgroud)

在显示所有包含字符串的环境变量(并在我发布此内容后删除以减少垃圾邮件)之后,此pre-commit钩仅拒绝每次提交。所以现在(之后):GIT@chmod +x

$ git commit
GIT_EXEC_PATH=/usr/local/libexec/git-core
GIT_INDEX_FILE=.git/index
GIT_AUTHOR_NAME=Chris Torek
GIT_PREFIX=
GIT_AUTHOR_EMAIL=chris.torek gmail.com
GIT_AUTHOR_DATE= 1570904668 -0700
Run Code Online (Sandbox Code Playgroud)

要么:

$ git commit --author='A U Thor <thor@example.com>'
GIT_EXEC_PATH=/usr/local/libexec/git-core
GIT_INDEX_FILE=.git/index
GIT_AUTHOR_NAME=A U Thor
GIT_PREFIX=
GIT_AUTHOR_EMAIL=thor example.com
GIT_AUTHOR_DATE= 1570904927 -0700
Run Code Online (Sandbox Code Playgroud)

现在应该很清楚如何检查“作者”设置。您可以选择始终执行此操作,或者仅当id您说您以“产品用户”身份运行时才选择这样做(实际上这意味着什么)。

编写一个预推钩

预推钩子类似,但是它提交或多个提交存在之后发生。请注意,您无法更改提交,现在已经太晚了;用户必须丢弃任何错误的提交以支持新的和改进的替换,但是您可以 检查 Git即将发送的提交。

和以前一样,您的钩子可以用任何您喜欢的语言编写,尽管通常在这里最简单的是Shell脚本。它的工作是检查已经存在的提交,确认您是否愿意将它们发送到接收方Git,如果是,则退出0。如果预推送钩子退出非零值,则整个推送都将中止。

一个预推钩子在其标准输入上接收输入,而不是命令行参数,一次只接收一行。因此,您的钩子必须读取所有输入行。每行中有四个字符串,每个字符串之间隔开一个空格,并以换行符结尾(不返回回车符):

<local ref> SP <local sha1> SP <remote ref> SP <remote sha1> LF
Run Code Online (Sandbox Code Playgroud)

(如githooks文档中所述)。

不幸的是,在时git push,远程sha-1哈希ID可能在本地存储库中,也可能不在本地存储库中。如果不是,那么您唯一了解的是,如果您和另一个Git都允许推送完成,则远程引用会丢失一些提交。因此,在这种情况下,您可能要中止推送,因为只有在用户使用--force并且git push --force通常不希望这样做的情况下,推送才能成功。(如果用户确实需要强制执行此推操作,则他/她/他们/无论使用什么方法都可以git push --n-verify -f绕过预推钩子……或者,他们可以git fetch先运行,以便该提交在本地存在。)

确认远程的哈希ID在本地存在之后,您可以检查传出的提交(和/或要删除的提交),然后可以使用git rev-list获取此类提交的哈希ID。

作为一个完全未经测试的示例,请考虑以下shell脚本:

while read localref localhash remoteref remotehash; do
    case $remoteref in
    refs/heads/*)
        remotebranch=${localref#refs/heads/};;
    *)
        echo "pushing to non-branch $remoteref - not checking this one"
        continue;;
    esac
    if ! git rev-parse --quiet --verify $remotehash >/dev/null; then
        echo "push to branch $remotebranch aborted"
        echo "need commits from them; please run git fetch first"
        exit 1
    fi
    git rev-list $remotehash..$remotehash | while read hash; do
        if ! check-commit $hash; then
            echo "git push to branch $remotebranch aborted: commit $hash failed check"
            exit 1
        fi
    done
    n_removed=$(git rev-list --count $localhash..$remotehash)
    if [ $n_removed -ne 0 ]; then
        echo "warning: force push discards $n_removed commits from $remotebranch"
    fi
done
Run Code Online (Sandbox Code Playgroud)

如果此shell脚本片段正确(请记住,未经测试),它仍然需要您编写自己的shell函数check-commit。该函数应该检查将要发送的提交,并确保您愿意将其发送到另一个Git。

编写服务器端预接收钩子

如果您完全控制服务器Git,则可以编写自己的预接收钩子。与以前一样,它只是一个可执行程序,可以用您喜欢的任何语言编写,操作系统可以通过其exec系统调用来调用,该程序存储在名为的文件中.git/hooks/pre-receive

与上面的预推挂钩一样,预接收挂钩在其标准输入上以一系列行的形式获取其输入,每个请求的引用更新一次。您的工作是读取所有行,验证是否允许所有传入提交,如果允许,则退出零。如果某些提交应被拒绝,则只需退出非零即可。打印出您为什么拒绝提交的原因是一个非常好的主意,这样,无论运行的是谁,都可以看到您的输出(带有单词),以使他们可以知道为什么拒绝推送。但是,仅退出非零值将导致整个推送被拒绝。git pushremote:

编写服务器端更新挂钩

如果您完全控制服务器Git,则可以编写自己的更新挂钩。与以前一样,它只是一个可执行程序,可以用您喜欢的任何语言编写,操作系统可以通过其exec系统调用来调用,该程序存储在名为的文件中.git/hooks/update

更新挂钩接收其参数作为实际参数。参数的顺序与馈给预接收挂钩的行的顺序不同。有关详细信息,请查阅githooks文档。与预接收挂钩一样,您的工作是检查建议的参考更新,并退出0以允许该更新,或者退出非零值以拒绝该更新。与预接收挂钩不同,拒绝一个更新不会自动拒绝其他更新。像pre-receive钩子一样,打印一条有关为何拒绝更新的消息是一个很好的主意