推送到Git远程仓库之前,请检查提交的大小。

6

我在我的编辑器中发现一个错误(很糟糕),偶尔会将大文件写入工作目录。然后我执行git push时,没有手动检查这些大文件是否存在,导致git远程出现过载并最终报错。

有没有办法检查我存储库的大小是否超过了某个以MB为单位的阈值(也许可以使用git hook)?


大文件是否总是保存在某个特定的文件夹中?文件名是否具有一致的模式,例如不规则扩展名? - Code-Apprentice
git push 不会处理未提交的文件。你必须在本地进行提交。你是盲目使用 git add . 或类似命令吗?那是一个不好的反模式。 - Chris
是的,我正在提交它们并通过提交所有未被.gitignore忽略的文件来推送它们。 - user7898461
1
@OlegzandrDenman 你有答案了吗?这与 Bitbucket 存储库相关,其最大大小为1GB。 - vineeshvs
4个回答

5
Git在运行git push时不会以任何方式使用工作树。具体来说,git push推送的是提交,以及使这些提交完整所需的任何对象,这些对象通常是在提交时冻结到提交中的文件。1 请注意,git commit本身也不会使用工作树:它会提交索引(也称为暂存区,有时称为缓存)中的所有内容。这就是为什么您必须在提交之前添加您的文件git add。虽然git commit有几个选项可以使其自动将工作树文件复制到暂存区中那些文件的版本上;但原理仍然是相同的:git commit提交的是索引中的内容,而不是工作树中的内容。
因此,检测此问题的最佳Git挂钩是一个预提交挂钩,如githooks文档中所述:

pre-commit

    该挂钩由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 对象也是压缩的。尽可能地,它们会使用服务器上已存在的先前对象进行非常压缩。因此,如果您有一个十 GB 的文本文件,但只对其进行了一点更改并提交,即使该提交包含了一个十 GB 的文件,由于 Git 发送的所谓的thin pack 将告诉服务器: 嘿,记得你已经有那个十 GB 的对象吗?取出那个对象,从中间删除几个字节,并替换为这些其他字节。


2
如果你知道大文件的名称或模式(例如后缀),你可以将其添加到 .gitignore 文件中,直到你解决编辑器问题为止。
你可以查看 这个答案,其中描述了一个服务器端更新钩子。

这是一个很好的想法,你应该得到一个赞,但如果你能找到一种通用的方法来解决任何未知的大文件问题,那就最好了。 - user7898461
@OlegzandrDenman,请更新答案并附上此钩子的链接。 - Karol Dowbecki
@OlegzandrDenman,很明显你可以根据名称忽略某些内容。但是有一个问题,git add -A和git status -s不会告诉你大小,而git commit -m“sfds”也不会告诉你大小。只有在推送时才会发现有大量内容。当处理框架或嵌套框架时可能会出现这种情况。 - barlop

2

由于这是一个持续进行的问题,您应该养成在执行git commit之前运行git status的习惯。您可以查看将被提交的文件列表,以查找不应该存在的文件。


2
一个项目可能会有很多东西,特别是当你处理一些框架时,你并没有编写或导入每个单独的文件。而且,git status 命令不会告诉你大小。 - barlop

0

如果您想要多个提交的大小,可以采用另一种方法:

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

请查看 commit b6839fd(2020年7月16日),以及 commit 6e2ef8ecommit 9fcc9ca(2020年7月10日),作者为 Christian Couder (chriscool)
(由 Junio C Hamano -- gitster --commit be53706 中合并,2020年7月30日)

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

签名:Christian Couder

It's useful and efficient to be able to get the size of the contents directly without having to pipe through wc -c.

Also the result of the following:

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

is off by one as git for-each-ref(man) appends a newline character after the contents, which can be seen by comparing its output with the output from git cat-file(man).

As with %(contents), %(contents:size) is silently ignored, if a ref points to something other than a commit or a tag:

$ 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现在在其手册页面中包含:

contents:size

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


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