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

问题描述 投票:0回答:5

我的编辑器中有一个错误(太可怕了),有时会将大文件写入工作目录。然后,我在不手动检查这些大的新文件的情况下执行了

git push
,并且 git 远程超载并最终出错。

是否有一些检查(可能是 git hook)可以用来检查我的存储库是否超过特定大小(以 MB 为单位)?

git github githooks
5个回答
5
投票

当您运行

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

请注意,

git commit
本身also不使用工作树:它提交index中的任何内容(也称为staging-area,有时也称为cache)。 这就是为什么您必须在提交之前
git add
您的文件。
git commit
有一些选项可以使其自动将工作树文件复制到索引/暂存区域中这些文件的版本之上;但原则仍然是:
git commit
提交索引中的内容,而不是工作树中的内容。

因此,在 Git hook 上检测此问题的最佳选择是预提交挂钩,如 githooks 文档中所述:

预提交

    这个钩子由 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 对象吗? 拿那个,从中间删除几个字节,然后用其他字节替换它们。


2
投票

如果您知道大文件名或模式,例如后缀,您可以将其添加到

.gitignore
,直到您解决编辑器的问题。

您可以检查这个答案,它描述了服务器端更新挂钩。


2
投票

由于这是一个持续存在的问题,因此您应该在执行

git status
之前养成跑步
git commit
的习惯。您可以查看将提交的文件列表以查找不属于的文件。


0
投票

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

使用 Git 2.29(2020 年第 4 季度),“

git for-each-ref --format= <>
(man)”学会了
%(contents:size)

请参阅 Christian Couder (chriscool)commit b6839fd(2020 年 7 月 16 日)和 commit 6e2ef8e

commit 9fcc9ca(2020 年 7 月 10 日)。
(由 Junio C Hamano --
gitster
--
合并于 commit be53706,2020 年 7 月 30 日)

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

的支持

签署人:Christian Couder

无需通过管道即可直接获取内容的大小,这非常有用且高效。

还有以下结果:

wc -c

 关闭了 1,因为 

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

(man) 在内容后面附加了一个换行符,可以通过将其输出与 git for-each-ref
(
man) 的输出进行比较来看出.

git cat-file

一样,如果 ref 指向提交或标签以外的内容,

%(contents)
会被默默忽略:
%(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

提交或标记消息的大小(以字节为单位)。


0
投票
contents:size

“更改的文件”部分。其次,检查

staged
文件的大小并忽略这些被“删除”的文件。 但是,它没有考虑压缩步骤,因此实际提交通常会具有较小的大小。另外,通过“ls -l”检查“修改”文件的大小可能是错误的,因为这些是“git对象”,并且可能最好通过

git status

git ls-files --stage
获取对象的大小,如
Torek的答案所示
.

git cat-file -s $hash

调用的缺点是它包含已知的 git 文件,这些文件可能不包含在当前提交中。

这是一个带有注释和调试行的脚本:

git ls-files --stage

这就是它的实际工作原理。它使用一些技术来获取用户输入。

首先将文件添加到舞台:

stage phase 然后,如果某些文件超出限制,则会打印它们。如果您选择“n”,则不会创建提交:

pre commit warning - no

pre commit warning - yes

© www.soinside.com 2019 - 2024. All rights reserved.