git删除历史大文件

BFG Repo-Cleaner

Removes large or troublesome blobs like git-filter-branch does, but faster. And written in Scala

BFGgit-filter-branch 的一个更简单、更快捷的替代方案,用于从Git存储库历史中清除不良数据:

  • 移除超大文件,不小心提交的大型二进制文件或已不再使用,但已提交到Git存储库且需要清除的文件。
  • 移除误提交的密码、凭证和其他私人数据。

git 仓库地址: https://github.com/rtyley/bfg-repo-cleaner

文档地址: https://rtyley.github.io/bfg-repo-cleaner/

bfg指令集

  • -b, --strip-blobs-bigger-than <size>
    移除大于 X 的文件块(例如 ‘128K’、’1M’ 等)
  • -B, --strip-biggest-blobs <NUM>
    移除体积最大的 NUM 个文件块
  • -bi, --strip-blobs-with-ids <blob-ids-file>
    移除指定 Git 对象 ID 的文件块
  • -D, --delete-files <glob>
    删除指定名称的文件(例如 ‘.class’、’.{txt,log}’ —— 匹配文件名,而非仓库内的路径)
  • --delete-folders <glob>
    删除指定名称的文件夹(例如 ‘.svn’、’*-tmp’ —— 匹配文件夹名,而非仓库内的路径)
  • --convert-to-git-lfs <value>
    将指定名称的文件(例如 ‘.zip’ 或 ‘.mp4’)提取到 Git LFS 中
  • -rt, –replace-text
    过滤文件内容,替换匹配的文本。表达式应逐行写在文件中,默认每个表达式按字面量处理,但支持 regex: 和 glob: 前缀,可使用 ==> 指定替换字符串(默认替换为 **REMOVED**)。
  • -fi, --filter-content-including <glob>
    仅对匹配该表达式的文件进行内容过滤(例如 ‘*.{txt,properties}’)
  • -fe, --filter-content-excluding <glob>
    不对匹配该表达式的文件进行内容过滤(例如 ‘*.{xml,pdf}’)
  • -fs, --filter-content-size-threshold <size>
    仅对小于指定大小的文件进行内容过滤(默认 1048576 字节)
  • -p, --protect-blobs-from <refs>
    保护出现在指定引用的最新版本中的文件块(默认为 ‘HEAD’)
  • --no-blob-protection
    允许 BFG 修改甚至你的最新提交。不推荐:你应当已确保最新提交是干净的。
  • --private
    将此仓库重写视为移除私有数据(例如:从提交消息中省略旧的提交 ID)
  • --massive-non-file-objects-sized-up-to <size>
    增加内存使用,以处理大小不超过 X 的超大提交、标签和树对象(例如 ‘10M’)
  • <repo>
    要清理的 Git 仓库的文件路径

移除超大文件(远程仓库)

步骤一:克隆裸仓库

首先,使用 --mirror 标志克隆一个新副本的仓库。git clone --mirror 命令将从远程仓库创建一个裸仓库。这意味着你平时的文件将不可见,但它是你的仓库中Git数据库的完整副本。此时,你应该对其进行备份,以确保不会丢失任何内容。

1
git clone --mirror https://example.com/some-big-repo.git

git clone --mirror

步骤二 查看历史大文件(可忽略)

进入到上步骤创建的 <gitRepo>.git 文件夹中,执行

