是否有一个git钩子可以防止二进制签入

时间:2013-11-26 19:24:10

标签: git

有没有人知道一个好的git钩子会在提交时检查二进制文件并抛出错误?我试图阻止二进制文件被提交到我的存储库,但有时人们会犯错误。

谢谢!

3 个答案:

答案 0 :(得分:7)

我不知道现有的钩子,但是git已经附带了一个钩子来检查添加“非ascii名称”,作为一个示例预提交钩子。这可能已经在您现有的git存储库中.git/hooks/pre-commit.sample

使用该挂钩作为模板并考虑"How to determine if Git handles a file as binary or as text?"的答案,您可以执行以下操作(请参阅"git's semi-secret empty tree"了解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-names挂钩添加against=逻辑。要仅拒绝 new 二进制文件,也要添加--diff-filter=A参数。

如果您愿意,可以使用其他错误消息文本。你可以反转测试(而不是断言“停止二进制”,使其默认停止,你必须设置“allowbinaries”来添加二进制文件),等等。当然你可以允许特定的目录充满二进制文件,或者其他,通过对diff-index输出进行额外的过滤。

答案 1 :(得分:2)

无耻的插件,但我wrote a pre-receive hook可以更智能地执行此操作。搜索后可以通过库存Git找到没有任何功能的可配置方式,而无需安装更大的Git管理系统。

答案 2 :(得分:0)

我们对Git回购有类似的要求。我们不希望允许非常大或二进制文件被意外检查,因为它们可以使回购膨胀并且很难从历史中删除。坦率地说,我很惊讶这样的钩子并不是所有Git用户的要求。我们希望我们在客户端,以便用户立即知道他们犯了错误。我们还希望允许用户在确定应该提交文件时覆盖挂钩。

为了测试二进制文件,我只使用了Perl的-B检查。我选择使用预提交钩子。要覆盖挂钩,我们只需打印提醒,告诉用户使用'--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;
  }
}