在推送到git remote之前检查提交大小

时间:2018-07-12 22:28:43

标签: git github githooks

我的编辑器中有一个错误(非常糟糕),有时大文件会写入到工作目录中。然后,我执行了git push,而无需手动检查这些新文件,而git remote变得超载并最终出错。

是否可以使用一些检查(也许是git钩子)来检查我的存储库是否超过一定大小(以MB为单位)?

4 个答案:

答案 0 :(得分:5)

在运行git push时,Git不会以任何方式使用工作树。具体来说,git push推送是 commits ,还需要任何对象(主要是内容在提交时被冻结到提交中的文件)才能完成这些提交。 1

请注意,git commit本身不使用工作树:它会提交 index 中的任何内容(也称为 staging-区域,有时还包括缓存)。这就是为什么您必须git add提交文件之后再进行提交的原因。 git commit中有一些选项可以使它自动在索引/暂存区域中的那些文件的版本之上复制工作树文件。但是原理仍然存在:git commit提交索引中的内容,而不是工作树中的内容。

因此,您最好使用Git hook 来检测此问题,这是一个预先提交的钩子,如the githooks documentation中所述:

  

预提交

     
    此钩子由git commit(1)调用,并且可以通过   --no-verify选项。它不带参数,在调用之前   获取建议的提交日志消息并进行提交。退出中   此脚本中状态为非零的情况会导致git commit命令   在创建提交之前中止。

(文档还有更多内容;请单击链接查看。)

编写Git钩子有些棘手(尤其是服务器端钩子),但这还算不错:

#! /bin/sh
# pre-commit hook: check for large files
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 2 3 15
MAX_FILE_SIZE=1048576 # 1 MB
status=0
git ls-files --stage > $TMP
while read mode hash stage path; do
    objsize=$(git cat-file -s $hash)
    if [ $objsize -gt $MAX_FILE_SIZE ]; then
        echo "file too big: '$path' as staged exceeds $MAX_FILE_SIZE bytes" 1>&2
        status=1
    fi
done < $TMP
exit $status

(未测试)。相反,您可以选择一个预推钩子,但这要晚一些。


1 这些Git对象也被压缩。只要有可能,就可以使用服务器上已存在的现有先前对象对它们进行高度压缩。因此,如果您有一个10 GB的文本文件,但是您对其进行了小的更改并提交,则即使该文件中有一个10 GB的文件,推动该提交也将占用很小的空间,因为所谓的 thin pack Git发送的消息说:嘿,还记得您已经有10 GB的对象吗?拿那个,从中间删除几个字节,然后用其他字节替换它们。

答案 1 :(得分:3)

由于这是一个持续存在的问题,因此您应该养成运行git status的习惯,然后再进行git commit。您可以查看将提交的文件列表,以查找不属于它们的文件。

答案 2 :(得分:2)

如果您知道大文件名或格式,例如后缀,您可以将其添加到.gitignore中,直到解决编辑器问题为止。

您可以检查this answer,它描述了服务器端更新挂钩。

答案 3 :(得分:0)

另一种方法,如果您希望多次提交的大小:

使用Git 2.29(2020年第四季度)时,“ git for-each-ref --format= man <>”学到了%(contents:size)

请参见commit b6839fd之前的commit 6e2ef8e(2020年7月16日)和commit 9fcc9caChristian Couder (chriscool)(2020年7月10日)。
(由Junio C Hamano -- gitster --commit be53706中合并,2020年7月30日)

ref-filter:添加对%(contents:size)的支持

签名人:Christian Couder

能够直接获取内容的大小而不必通过wc -c进行传递,这既有用又有效。

也是以下结果:

git for-each-ref --format='%(contents)' refs/heads/my-branch | wc -c man

偏移了一个,因为[ git for-each-ref ](https://github.com/git/git/blob/b6839fda6809b1de8d528837dfc99d0837f77c9d/Documentation/git-for-each-ref.txt)<sup>([man](https://git-scm.com/docs/git-for-each-ref))</sup>在内容后面附加了换行符,可以通过将其输出与git cat-file的输出进行比较来看到< sup>(man)。

%(contents)一样,如果ref指向除提交或标记之外的其他内容,则%(contents:size)会被静默忽略:

$ git update-ref refs/mytrees/first HEAD^{tree}
$ git for-each-ref --format='%(contents)' refs/mytrees/first

$ git for-each-ref --format='%(contents:size)' refs/mytrees/first

git for-each-ref现在包含在其man page中:

contents:size

提交或标记消息的字节大小。