1
2
3
4
5
6
7
8
9
10
git verify-pack -v ./objects/pack/*.idx 2>/dev/null | \
sort -k 3 -rn | \
head -20 | \
awk '{cmd="git rev-list --objects --all | grep " $1 " | awk '\''{print $2}'\''"; cmd | getline fname; close(cmd); print $3, $1, fname}' | \
awk '{size=$1; hash=$2; fname=$3; \
if(size>=1073741824) {s=sprintf("%.2f GB", size/1073741824)} \
else if(size>=1048576) {s=sprintf("%.2f MB", size/1048576)} \
else if(size>=1024) {s=sprintf("%.2f KB", size/1024)} \
else {s=sprintf("%d B", size)}; \
printf "%-12s %-40s %s\n", s, (fname=="" ? "<已删除>" : fname), hash}'

git verify-pack -v ./objects/pack/*.idx : 读取用 git pack-objects 命令创建的 Git 压缩包的 idx 文件,并验证 idx 文件和相应的压缩包文件。

  • -v : 验证数据包后,显示数据包中包含的对象列表和 delta 链长度直方图。
1
2
3
4
5
6
7
$ git verify-pack -v .git/objects/pack/*.idx
# 输出示例:
# 对象哈希 类型 大小(字节) ...其他列
# a1b2c3... blob 44564480 ...
# d4e5f6... blob 15938355 ...
# g7h8i9... blob 8703180 ...

git verify-pack -v

2>/dev/nullgit verify-pack 可能会输出一些警告或错误(比如找不到文件、权限问题等),加上 2>/dev/null 后,这些烦人的错误信息就不会显示在终端了q,让输出更干净,只显示我们想要的结果。

sort -k 3 -rn:按第3列进行排序

  • -k 3 : 按照第3列(字段)排序
  • -r : 倒序排列(reverse),从大到小
  • -n : 按数字大小排序(numeric),而不是按字符串

head -20 : 从排序结果中取出最大的20个对象

./objects/pack/\*.idx 表示裸仓库中的 idx 文件目录,如果不是从 <gitRepo>.git 文件夹中执行该命令,根据实际情况调整。

git verify-pack

步骤三:移除超大文件

从官网网站下载 bfg-repo-cleaner 工具, 并移动到 <gitRepo>.git 文件夹同级目录中,执行删除操作。

  • 删除指定大文件
1
java -jar <bfgPath>/<bfgName>.jar --strip-biggest-blobs <NUM> some-big-repo.git

--strip-biggest-blobs

步骤四:执行git gc

BFG会更新您的提交以及所有分支和标签,确保它们是干净的,但它并不会实际删除不需要的内容。回到 <gitRepo>.git 文件夹中,手动运行 git gc 命令,移除之前调用 git add 所创建的不可达对象,打包引用,修剪引用日志、rerere metadata 或过时的工作区。

1
git reflog expire --expire=now --all && git gc --prune=now --aggressive

git gc

步骤五:推送更新

最后,当你对仓库的更新状态感到满意后,在 <gitRepo>.git 文件夹中,执行以下命令,将其推回远程仓库

1
git push --mirror

注意事项

  1. bfg 默认会保护当前版本(HEAD)不去清理,如果当前 HEAD 也有要清理的文件,则需要使用 --no-blob-protection 参数

  2. bfg 操作后会修改 git commitID,多人开发的时候需要从远程仓库拉取最新代码后再开发,避免冲突问题

  3. 默认情况下,BFG 会保护你最新的提交(HEAD)不被修改,以防当前代码出问题。但是,当它清理历史记录时,如果某个文件在旧的提交中存在,但在你最新的代码中已经不需要了,BFG 会在该旧提交的位置创建一个空的占位文件来“顶替”它。所以操作BFG后,历史中的文件会被替换为 <fileName>.REMOVED.git-id,这是 BFG 的一个核心设计。这个占位文件本身是无害的,如果希望彻底删除它们,执行BFG时添加 --no-blob-protection 参数

移除私密数据

步骤一:克隆裸仓库

1
git clone --mirror https://example.com/some-big-repo.git

git clone --mirror

步骤二:创建替换规则文件

<gitRepo>.git 文件夹同级目录中,创建一个名为 bfg-replace.txt 的文件,文件名随意,该文件用于指定敏感信息匹配,此文件中的每一行都是一个匹配表达式。

1
2
3
4
5
6
7
8

password1="abc"===>password1="def"
password2="abc"==>
regex:password3=.+===>password3=''

password1="abc"===>password1="def" # password1="abc" 改为 password1="def"
password2="abc"==> # 移除password2
regex:password3=.+===>password3='' # 正则匹配替换,将password3 中的所有数据替换为空字符串
  • ==> 来指定匹配的文本应该被替换成什么(如果没有指定,就会被替换成默认值 ***REMOVED***
  • regex: 前缀说明表达式是一个正则表达式。

步骤三:删除敏感信息

1
java -jar <bfgPath>/<bfgName>.jar --replace-text <replacePath>/<bfg-replace>.txt --filter-content-including <glob> --no-blob-protection some-big-repo.git
  • <bfgPath> : BFG 工具所在路径,如果在 <gitRepo>.git 文件夹同级目录中,直接写 <bfgName>.jar 即可
  • <bfgName> : BFG 工具文件名,如 bfg-1.15.0
  • <replacePath> : 替换规则文件所在路径,如果在 <gitRepo>.git 文件夹同级目录中,直接写 <bfg-replace>.jar 即可
  • <bfg-replace> : 替换规则文件名
  • --filter-content-including <glob> : 匹配的文件,用于指定要处理的文件
  • some-big-repo.git : 裸仓库路径

--replace-text

步骤四:推送更新

最后,当你对仓库的更新状态感到满意后,在 <gitRepo>.git 文件夹中,执行以下命令,将其推回远程仓库

1
git push --mirror

git删除历史大文件
http://example.com/git/bfg/
作者
傅阳臣
发布于
2026年4月23日
许可协议