Python 预接收挂钩中的差异

Python 预接收挂钩中的差异,python,git,githooks,Python,Git,Githooks,我已经用Python编写了一个简单的服务器端git预接收钩子。目标是分析差异和拒绝推文,我们认为某些文本无效。我使用以下一组命令编写了钩子: git ls-tree git diff --name-only git cat-file 但是,我刚刚注意到,我正在扫描作为提交的一部分推送的整个文件。但我只想在这次推送中扫描不同的线条 原因是一些无效的文本可能是假阳性的,是可以的。它可以被强制推动。但是,如果再次编辑同一文件并添加有效文本,则推送将被拒绝,因为该文件以前包含无效文本。每次编辑文件时

我已经用Python编写了一个简单的服务器端git预接收钩子。目标是分析差异和拒绝推文,我们认为某些文本无效。我使用以下一组命令编写了钩子:

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树
不适用于两种提交情况:

  • 根提交没有父级。幸运的是,解决办法来了:
    git diff tree-p$(git hash object-t tree/dev/null)$hash
    起到了作用

  • 合并提交有两个或多个父级。在这里,默认情况下,
    git-diff-tree
    生成一个组合的diff。如果可以的话,你可以忽略这个案例。如果不是,您可以考虑使用<代码>——第一个父- M<代码>或只是<代码> -M>代码>来分割合并并获得多个差异,针对每个父级(默认)或第一个父级(<代码>第一个父级< /代码>)。

这将使您获得一次提交的差异,因此现在我们进入最后一部分

现在是处理hook的stdin输入行的时候了 当你阅读每一行时,你的工作是:

  • 检查新旧散列中的特殊全零位空散列。在Python中,有多种方式来表达这一点;一是:

    def is_null(hash):
        return all(i == '0' for i in hash)
    
    如果旧哈希为null,则在新哈希处创建引用。如果新散列为null,则表示引用使用给定的旧散列,并且正在被删除。否则,两个散列都不为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
    :这产生的对称差分本身是对称的,当然,除了左右两侧是相反的。)

假设您以某种方式处理了创建,如果您的目标是检查新可到达的提交,那么您只需简单地浏览一下,就可以知道它们是否是存储库的新提交