限制GIT提交大文件
限制 Git 提交单个超过 10M 的文件,需要从客户端(防止本地提交) 和服务器端(防止推送到远程) 双重控制,结合工具和脚本实现自动化拦截。以下是具体可落地的方案,覆盖不同操作系统和场景:
一、客户端拦截:用 husky
+ 钩子脚本阻止本地提交
通过 Git 的 pre-commit
钩子(提交前触发),检查暂存区文件大小,超过 10M 则直接阻止提交。配合 husky
可简化钩子管理,确保团队成员统一生效。
【husky: GIT hook管理工具】
步骤 1:安装 husky
并初始化(适用于 Node 项目,非 Node 项目可手动配置钩子)
# 1. 安装 husky(若项目无 package.json,先执行 npm init -y 创建)
npm install husky --save-dev# 2. 初始化 husky,创建 .husky 目录(存放钩子脚本)
npx husky install# 3. 配置自动启用 husky(其他人克隆仓库后,安装依赖时自动初始化)
echo "npx husky install" >> .git/hooks/post-checkout # 切换分支后自动启用
npm set-script prepare "husky install" # 安装依赖后自动执行
步骤 2:创建 pre-commit
钩子脚本(检查文件大小)
# 创建 pre-commit 钩子
npx husky add .husky/pre-commit "bash .husky/check-large-files.sh"# 创建检查脚本(核心逻辑)
touch .husky/check-large-files.sh
编辑 check-large-files.sh
脚本(兼容 Linux/macOS/Windows WSL):
#!/bin/bash# 最大允许文件大小(10M = 10*1024*1024 字节)
MAX_SIZE=$((10 * 1024 * 1024))
# 暂存区文件列表(仅包含新增/修改的文件,排除删除的文件)
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)# 遍历文件检查大小
for FILE in $STAGED_FILES; do# 跳过不存在的文件(可能已删除但未提交)if [ ! -f "$FILE" ]; thencontinuefi# 获取文件大小(兼容 Linux/macOS)if [[ "$OSTYPE" == "darwin"* ]]; then# macOS 用 stat -f%zFILE_SIZE=$(stat -f%z "$FILE")else# Linux 用 stat -c%sFILE_SIZE=$(stat -c%s "$FILE")fi# 检查是否超过限制if [ $FILE_SIZE -gt $MAX_SIZE ]; then# 转换为 MB 显示FILE_SIZE_MB=$(echo "scale=2; $FILE_SIZE / 1024 / 1024" | bc)echo -e "\033[31m❌ 错误:文件 '$FILE' 大小为 ${FILE_SIZE_MB}M,超过 10M 限制!\033[0m"echo -e " 解决方案:\n 1. 用 Git LFS 跟踪:git lfs track '$FILE'\n 2. 压缩/裁剪文件后重新提交"exit 1 # 阻止提交fi
doneecho -e "\033[32m✅ 所有文件大小符合规范\033[0m"
exit 0
步骤 3:赋予脚本执行权限
chmod +x .husky/check-large-files.sh
测试效果
尝试提交一个超过 10M 的文件:
# 创建一个 15M 的测试文件
dd if=/dev/zero of=test-large.file bs=1M count=15# 暂存并提交
git add test-large.file
git commit -m "test: add large file"
此时会报错并阻止提交,提示解决方案。
二、服务器端拦截:用 pre-receive
钩子阻止推送
客户端钩子可能被人为绕过(如删除脚本),因此需要在 Git 服务器(如自建 GitLab、Gitea 或远程仓库)配置 pre-receive
钩子,作为最后一道防线。
步骤 1:进入服务器仓库的钩子目录
假设远程仓库路径为 /var/git/repo.git
(自建 Git 服务器),进入钩子目录:
cd /var/git/repo.git/hooks
步骤 2:创建 pre-receive
钩子脚本
vim pre-receive # 新建文件,写入以下内容
脚本内容:
#!/bin/bashMAX_SIZE=$((10 * 1024 * 1024)) # 10M# 读取推送的引用(旧版本、新版本、分支名)
while read -r OLD_REF NEW_REF REF_NAME; do# 处理新分支(旧版本为全0)if [ "$OLD_REF" = "0000000000000000000000000000000000000000" ]; then# 新分支:检查所有提交的文件FILES=$(git diff-tree --no-commit-id --name-only -r "$NEW_REF")else# 已有分支:检查新旧版本差异文件FILES=$(git diff-tree --no-commit-id --name-only -r "$OLD_REF" "$NEW_REF")fi# 遍历文件检查大小for FILE in $FILES; do# 获取文件在新版本中的大小FILE_SIZE=$(git cat-file -s "$NEW_REF:$FILE" 2>/dev/null)if [ -n "$FILE_SIZE" ] && [ "$FILE_SIZE" -gt "$MAX_SIZE" ]; thenFILE_SIZE_MB=$(echo "scale=2; $FILE_SIZE / 1024 / 1024" | bc)echo -e "\033[31m❌ 错误:推送的文件 '$FILE' 大小为 ${FILE_SIZE_MB}M,超过 10M 限制!\033[0m"exit 1 # 阻止推送fidone
doneexit 0
步骤 3:赋予执行权限
chmod +x pre-receive
三、特殊场景处理
1. 允许特定大文件(白名单)
如果某些大文件(如设计稿、必要资源)必须提交,可在脚本中添加白名单:
# 在检查文件大小前添加白名单判断(以客户端脚本为例)
WHITELIST=("docs/design.psd" "assets/big-icon.png") # 允许的文件路径
if [[ " ${WHITELIST[@]} " =~ " $FILE " ]]; thencontinue # 跳过检查
fi
2. 处理已提交的大文件
如果大文件已被提交到仓库,需彻底移除(否则仓库体积仍会很大):
推荐用 BFG Repo-Cleaner
工具(比 git filter-branch
更快):
# 1. 下载 BFG(https://rtyley.github.io/bfg-repo-cleaner/)
# 2. 清理所有超过 10M 的文件
java -jar bfg.jar --strip-blobs-bigger-than 10M my-repo.git# 3. 提交修改到远程
cd my-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push origin --force
3. 大文件的正确处理方式:使用 Git LFS
对于必须跟踪的大文件(如视频、大型二进制文件),推荐用 Git LFS
(大文件存储):
# 1. 安装 Git LFS
git lfs install# 2. 跟踪特定类型大文件(如 .psd、.mp4)
git lfs track "*.psd"
git lfs track "*.mp4"# 3. 提交跟踪规则
git add .gitattributes
git commit -m "chore: track large files with LFS"# 4. 正常提交大文件(LFS 会自动处理)
git add large-file.psd
git commit -m "feat: add design file"
总结
- 客户端:用
husky + pre-commit
钩子在提交前拦截,即时反馈给开发者。 - 服务器端:用
pre-receive
钩子作为最后防线,防止绕过客户端检查的情况。 - 最佳实践:配合
Git LFS
管理必要的大文件,既遵守规范又不影响开发。
通过这套方案,可有效避免大文件污染 Git 仓库,保持仓库轻量化和同步效率。