如何在指定日期前清理Git仓库中的二进制文件?
清理Git仓库中旧Simulink二进制文件的解决方案
问题分析
你之前使用git filter-repo的命令存在两个核心问题:
--refs HEAD~50 --refs mybranch限定了仅处理该提交范围内的内容,导致分支的其他部分被过滤,最终分支消失;--invert-paths是全局生效的,会直接排除所有.slx文件,而非仅旧提交中不再使用的文件,完全不符合你的需求。
以下是符合你规则的解决方案,核心思路是:保留当前HEAD中所有文件,保留指定提交/日期后的完整历史,仅清理指定节点前、且当前HEAD不再使用的Simulink二进制文件(可选择删除或替换为空文件)。
准备工作
- 镜像克隆仓库:必须用
--mirror克隆,确保能处理所有分支和标签:
git clone --mirror <远程仓库URL> my-repo-mirror cd my-repo-mirror
- 备份镜像仓库:复制整个
my-repo-mirror目录,避免操作失误导致数据丢失。 - 获取当前HEAD中需保留的Simulink文件列表:
git ls-tree -r HEAD --name-only | grep -E '\.(slx|sldd)$' > keep-these-simulink-files.txt
方案一:按提交数保留历史(比如最近50次提交)
1. 编写过滤脚本
创建filter-simulink.py脚本,实现基于提交节点的过滤逻辑:
import sys import git_filter_repo as fr # 读取需保留的Simulink文件列表 with open('keep-these-simulink-files.txt', 'r') as f: keep_files = set(f.read().splitlines()) # 获取最近50次提交的起始节点哈希 # 先在终端执行:git rev-parse HEAD~50,把结果替换到这里 cutoff_commit = '<HEAD~50的哈希值>' def filter_callback(commit, metadata): # 判断当前提交是否在保留节点之后(含节点本身) is_after_cutoff = False try: result = fr.run_command(['git', 'merge-base', '--is-ancestor', cutoff_commit, commit.hexsha]) is_after_cutoff = (result == 0) except: pass if is_after_cutoff: # 保留该提交的所有文件,不做修改 return # 处理保留节点之前的提交:清理不在保留列表的Simulink文件 new_files = [] for file in commit.files: if file.filename.endswith(('.slx', '.sldd')): if file.filename not in keep_files: # 若需替换为空文件,替换下方代码为注释中的内容 # 替换为空文件: # empty_blob = fr.Blob.from_string(b'') # file.blob = empty_blob # 若需直接删除,跳过该文件: continue new_files.append(file) else: # 非Simulink文件全部保留 new_files.append(file) commit.files = new_files if __name__ == '__main__': fr.FilteringOptions.parse_args() fr.RepoFilter(commit_callback=filter_callback).run()
2. 执行过滤
python filter-simulink.py
3. 验证结果
- 查看仓库体积变化:
du -sh . - 检查分支完整性:
git branch -a - 验证旧提交中的文件:
git show <旧提交哈希>:<目标slx文件>,确认不在保留列表的文件已被删除/替换为空。
4. 推回远程仓库
注意:此操作会重写仓库所有历史,必须通知所有协作成员重新克隆仓库,禁止基于旧历史推送!
git push --force
方案二:按日期保留历史
若需按指定日期(比如2024-01-01)过滤,只需修改脚本中的is_after_cutoff判断逻辑:
from datetime import datetime # 指定 cutoff 日期 cutoff_date = datetime(2024, 1, 1) # 获取提交的提交时间 commit_date = datetime.fromtimestamp(commit.committer_date.timestamp()) # 判断提交是否在指定日期之后 is_after_cutoff = (commit_date >= cutoff_date)
其余步骤与方案一完全一致。
关键注意事项
- 历史重写后,所有协作成员必须丢弃本地旧仓库,重新克隆新仓库;
- 操作前务必备份镜像仓库,避免不可逆的数据丢失;
- 若需要保留旧提交中当前仍在使用的Simulink文件,脚本会自动保留(因为这些文件在
keep-these-simulink-files.txt列表中); - 替换为空文件的操作会保留文件路径,但清空内容,适合需要保留目录结构的场景。
内容的提问来源于stack exchange,提问作者Waldi
相关产品推荐
相关产品推荐

