使用 git filter-repo清理大文件历史并成功推送到 GitHub:从问题到解决的完整记录
使用git filter-repo对提交记录进行管理,实现项目的版本控制
一、问题场景:
在项目开发过程中,我们经常会因为不小心将大文件(如 .pth 模型文件)提交到 Git 中,导致 GitHub 拒绝推送(限制 100MB 文件大小)。并且这一次失败推送会被记录在git历史中(即使在远程仓库也会保存这个历史),所以即便在删除这个大文件之后,再次推送时仍会将历史中的大文件进行推送,从而造成推送失败。本文记录一次完整的处理过程,帮助你彻底解决“历史提交包含大文件、GitHub 拒绝推送”等问题。
二、问题描述
我在 PyCharm 中开发项目,误将两个模型文件 vgg16_method1.pth 和 vgg16_method2.pth 提交到了 Git。本地删除并添加 .gitignore 后,Git 仍然在推送时提示:
remote: error: File vgg16_method1.pth is 540.00 MB; this exceeds GitHub's file size limit of 100.00 MB
三、尝试排查和误区:
1、控制台提示lfs
首先,我根据控制台提示的lfs(git的一个专门管理大文件的版本),去官网(https://git-lfs.com/)下载了一个扩展包,在bash中install lfs之后再次提交推送,再次出现超出文件限制提示,原因未知。另外控制台提出一个将大文件分为100MB小包进行上传的方案,各位可以参考。
2、添加.gitignore
网上给出了在项目文件夹中添加.gitignore文件的方式,可以在提交时忽略.gitignore文件中描述的特定文件。于是我创建了一个.gitignore文件(保存时文件类型需要选择‘所有’),并键入了以下内容:
*.pth
尝试后未果,遂继续探索其他方案。
3、使用 git filter-repo
经过gpt解答,得知本地删除文件后仍无法推送,原因是:Git 是版本控制系统,历史提交也会被上传。所以即便删除了文件,历史中仍然存在那次“错误的提交”。.gitignore 只能阻止新文件进入 Git,不会影响已经提交的文件。因此必须清除历史记录中的大文件。
并向我引入了git filter-repo工具,可以对git历史提交记录进行管理。
四、解决方案:使用 git filter-repo
安装 git-filter-repo
pip install git-filter-repo
或从 GitHub 安装:链接: [https://github.com/newren/git-filter-repo)
删除指定文件的历史记录
在项目根目录执行以下命令:
git filter-repo --path models/vgg16_method1.pth --path models/vgg16_method2.pth --invert-paths --force
- –path:指定要删除的文件路径
- –invert-paths:表示删除这些路径,保留其他所有内容
- –force:即使当前不是 fresh clone(必要)
可选:批量删除所有 .pth 文件
git filter-repo --path-glob '*.pth' --invert-paths --force
五、推送修改后的仓库到 GitHub
修改历史后,GitHub 上的旧历史还在,因此需要强制推送:
git push origin master --force
'master’可替换为实际分支名。注意:这会覆盖远程的历史记录,确保这是你想要的操作!
六、PyCharm 中的后续操作
-
推送是否恢复正常?
是的,一旦历史被清理并成功强制推送,你就可以在 PyCharm 中直接使用 Push 按钮正常推送,无需每次再 --force。 -
.pth 文件是否还会被提交?
不会。如果正确添加了 .gitignore:*.pth
PyCharm 中未被追踪的 .pth 文件会显示为灰色,不会再进入 Git 提交。
七、其他问题
-
清理大文件为什么要重写远程仓库历史?
因为 Git 会保留所有历史提交,必须彻底从历史中删除文件,才能真正释放它们。Git 是分布式版本控制系统,本地和远程的仓库是两个完整的仓库副本
每次做如下操作:- git commit:只修改本地仓库的历史记录
- git push:把本地仓库的历史记录“同步”到远程仓库(比如 GitHub)
所以问题的本质是:若先前已经提交并尝试推送过一个包含大文件的项目,并且最后推送失败了,即使我后续删掉了它、加了 .gitignore,个文件仍然在旧的提交记录(历史)中。
当我执行:git pushGit 就试图把整个提交历史(包括之前的版本)上传到 GitHub,但 GitHub 拒绝了,因为历史中包含超过 100MB 的文件。
git filter-repo 做的是:修改整个本地 Git 历史,删除某些提交中包含的大文件,这时,本地git历史已经重写,但 GitHub 上的远程仓库还保留旧历史(也就是含大文件的那份)。
所以必须执行:git push --force来告诉远程:“我现在用新的历史来覆盖远程仓库历史,请用我的新版本替换你那边的旧版本。”
总结:清理 .pth 是在本地做,但需要强制 push(–force) 才能让 GitHub 的远程仓库同步这份“被修改过历史”的仓库。 -
其他协作者怎么办?
如果是协作项目,其他人必须重新 clone 仓库,因为历史已经改变。
八、总结
这次经历让我深刻理解了 Git 的版本控制机制及其对“历史”的重视。也提醒我们:
- .gitignore 要在 添加大文件前 就配置好
- 提交前建议使用 git status 和 .gitignore 检查提交内容
- 使用 git filter-repo 时一定要谨慎操作、做好备份
更多推荐
所有评论(0)