在使用 Git 进行代码版本控制时,我们经常会遇到需要将本地仓库推送到多个远程仓库进行备份的情况。然而,当累积的提交量较大时,可能会遇到 GitHub 的 2GB 推送限制,导致 push 操作失败。本文将详细介绍这个问题的原因和多种解决方案。
我有一个本地的 git 仓库,一直在 commit 并 push 到默认的 GitHub 账号下的仓库内。我有另外一个 GitHub 账号用于源码备份,我最后一次将这个本地仓库进行 push 备份是在半年前,现在已经累计有半年的提交一直没有 push 到该 GitHub 下仓库内了。现在我进行 push 备份时,报错:remote: fatal: pack exceeds maximum allowed size (2.00 GiB)
。
当你尝试将积累的大量 Git 提交推送到 GitHub 时,如果推送的提交量过大,就可能遇到以下错误:
remote: fatal: pack exceeds maximum allowed size (2.00 GiB)
# 或
fatal: the remote end hung up unexpectedly
这个错误表明你的推送操作超过了 GitHub 的 2GB 限制阈值。正常情况下,遇到这种错误的概率是比较小的,我是因为仓库里必须要保留近 20 个大文件且经常对其进行修改导致的。
GitHub 设置 2GB 的推送限制主要有以下几个原因:
这是最安全和可控的解决方案,通过将大量提交分成小批次逐步推送。
下面是一个我用来自动分批推送提交 shell 脚本。这个脚本会从指定的起始 commit 开始,按照批次大小自动推送到远程仓库。
#!/bin/bash
# 检查参数
if [ "$#" -lt 4 ]; then
echo "Usage: $0 <remote_name> <branch_name> <start_commit> <batch_size>"
echo "Example: $0 backup main abc123 50"
exit 1
fi
REMOTE=$1
BRANCH=$2
START_COMMIT=$3
BATCH_SIZE=$4
# 验证remote是否存在
if ! git remote get-url $REMOTE > /dev/null 2>&1; then
echo "Error: Remote '$REMOTE' does not exist"
exit 1
fi
# 验证起始commit是否有效
if ! git rev-parse --verify $START_COMMIT^{commit} > /dev/null 2>&1; then
echo "Error: Invalid start commit: $START_COMMIT"
exit 1
fi
# 获取从起始commit到HEAD的所有提交
COMMITS=($(git rev-list --reverse $START_COMMIT..HEAD))
TOTAL_COMMITS=${#COMMITS[@]}
if [ $TOTAL_COMMITS -eq 0 ]; then
echo "No commits to push after $START_COMMIT"
exit 0
fi
echo "Found $TOTAL_COMMITS commits to push"
echo "Will push in batches of $BATCH_SIZE commits"
# 计算需要多少批次
BATCHES=$(( (TOTAL_COMMITS + BATCH_SIZE - 1) / BATCH_SIZE ))
for ((i = 0; i < BATCHES; i++)); do
START_IDX=$((i * BATCH_SIZE))
if [ $((START_IDX + BATCH_SIZE)) -lt $TOTAL_COMMITS ]; then
END_COMMIT=${COMMITS[$((START_IDX + BATCH_SIZE - 1))]}
else
END_COMMIT=${COMMITS[$((TOTAL_COMMITS - 1))]}
fi
START_COMMIT_SHORT=$(git rev-parse --short ${COMMITS[$START_IDX]})
END_COMMIT_SHORT=$(git rev-parse --short $END_COMMIT)
echo "Pushing batch $((i + 1))/$BATCHES: $START_COMMIT_SHORT..$END_COMMIT_SHORT"
# 尝试推送这一批次的提交
if git push $REMOTE $END_COMMIT:refs/heads/$BRANCH; then
echo "Successfully pushed batch $((i + 1))"
else
echo "Error pushing batch $((i + 1))"
echo "Failed at commit range: $START_COMMIT_SHORT..$END_COMMIT_SHORT"
echo "You can resume from the last successful commit"
exit 1
fi
# 添加小延迟,避免触发GitHub的限制
sleep 2
done
echo "All commits have been pushed successfully!"
使用这个脚本的方法:
首先将脚本保存为 git-batch-push.sh
给脚本添加执行权限:
chmod +x git-batch-push.sh
./git-batch-push.sh backup main 起始commit的hash值 50
参数说明:
例如:
./git-batch-push.sh backup main abc123def456 50
脚本的主要特性:
如果在运行过程中发生错误,脚本会显示最后成功的提交,你可以从那里继续推送。
要找到起始 commit 的 hash 值,你可以在 GitHub 提交历史里查看最后一次提交的 hash,可以直接复制。
查看提交历史的相关 git 命令:
# 查看本地提交历史
git log --oneline
# 查看远程分支的提交历史
git log --oneline backup/main
# 同时对比多个远程分支
git log --oneline origin/main upstream/develop
如果不需要完整的提交历史,可以使用浅克隆:
# 浅克隆仓库
git clone --depth 1 原仓库地址 new-repo
cd new-repo
# 添加备份仓库
git remote add backup 备份仓库地址
# 推送到备份仓库
git push backup main
对于包含大文件的仓库,建议使用 Git LFS:
# 安装Git LFS
git lfs install
# 追踪大文件
git lfs track "*.psd"
git lfs track "*.zip"
# 确保.gitattributes被提交
git add .gitattributes
git commit -m "配置Git LFS跟踪规则"
如果其他方法都不可行,可以考虑重新初始化仓库:
# 备份原始文件
cp -r 项目目录 项目目录_backup
# 删除Git历史
rm -rf .git/
# 重新初始化
git init
git remote add origin 远程仓库地址
# 分批添加和提交文件
git add 文件/目录
git commit -m "Initial commit"
# 推送到远程
git push -u origin main
为避免遇到类似问题,建议:
使用 git 命令检查仓库大小和找出大文件的方法:
# 检查仓库大小
git count-objects -vH
# 找出大文件
git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | sort -nr -k3
相关链接:
GitHub 的 2GB 推送限制虽然可能会带来一些不便,但通过合理的策略和工具,我们可以有效地解决这个问题。关键是要选择适合自己项目特点的解决方案,并在日常开发中养成良好的 Git 使用习惯。