有没有一个可以防止二进制文件提交的git钩子?

14

有没有人知道一个好的git hook,可以在提交时检查二进制文件并报错?我想防止二进制文件被提交到我的代码库中,但有时候人们会犯错误。

谢谢!


请查看此代码片段并根据需要进行更新 - https://gist.github.com/robertranjan/23570b820c534dd434ea2b409142c7f7 - Robert Ranjan
3个回答

9
我不知道是否有现成的钩子,但是git已经自带了一个检查添加“非ASCII名称”的钩子,作为一个示例pre-commit钩子。这很可能已经存在于您现有的git存储库中,路径为.git/hooks/pre-commit.sample
可以使用该钩子作为模板,并考虑"如何确定Git将文件处理为二进制文件还是文本文件?"的答案,您可以做出类似以下的操作(请参见"git的半秘密空树"以了解EMPTY_TREE的来源):
#! /bin/sh

stop_binaries=$(git config --get hooks.stop_binaries)

exec 1>&2

if [ "$stop_binaries" = true ]; then
    EMPTY_TREE=$(git hash-object -t tree /dev/null)
    # or: EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904
    if git diff --cached --numstat $EMPTY_TREE | grep -e '^-' >/dev/null; then
        echo Error: commit would add binary files:
        git diff --cached --numstat $EMPTY_TREE | grep -e '^-' | cut -f3-
        exit 1
    fi
fi

这里使用git diff --cached来查看将被提交的内容,并将其与初始空树进行比较。请注意,它会拒绝具有已存在(但未更改)二进制文件的提交;要使其仅拒绝新或更改的二进制文件,请从非ASCII名称钩子中添加against=逻辑。如果要仅拒绝二进制文件,则还需添加--diff-filter=A参数。

如果需要,可以使用其他错误消息文本来提高可读性。您还可以反转测试(而不是必须断言“停止二进制文件”),使其默认停止,您必须设置“allowbinaries”以添加二进制文件等。当然,您还可以通过对diff-index输出进行其他过滤来允许特定目录中的二进制文件等。


遗憾的是,使用这个工具处理一个大约100MB的压缩文件导致我的16GB Windows系统崩溃了。因此看来这个工具并不具备可扩展性。 - abergmeier
@abergmeier:奇怪。似乎只有100MB不应该成为问题。但另一方面,我不使用Windows. :-) - torek

3

不好意思,这里要做一个自我推销,但是我写了一个pre-receive hook,可以更加智能和可配置地实现这个功能。在查找了很多没有完全符合需求的现成Git管理系统之后,我终于成功地为stock Git提供了这个功能,而且不需要安装一些较大的Git管理系统。


2
将您的 README 重命名为 README.md 将非常有用! - Steve Lorimer
Git钩子是解决问题的好方法,但是你如何将它们分发给用户呢?钩子不会随着项目的克隆而传输,您必须以其他方式分发这些脚本,然后让用户将其复制到他们的.git/hooks目录中并使其可执行。 - Balualways
SteveLorimer:谢谢你的提示。我用POD编写了文档,但我只是将README.pod链接到主脚本,希望现在看起来更好。@Balualways:如果您需要将它们分发给用户,则可以使用一些脚本将其安装在.git中。这是一个功能,因为它们会影响正常的Git命令,并且可能包含会清除您的FS等内容的东西。当您克隆某个随机项目时,您不想担心这些问题。但是,您无需将此挂钩分发给用户。您只需要在推送到主存储库时检查它即可。 - Ævar Arnfjörð Bjarmason

0
我们的Git仓库有类似的要求。我们不希望意外提交非常大或二进制文件,因为它们会使仓库膨胀并且很难从历史记录中删除。坦白地说,我很惊讶这样的钩子不是所有Git用户的必需品。我们希望将其放在客户端,以便用户立即知道他们犯了一个错误。我们还希望允许用户覆盖钩子,如果他们确定文件应该被提交。
为了测试二进制文件,我只使用了Perl的-B检查。我选择使用pre-commit钩子。要覆盖钩子,我们只需打印一个提醒,告诉用户使用“--no-verify”重新运行提交。
最大文件大小是任意设置的,并在脚本中设置。您可以根据情况将其设置为适当的大小。
您还会注意到,这仅检查正在添加的文件(而不是修改的文件),因为我们不希望钩子每次修改大型或二进制文件时都变得麻烦。如果您想更加严格,可以将diff-filter更改为使用“ACM”(已添加、已复制或已修改)。
#!/usr/bin/perl
# The hook should exit with non-zero status after issuing an appropriate 
# message if it wants to stop the commit.

use strict; 
use warnings;

my $file;
my $MAX_SIZE = 100000; # Limit files to 100KB


# Only check binary and file size when files are added otherwise users
# get an error every time they modify they file.   This has the dissadvantage
# of not catching if a file grows too large after the initial commit
#
# Get list of added files only (i.e. new files)
my @new_file_list =  `git diff --cached --name-only --diff-filter=A`;
foreach $file (@new_file_list)
{
  chomp($file);

  # Check if file is binary
  if (-B $file)
  {
    print STDERR "WARNING: $file is binary.\n";
    print STDERR "Please check with repo owner before committing binary files.\n";
    print STDERR "To bypass this warning re-run your commit with the '--no-verify' option\n";
    exit 1;
  }

  # Check if file is very large
  if (-s $file > $MAX_SIZE)
  {
    print STDERR "WARNING: $file is greater than $MAX_SIZE bytes.\n";
    print STDERR "Please check with repo owner before committing very large files.\n";
    print STDERR "To bypass this warning re-run your commit with the '--no-verify' option\n";
    exit 1;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接