Git – 如何验证提交消息?

上次我为初学者写了GIT简介。这次我想解决一下GIT中的一些高级问题。我必须解决以下问题:所有提交消息都需要遵循一些特定的规则(行的最大长度等),如果提交消息不满足这些规则,则不应该提交任何提交。

我认为应该有一个简单的解决方案来解决这个问题,并且很多人已经解决了这个问题,因为几个项目需要验证提交消息。事实上,这并不容易。让我来描述一下原因

Git提交钩子

在GIT中,您可以指定所谓的提交挂钩。这些是在特定操作的情况下调用的脚本。存在在“客户端”端运行的提交钩子和在“服务器”端运行的钩子。我正在使用引号,因为我们在GIT中知道服务器和客户端repos没有指定的角色,每个repo都可以表现为服务器和客户端。您可以在git repo中的.git / hooks下找到所有这些提交挂钩。

有一个名为commit-msg的提交钩子,这正是我们所需要的。如果您正在调用git commit命令,则调用此脚本,它将提交消息作为输入参数,如果它不返回0,则将丢弃提交。听起来真的很棒。在“客户端”repo上提交时,此脚本运行的唯一问题。这意味着如果客户端,即克隆服务器repo的客户端,正从repo的.git / hooks文件夹中删除此提交挂钩,他将能够提交他想要的任何内容。所以这作为第一次检查是好的,但仍然没有以安全的方式解决问题。此外,commit_hooks不受版本控制,因此您需要找到另一种方法(可能通过一些额外的脚本)将它们复制到客户端repos。或者,您可以在hooks文件夹和版本控制文件夹之间创建符号链接。

如果我们想百分之百确定服务器仓库中不会出现无效的提交消息,我们需要在服务器端进行检查。

对于服务器端的检查,一种可能性是使用commit hook。只要有人将某些东西推送到服务器并且如果它具有非零返回值,就会调用此提交钩子,推送将被拒绝。

唯一的问题是这个提交钩子没有明确的输入,说明已经推送了哪些确切的提交。它可以从标准输入读取它的输入,它只包含以下格式的git引用的更改:旧值新值引用名称。

如何弄清楚哪些是新的提交?

首先深入了解git并了解参考资料。

Git分支和引用

当你在git中推送提交时,你总是在推动分支。默认情况下,您在主分支上,但您可以随时创建从现有分支分支出来的新分支。如果你正在进行git推送,它会将你的分支推送到其上游分支(如果存在)。如果从服务器获取分支,则会自动设置其上游分支。上游分支始终是服务器上的分支。如果上游分支不存在或者你处于分离头模式(你不在任何分支上,你的头只是指向一个随机提交)git将要求你指定你推动哪个分支(如git push origin)主)。

我们现在退一步吧。什么是git ref? git ref就像是指向存储库中特定提交的命名指针。您可以在.git / ref目录下找到所有引用。分支只不过是特殊的引用。它们也只是一个指向提交的指针,但是如果你向提交提交新内容,分支将自动更改为指向分支上的最新提交。但它只是一个命名指针,没有别的。

git push会发生什么?

提交不太了解。他们知道自己的内容和父母的提交。在合并提交的情况下,提交具有多个父级,否则只有一个。回购中的第一个“根”提交根本没有父级。

因此,如果你正在调用git push,你总是推动一个或多个(通过使用git push –all)braches。您首先要告知服务器该分支指向的新提交。这是您作为预接收提交挂钩的输入所获得的值。推送提交挂钩还检查服务器上是否已存在分支,如果是,则允许预接收挂钩知道其先前的内容是什么。

然后服务器检查它是否已经有提交(提交存储在.git / objects下)。如果没有,那么它将从客户端获取提交并检查其父级是什么。如果父服务器不在服务器上,则父提交也将移动到服务器。它一直持续到服务器上的第一个父提交。

如何弄清楚提交的预接收挂钩是新的?

最大的成就是预接收挂钩只告诉我们哪些引用已被更改为什么,没有别的。我们的目标是验证所有新推送的提交消息,但没有别的。

第一个也是最简单的情况,如果有人推送提交到之前已存在的分支。在这种情况下,我们获取引用的旧值和它的新值,并使用git log old_hash..new_hash,我们将看到它们之间的提交。

当这个方法显示的提交次数超过必要时,有一个极端情况:在合并提交的情况下,它显示合并分支的整个内容,但是可能已经至少部分地推送了该分支。

我还需要提到删除引用(或分支)时的情况。在这种情况下,新散列将是40次0,但这也意味着不需要验证提交消息。

最后一个案例是推送新分支的时候。在这种情况下,引用的旧散列是零的40倍,并且我们有引用的新散列。这意味着我们只有分支上最新提交的哈希值。知道什么?经过一番调查后,我的想法是和推进一样。检查最新提交,然后跳转到其父提交,如果合并提交对所有父项执行相同操作并停止此活动,我们在之前已推送的分支上达到提交。

这个想法听起来不错,但是如何确定服务器上是否已经存在提交。肯定有多种解决方案,但我花了一些时间找到一个正常工作的解决方案。

我的解决方案是git branch –contains此命令返回有关其历史记录中包含特定提交的分支的列表。但要注意由于git仅存储对分支上最新提交的引用,因此作为此提交的祖先的所有提交都在此分支上。因此,如果我从主分支的某个点开始分支,那么在我的分支之前的主分支上的所有提交也是我的分支的一部分。还有一点需要注意:客户端上的分支和服务器上的分支不一样,这将是我们任务的解决方案。

根据我的经验,服务器上的所有提交至少属于一个分支,因为无法推送分离的提交。在更改引用之前调用预接收提交挂钩。这意味着之前未推送的所有提交都不是任何当前存在的分支的一部分,但是已经存在的所有提交都是至少一个分支的一部分。这是我们可以在这里使用的事实。

摘要

让我总结一下在服务器端提交钩子上检查git commit消息的解决方案。

从分支的最新提交开始,按父进行父对象检查这个git分支–contains是否返回一个空列表。如果是这样验证其提交消息并检查其父级,如果没有,则此提交已经被推送过,我们在此分支上没有其他任何操作。特别注意合并提交,检查每个父母。

我希望这个解决方案是正确的,直到现在它通过了所有测试用例,我也希望它能帮助你解决你的任务。

资讯来源:由0x资讯编译自DEV,原文:https://dev.to/rlxdprogrammer/git-how-to-validate-commit-messages-55m5 ,版权归作者所有,未经许可,不得转载
你可能还喜欢