You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用BFG缩减Git仓库体积后分支分歧及大文件重复引入问题

问题背景

假设存在一个含README.md的测试仓库,流程如下:

  1. 在其他分支提交大文件并向master发起PR
  2. 通过另一个PR合并移除大文件,但Git对象中仍遗留大体积.pack文件
  3. 使用BFG工具清理该文件,步骤为:
    • 下载bfg.jar
    • 用--mirror参数克隆仓库(否则远程分支无法更新)
    • 执行命令:java -jar path/to/bfg.jar --delete-files 'somelargefile.zip'
    • 执行命令:git reflog expire --expire=now --all && git gc --prune=now --aggressive
    • 执行命令:git push --force

清理后远程仓库恢复整洁,但协作成员的本地仓库仍保留带大.pack文件的分支。拉取最新代码时会出现「You have divergent branches and need to specify how to reconcile them」错误,无论选择合并/变基/快进,后续提交都会再次引入大文件,形成循环。

本地仓库修复方案(无需重新克隆)

针对本地已有问题分支的情况,按以下步骤操作:

  1. 重置本地分支到远程最新状态
    切换到受影响的分支(比如master),执行:

    git fetch origin
    git reset --hard origin/master
    

    该操作会丢弃本地分支的所有未提交修改,强制对齐远程仓库的最新干净版本。

  2. 清理本地Git冗余对象
    执行本地GC命令彻底清除残留的大文件对象:

    git reflog expire --expire=now --all
    git gc --prune=now --aggressive
    
  3. 删除本地废弃分支
    如果之前提交大文件的分支已无保留必要,直接删除本地对应的分支:

    git branch -D old-large-file-branch
    

    避免后续误操作再次合并该分支。

用Git钩子阻止大文件提交(含历史残留)

可以通过两种钩子从源头拦截大文件:

1. 本地预提交钩子(pre-commit)

在本地仓库的.git/hooks/目录下创建pre-commit文件(若有.sample后缀则去掉),写入以下内容:

#!/bin/sh

# 设置允许的最大文件大小(单位:字节,这里设为10MB)
MAX_SIZE=$((10*1024*1024))

# 检查即将提交的所有新增/修改文件
for FILE in $(git diff --cached --name-only); do
    if [ -f "$FILE" ]; then
        FILE_SIZE=$(stat -c%s "$FILE")
        if [ "$FILE_SIZE" -gt "$MAX_SIZE" ]; then
            echo "错误:文件 $FILE 大小超过 $MAX_SIZE 字节,禁止提交"
            exit 1
        fi
    fi
done

# 扫描所有历史对象,防止通过变基/合并引入残留大文件
git rev-list --all --objects | grep -E "^[0-9a-f]{40} .*$" | while read -r HASH PATH; do
    OBJECT_SIZE=$(git cat-file -s "$HASH")
    if [ "$OBJECT_SIZE" -gt "$MAX_SIZE" ]; then
        echo "错误:历史对象中发现大文件 $PATH(大小 $OBJECT_SIZE 字节),禁止提交"
        exit 1
    fi
done

exit 0

然后给文件添加执行权限:

chmod +x .git/hooks/pre-commit

2. 远程预接收钩子(pre-receive)

在远程仓库的hooks/目录下创建pre-receive文件,写入以下内容:

#!/bin/sh

MAX_SIZE=$((10*1024*1024))

while read -r OLD_REF NEW_REF REF_NAME; do
    # 检查推送的所有提交中的文件
    git rev-list "$OLD_REF..$NEW_REF" --objects | grep -E "^[0-9a-f]{40} .*$" | while read -r HASH PATH; do
        OBJECT_SIZE=$(git cat-file -s "$HASH")
        if [ "$OBJECT_SIZE" -gt "$MAX_SIZE" ]; then
            echo "错误:推送的提交中包含大文件 $PATH(大小 $OBJECT_SIZE 字节),拒绝接收"
            exit 1
        fi
    done
done

exit 0

添加执行权限:

chmod +x hooks/pre-receive

内容的提问来源于stack exchange,提问作者user1735921

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 02:05:13