我想在我们的 git 服务器中设置一个预接收挂钩来检查配置文件并在它无效时丢弃推送(我想根据分支名称检查某些令牌的存在)。但是我已经看到 preceive 钩子只接收 (old-rev, new-rev, refname) 的列表,而我发现检查文件内容的唯一方法是区分这些引用,这不是很舒服。
是否有捷径可寻?使用预提交挂钩会更容易,但我想在服务器中设置最后一道屏障。
在新对象(提交、带注释的标记对象、树和 blob)已加载到存储库中但在引用(分支名称、标记名称等)已更改之前调用预接收或更新挂钩。
这就是为什么pre-receive 钩子获取 ( old
, new
, ref
) 三元组列表的原因:现有 repo 具有对象,现有 ref(如果有)指向 SHA-1 为 的对象(通常是提交,有时是标记)old
。Git 提议将其更改为指向 SHA-1 所在的对象new
(或者如果这两者中的一个恰好是全零“空 SHA-1”,则创建或删除它)。
我发现检查文件内容的唯一方法是区分这些引用
这是一种方法,但您拥有一整套 git 命令来提取所有内容。例如,您可以在某处 ( ) 创建一个新的空目录,然后运行以在该路径中获取完整的树。(如果树很大,这可能需要一些时间。当然,您在其上运行的任何测试都需要更多时间。)mkdir path
git --work-tree=path checkout sha1
您必须准确地决定要检查的内容。这和您希望的一样复杂,但是对于分支名称(ref
形式为,其中是任何分支名称,即可能包含更多斜杠),请考虑 ref 更新可能会执行以下一项或多项操作(一些组合显然是不可能的):refs/heads/name
name
例如,如果我有一个裸仓库的克隆origin
并且我这样做:
git fetch origin # get up-to-date with origin
git checkout -b branch origin/branch # make tracking branch for origin/branch
git reset --hard HEAD~3 # back up 3 commits
echo more stuff >> existing_file # modify something
git commit -a -m 'add new text' # commit the change
git revert --no-edit HEAD # add another commit that undoes change
git push -f origin branch # and push
然后更新将删除三个提交并添加两个。如果您检查new
SHA-1(再次使用old
, new
,ref
三重符号),您将获得的树看起来与我要求推送的版本完全相同。如果树必须通过某些测试,大概是HEAD~3
确实通过了这些测试的版本,所以这个版本也可以。但是,我提交的添加一行的内容existing_file
可能无法通过测试,并且您可能不喜欢我删除了三个提交的事实。
因此,再次由您决定要检查什么,并编写代码来实现它。检查强制推送是否正在删除提交;允许或禁止这一点。检查是否正在创建新的分支名称;允许或禁止。检查分支名称是否被删除;允许或禁止。如果正在添加提交,请检查每个中间提交的树,或仅检查最终树;允许或禁止。添加的提交是否涉及合并?是否添加、删除或更改了标签?等等。
只是为了好玩,不久前我写了一个预接收 shell 脚本(在 POSIX 样式的 shell 中),它可以完成其中的许多工作(它不检查任何提交的内容)。我做了一些非常简单的测试,它似乎工作。它可以用作更彻底检查的起点。
但是,如果您正在认真检查,您可能需要考虑使用gitolite。