一、问题场景:

在项目开发过程中,我们经常会因为不小心将大文件(如 .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 push
    

    Git 就试图把整个提交历史(包括之前的版本)上传到 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 时一定要谨慎操作、做好备份
Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