repo-filter的安装
- 这个是依赖于
python的pip的 所以需要先安装python - 安装
repo-filter
1 | python -m pip install --user git-filter-repo # 对于个人用户安装 |
在windows中就被安装在site-packages
使用场景
- 删除仓库历史中的大文件 参数解释:
1
git filter-repo --force --invert-paths --path large_file.txt
- –force:允许覆盖当前仓库。
- –invert-paths:保留不匹配路径的提交,这里是反选,即删除匹配路径的文件。
- –path large_file.txt:指定要从历史中删除的文件名。
- 替换文件内容 在
1
git filter-repo --replace-text <replacement-file>
<replacement-file>中定义替换规则。 - 根据大小过滤文件 删除大于10MB的二进制文件。
1
git filter-repo --strip-blobs-bigger-than 10M
高级操作
下面给出一条一次性完成「删除仓库里全部文件并统一重写所有提交信息」的 git filter-repo 命令示例。
(⚠️ 会彻底清空工作目录内容并改写历史,务必先备份!)
✅ 1. 克隆裸仓库(避免工作区干扰)
1 | git clone --mirror https://github.com/you/repo.git |
✅ 2. 删除全部文件
1 | git filter-repo --invert-paths --path '*' --all |
解释
--invert-paths让--path '*'变成“排除所有文件”,即保留空提交,但把文件全部删掉。--all同时作用于所有分支、标签。
✅ 3. 批量重写所有提交信息
创建一个文本文件 msg-map.txt,每行一条替换规则(支持正则):
1 | # 旧内容<tab>新内容 |
然后执行:
1 | git filter-repo --replace-message msg-map.txt |
如果想完全统一成一句话,可直接:
1 | echo '.* Initial commit' | git filter-repo --replace-message - |
✅ 4. 强制推回远程
1 | git push --force |
所有协作者需重新克隆。
小结
| 目的 | 命令 |
|---|---|
| 删除全部文件 | git filter-repo --invert-paths --path '*' --all |
| 重写所有提交信息 | git filter-repo --replace-message <map-file> |
注意以上的做法是错误的可以重置message但是无法删除文件
总之依靠git filter-repo --invert-paths --path 删除文件是不靠谱的
使用commit-callback 删除文件
下面给出 纯 git-filter-repo 官方思路 的「终极方案」:
用 --commit-callback(而不是 --path 或 --strip-blobs-bigger-than)
在 Python 层里把 每一次提交直接置空(tree = 空树),并且把消息统一改掉。
这样无论普通文件、子模块、LFS、任何 blob 都会消失,100 % 成功。
✅ 1. 进入裸仓库
1 | git clone --mirror https://github.com/you/repo.git |
✅ 2. 一条命令:空树 + 统一消息
1 | git filter-repo --force |
说明
commit.file_changes = []:把本次提交携带的 所有文件、子模块、重命名、删除 全部抹掉 → 生成空树。commit.message = b"Initial commit":提交信息统一重写成你想要的文字。--force:避免“已过滤过”的拒绝提示。
✅ 3. 验证
1 | git ls-tree -r HEAD # 没有任何文件/子模块 |
✅ 4. 强制推回
1 | git push --force |
⚠️ 备份提醒
这条命令会永久重写整个仓库历史,务必先在别处备份裸仓库或打 tag 再做。
这个操作下会导致整个仓库空 因为git 会丢掉空提交默认
所以
出现这条提示说明:你刚才那条 --commit-callback 把「所有提交」都变成了「空提交」,结果 filter-repo 认为这些空提交没有实际意义,于是把它们全部丢弃了,仓库里一个提交都不剩,HEAD 指向的 main 分支也就空了。
为什么会这样
git-filter-repo 的默认策略是:
如果一个提交被清空后 既没文件变更,又没父级变化,它就 会被删除,以免留下一堆无意义的空节点。
所以commit.file_changes = []后,所有提交都被当成“可被丢弃”,最终仓库归零。
正确做法:保留空提交
告诉 filter-repo “即使空提交也给我留下”,加 --prune-empty never:
1 | git filter-repo --force --prune-empty never |
--prune-empty never:强制保留空提交。- 不写
--message-callback:提交信息保持原样。
注意以上的命令写法是针对bash的
如果考虑到powershell应该这么写
1 | git filter-repo --force --prune-empty never --commit-callback "commit.file_changes=[];commit.message=b'Initial commit'" |
验证
1 | git log --oneline # 所有原提交都在,只是 tree 为空 |
推送
1 | git push --force |
仓库现在就是「所有历史提交都在,但每个提交里都没有文件」的状态。
后记
本来这个repo-filter是由python api的但是我没有成功过
1 | import git_filter_repo as fr |



