git pre-receive(push)hook检测是否在特定文件中完成了合并

时间:2015-10-20 16:33:13

标签: git

我有一个Git预接收挂钩,可以执行多种验证,例如提交消息和文件大小。

现在我还要包含一个验证,如果存在触及特定文件的合并提交,则阻止推送。原因是我们有一个文件应该只通过与发布版本控制相关的自动过程进行更改,当人们需要在本地解决合并冲突时,人们很容易合并该文件。

所以,鉴于当前的预接收挂钩:

filename=<path-to-file>
while read OLD_SHA1 NEW_SHA1 REFNAME; do
  ...

我需要:

  1. 检索正在推送的提交列表
  2. 对于每次提交,确定当前提交是否引用合并 提交
  3. 如果是合并提交,请检索其中的已更改文件 提交并检查它包括受限文件($ filename)
  4. 可选地,如果不是合并提交,它也可以检查作者,因为它预期它与特定的提交匹配(来自自动化过程)。这也可以防止开发人员做了一些错误的改变或挑选的情况。

    有人可以为此提供帮助吗? 如果有一个完整的解决方案(对于3个步骤)会很有帮助,因为我认为这对其他人来说可能很有意思。

1 个答案:

答案 0 :(得分:2)

很容易检测到提交序列中是否有合并:

git rev-list --min-parents=2 $OLD..$NEW

将它们交给你。 (并且请注意,在收到前后,你会得到两个有问题的SHA-1,这样你就可以了。)

确定&#34;更改文件&#34;有点困难。因为没有提交商店更改。每个提交只需附加一个完整的源代码树。这包括合并提交。对于非合并,发现更改的明显方法是:将提交与其父级进行比较。但是合并提交有两个(或更多)父母,所以你检查哪一个?有三个明显的答案:&#34;主线&#34;父母,&#34;分支&#34;父母,或者&#34;所有父母&#34;。我将此部分留给您,因为它是一个政策问题。

确定策略后,您只需使用git diff(或任何等效项)将父提交与合并提交进行比较。例如,如果您决定只想查看&#34;主线&#34;是否有变化? (即,第一)父母:

git diff [flags] ${sha1}^ $sha1

比较提交。将--name-status添加到flags部分,您将获得文件名和状态,并且可以检查M<tab><path>以查看是否修改了某个路径。

(您可以使用--diff-filter=M删除不仅仅是M状态文件的所有输出,并且如果您的过滤器只允许一个状态(例如,在这种情况下,则可以)使用--name-only,因为任何出现的名称都意味着状态,所以这就变成了:

git diff --name-only --diff-filter=M ${sha1}^ $sha1 | grep '^<path>$'

确保您没有启用git diff重命名检测:它不太可能,但差异可能决定父母和孩子之间的差异,你关心的文件是从其他文件重命名的,而不是在原地进行修改。)

您可能会在我编写的经过轻微测试的预接收脚本here中找到更多想法。