告别臃肿!使用 git-filter-repo 优雅清理 Git 历史记录

痛点:为什么我们的 .git 文件夹越来越大?

在日常开发中,你是否遇到过这样的情况:项目代码本身没多少,但执行 git clone 时却要下载几个 G 的数据?或者偶尔手抖,把包含密码的配置文件、测试用的 .mp4 视频、甚至是庞大的 .node_modules 目录提交到了 Git 中。

即便你随后立刻执行了 git rm 删除了这些文件,并在最新的 commit 中修复了问题,Git 的核心机制依然会忠实地在历史树中永久保留它们。这些"历史遗留物"会持续占用磁盘空间,拖慢拉取代码的速度。

为了彻底将它们从历史记录中抹除,我们需要重写 Git 历史。

过去,我们常使用 git filter-branchBFG Repo-Cleaner。但今天,我要向大家强烈推荐 Git 官方推荐的替代工具:git-filter-repo。它不仅速度极快,而且功能强大、语法简洁。


神器登场:什么是 git-filter-repo?

git-filter-repo 是一个用于重写 Git 历史记录的通用工具。根据 Git 官方文档的建议,由于 git filter-branch 存在性能和安全性问题,git-filter-repo 已经成为了执行此类任务的首选标准。

1. 安装指南

安装过程非常简单。由于它是基于 Python 编写的,最推荐的安装方式是使用 pip

bash 复制代码
# 确保你的系统中已安装 Python 3
pip install git-filter-repo

如果你是 macOS 用户,也可以直接使用 Homebrew:

bash 复制代码
brew install git-filter-repo

实战演练:常见场景清理指南

⚠️ 终极警告: 重写历史会改变所有受影响 commit 的 Hash 值。在进行以下任何操作前,请务必备份你的项目,或者在一个全新的 clone 目录中进行测试!

场景一:批量删除特定后缀的媒体文件(如 .png 和 .mp4)

这也是我在实际开发中最常遇到的情况。假设我们需要把项目中所有历史提交里的图片和视频彻底清理掉,只需在项目根目录执行:

bash 复制代码
git filter-repo --path-glob '*.png' --path-glob '*.mp4' --invert-paths --force

参数解析:

  • --path-glob: 用于指定匹配模式。
  • --invert-paths: 这是一个非常巧妙的参数,它告诉工具:保留除了匹配路径之外的所有文件。换句话说,就是删除匹配到的文件。
  • --force: 如果你不是在一个 fresh clone(全新克隆)的裸仓库(bare repo)中操作,工具会出于安全考虑阻止你,加上此参数可强制执行。

场景二:删除特定的敏感目录或文件

如果有人不小心把 config/database.yml(包含线上数据库密码)提交了,你可以这样抹除它:

bash 复制代码
git filter-repo --path config/database.yml --invert-paths --force

删除整个文件夹(比如不小心提交的 dist 编译产物):

bash 复制代码
git filter-repo --path dist/ --invert-paths --force

场景三:将某个子目录提取为独立的新仓库

有时候我们需要把一个巨型单体仓库中的某个模块(如 src/utils/)单独拆分出来。这个工具也能轻松搞定:

bash 复制代码
# 这会保留 src/utils 下的内容,并将其提升为仓库的根目录,丢弃其他所有文件
git filter-repo --subdirectory-filter src/utils/

清理后的收尾工作(非常重要!)

由于 git-filter-repo 是具有破坏性的,为了防止意外的误操作覆盖远程分支,工具在执行完毕后会自动移除你的 remote(远程源)配置

因此,当你确认本地仓库清理无误,且 .git 文件夹体积显著减小后,需要重新关联并推送到远程:

bash 复制代码
# 1. 重新添加远程仓库地址
git remote add origin <你的远程仓库URL>

# 2. 强制推送所有分支到远程服务器
git push origin --force --all

# 3. 如果你有标签(Tags),也需要强制推送标签
git push origin --force --tags

团队协作注意事项:

由于你重写了公共历史,团队中的其他成员不能 再使用简单的 git pull。他们需要重新 clone 仓库,或者使用 git fetch origin && git reset --hard origin/main(假设主分支是 main)来强制同步你清理后的最新历史。


总结

使用 git-filter-repo 可以极其高效地给 .git 目录"减肥"。日常开发中,我们还是应该养成良好的习惯,提前配置好 .gitignore 文件。对于确实需要版本控制的大型二进制文件,建议尽早引入 Git LFS (Large File Storage) 进行管理。

希望这篇文章能帮你解决 Git 历史清理的难题!如果有任何问题,欢迎在评论区留言讨论。

相关推荐
前端Hardy1 小时前
杀疯了!Git 2.54 正式发布,3个封神新特性,效率直接翻倍!
git
Eloudy3 小时前
迁移带有 git lfs 功能的 github 仓库
git·github
xlq223224 小时前
1.git
git
运维全栈笔记5 小时前
零基础掌握Jenkins CI/CD:Java项目自动构建与部署全流程指南
git·servlet·ci/cd·gitee·自动化·jenkins·devops
菜萝卜子6 小时前
【Git】GitLab 18.9 全局服务器钩子(Server Hooks)官方规范与落地实践
服务器·git·gitlab
用户11481867894847 小时前
Git Stash 丢失后的完整找回指南
前端·git
Ting.~7 小时前
GIT详解
java·笔记·git
克拉拉KLARA8 小时前
vscode禁用在git提交中插入ai coauthor copilot
git·vscode·copilot
水无痕simon9 小时前
05 Git 基础 – 查看提交历史
git
谢斯9 小时前
【GIT】子模块初始化与排错记录
git