Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Git:预接收钩子,只允许合并,不允许直接提交到主服务器_Git_Git Merge_Githooks_Git Commit - Fatal编程技术网

Git:预接收钩子,只允许合并,不允许直接提交到主服务器

Git:预接收钩子,只允许合并,不允许直接提交到主服务器,git,git-merge,githooks,git-commit,Git,Git Merge,Githooks,Git Commit,我在git远程分支上创建预接收钩子时遇到了一个问题,我想怎么做就怎么做 有什么问题吗? 不允许直接提交到主分支。只允许合并到主分支中 解决方案 到目前为止,我的解决方案是检查来自用户的推送是否有变化,主推送是否受到影响。但问题是,我无法区分更改是直接提交还是合并 #!/bin/sh while read oldrefid newrefid refname do if [ "$refname" = "refs/heads/master" ]; then echo $(git mer

我在git远程分支上创建
预接收
钩子时遇到了一个问题,我想怎么做就怎么做

有什么问题吗?

不允许直接提交到主分支。只允许合并到主分支中

解决方案

到目前为止,我的解决方案是检查来自用户的推送是否有变化,主推送是否受到影响。但问题是,我无法区分更改是直接提交还是合并

#!/bin/sh
while read oldrefid newrefid refname
do
if [ "$refname" = "refs/heads/master" ]; then
        echo $(git merge-base $oldrefid $newrefid)
        echo "---- Direct commit to master branch is not allowed ----"
        echo "Changes only with a merge from another branch"
        exit 1
fi
done
有人知道如何检查更改是否为合并吗


谢谢大家!

在预接收钩子中得到的是分支的上一个和新的提示,因此您必须检查已添加的提交列表,并查看是否有任何提交不是合并:

nonmerges=$(git rev-list --no-merges --first-parent $oldrefid..$newrefid | wc -l)
[ "$nonmerges" -eq 0 ] && exit 0
--第一个父级
将输出限制为从主线提交,即跳过合并到的提交(可通过第二个/第三个/…父级访问)


可能的复杂性:快进合并(很难与一系列正常提交区分)。

这里有一个简短的答案:看看由以下内容生成的值:

git rev-list --count --max-parents=1 $oldrefid..$newrefid
你希望这是零。请继续阅读解释(和注意事项)


您的循环具有正确的轮廓:

  • 读取所有ref更新
  • 对于那些更新您关心的分支(或其他引用)的分支,请执行一些检查
诀窍在于执行检查。考虑您接收到的另外两条信息,即旧的和新的SHA-1 ID,并且在这些钩子中,这两个SHA-1 ID中的一个(但不是两者)都是“代码>0 < /代码> s(意味着REF正在被创建或删除)。 要坚持更改不是创建或删除,您的测试应该确保SHA-1都不是全零。(如果您愿意假设只需要检查删除,您可以检查新的SHA-1是否全部为零。但如果可能发生创建,则仅当
分支最终以某种方式被删除时才会发生这种情况,例如,有人登录服务器接收推送,然后手动删除它,您仍然需要确保旧的SHA-1在最终测试中不全为零。显然,这种删除是可能的,问题是您是否要编写代码来处理这种情况。)

在任何情况下,最典型的推送都只是更新引用。请注意,任何新提交都已写入存储库(如果拒绝推送,它们将被垃圾收集),因此此时您的任务是:

  • 查找并验证引用用于命名的、它将不再命名的任何提交(这些提交将被非快进推送删除);及
  • 查找并验证引用现在将命名的、它不用于命名的任何提交(这些是推送将添加的新提交,无论是否快进:请记住,新推送可以在添加一个或多个提交的同时删除一个或多个提交)
要找到这两组提交,应该使用
git rev list
,因为这正是它的工作:生成由某个表达式指定的SHA-1列表。这里需要的两个表达式是“所有提交ID都可以从一个版本中找到,而这些ID还不能从其他ID中找到”。在
git rev list
术语中,这些术语是
git rev list$r1^$r2
,1或相当于
git rev list$r2..$r1
,用于两个版本说明符
$r1
$r2
。当然,这两个revspec只是建议的
push
的新旧ID

这两个ID的顺序决定了哪个提交集
git rev list
列出:对于快进操作,将被删除的提交集为空,将被添加的提交集为空


在这种特殊情况下,您的目标不是生成这些提交列表(尽管这样做可行),而是从这些列表中选择一些内容

您可能希望防止提交删除(即,即使执行
push
的用户指定了强制标志,也要强制快进)。在这种情况下,只需验证“待删除”列表是否为空就足够了。您可以通过确保列表实际上是空的,或者在具有
git rev list
的shell脚本中更简单,为您计算它们并检查结果是否为零

您肯定希望防止非合并的添加,但允许合并的添加。在这种情况下,添加
--max parents=1
(也可以拼写为
--no merges
)会告诉
git rev list
禁止具有两个或多个父级的提交,即合并。添加
--count
可获得满足此“非合并,因为零或一个父项”约束的提交计数。如果此计数为零,则根据定义,添加的任何提交都必须是合并

因此:

n=$(git rev-list --count --max-parents=1 $oldrefid..$newrefid)
if [ $n -gt 0 ]; then
    echo "disallowed: push adds $n non-merge commit(s)" 1>&2
    exit 1
fi
例如,将足以强制执行此特定约束


1您可以编写
git rev list$r1--not$r2
:不同之处在于
--not
的效果仍然存在,因此如果您要添加另一个修订ID
$r3
--not
将应用于
r3
。也就是说,
git rev list A^B C
表示
yes-A、not-B、yes-C
A--not B C
表示
yes-A、not-B、not-C
。请注意,在
rev list
语法中,
B..A
意味着
A^B
,也就是说,
B
完全是反向的。

“快进合并(很难与一系列正常的提交进行区分)”AFAIK无法区分一系列提交和快进合并。它只是我们合并到的分支的一个更新,用于提交所讨论的内容。@Zeeker您可以使用-g