繁体   English   中英

预接收钩中的差异

[英]diff in pre-receive hook

我用Python编写了一个简单的服务器端git pre-receive钩子。 目标是分析差异和拒绝包含某些我们认为无效的文本的推送。 我使用以下命令集编写了钩子:

git ls-tree
git diff --name-only
git cat-file 

但是我只是注意到我正在扫描作为提交一部分推送的整个文件。 但是我只想扫描差异,即在此推送中更改的行。

这样做的原因是一些无效的文本可能是误报,并且可以。 可以用力推动。 但是,如果再次编辑同一文件并添加有效文本,则推送将被拒绝,因为该文件以前具有无效文本。 每次编辑文件时都会发生这种情况,这很烦人

因此,基本上的问题是,如何仅在当前推送服务器端挂钩代码时获取更改后的linesdiff,而不是扫描完整文件。

谢谢

...如何只获得更改的行

这个问题是不完整的。 假设我告诉你,有些人包括爱丽丝,鲍勃,卡罗尔,等等。 现在我告诉你鲍勃与众不同。 与谁或什么不同?

在预接收挂钩中,您必须从标准输入中读取行。 每行的格式为:

old-hash new-hash reference-name

这些是什么意思? (尽管答案嵌入在下面的最后一节中,但是在继续下一节之前,这是您要回答的练习。)

获得差异需要选择两个项目

提交是文件的快照-冻结到该提交中的每个文件的完整副本。 没有差异 只有完整的文件。

但是,您需要差异。 为了使某些文件file.ext有所不同,您必须选择其他版本file.ext并将两者进行比较。 什么是正确的“其他版本”?

对于某些提交,您很幸运: file.ext有一个非常清晰正确的“其他版本”,即:该提交的提交中file.ext的副本。 实际上,对于提交中的每个文件都会重复此操作:我们想将那个文件的提交版本与该文件的父版本进行比较,以查看更改了什么。

为此有一个方便的脚本命令(“管道”),它是git diff-tree :给定普通非合并提交的哈希ID, git diff-tree将提交的父级与提交进行比较。 添加-p--patch可获得文本差异(这自动意味着-r选项)。 考虑使用-U0删除上下文行。 当然,您仍然需要解析输出行,以检测块头和添加/删除的标记。

但是,简单的git diff-tree <hash>不适用于两种情况的提交:

  • 提交没有父项。 幸运的是, 空树可以解救: git diff-tree -p $(git hash-object -t tree /dev/null) $hash可以解决问题。

  • 合并提交有两个或多个父级。 在这里git diff-tree默认会产生一个组合的diff 如果可以,您可以忽略这种情况。 如果不是这样,您可以考虑使用--first-parent -m或只是-m拆分合并并针对每个父级(默认)或第一个父级( --first-parent )获取多个差异。

这使您可以一次提交,因此现在进入最后一部分。

现在是时候处理钩子的stdin输入行了

阅读每一行时,您的工作是:

  • 检查旧的和新的哈希值是否有特殊的全零数字null哈希值 在Python中,有多种表达方式。 一个是:

     def is_null(hash): return all(i == '0' for i in hash) 

    如果旧哈希为空,则在新哈希处创建引用。 如果新哈希为null,则该引用曾经具有给定的旧哈希,并且正在被删除。 否则-两个哈希都不为空-引用将被更新:它具有旧的哈希,并且将具有新的哈希。

  • 弄清楚如何更改特定参考。 是否允许删除? 允许创作吗? 这是分支名称(以refs/heads/开头)与标签名称(以refs/tags/开头)还是其他名称无关紧要吗?

    创作特别困难。 新引入的名称使给定对象可以通过该名称访问。 如果对象是标记或提交,则也可以通过该名称访问其他对象。 这些对象中的某些或全部可能是新的。 这些对象中的某些或全部可能已经存在。 典型的案例是有人创建了新的分支名称:它可能指向一个已经存在于其他分支上的现有提交,或者可能指向一个新的提交,即新分支的新提示,其中可能包含许多其他的新提交。在加入一些现有分支之前。

    更新是最常见的,通常也是最简单的处理。 您知道现有的引用名称使旧对象可访问,而建议的更新将使新对象可访问。 如果引用是分支名称,则这两个对象实际上都是提交对象,并且很容易从提议的新哈希中找到哪些提交(如果有的话)是新可访问的,以及哪些提交(如果有的话)通过可访问性被删除。建议的新哈希:

     git rev-list $old..$new 

    产生一组新近可到达的哈希ID,并且:

     git rev-list $new..$old 

    产生不再可及的集合。 (使用git rev-list --left-right $old...$new ,带有三个点,可以同时获取两组哈希ID,并带有可区分的标记。您可以使用$new...$old :对称这样产生的差异本身就是对称的,当然,左右两侧是相反的。)

假设您已经以某种方式处理了创建,如果您的目标是检查新可访问的提交(无论它们是否是整个存储库中的全部),则可以简单地遍历所有新提交,测试每个新提交以查看它是否是根提交。 ,普通(单亲)提交或合并提交。 (提示:在git rev-list命令中添加--parents以获得父ID,以便您可以轻松知道每个提交有多少个父。此外,请考虑您要走的提交图片段的图结构: $old..$new可能包括合并,这可能使许多提交成为可访问的,而对于存储库而言,这可能是新的,也可能不是新的。)

您现在拥有了所有的提交哈希值,以及它们的父计数。 您还知道如何使用git diff-tree根据需要将每个提交与其父对象或空树进行比较。 因此,现在您可以编写您喜欢的预接收钩子了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM