处理历史提交中的大文件导致推送失败

适用场景:本地历史中曾提交过大文件(超过平台限制),后续虽然有新提交,但历史记录仍携带这些文件,导致推送被拒绝。需要从所有历史中彻底移除这些大文件,同时保留后续的正常提交。

所需工具git-filter-repo(安装:sudo apt install git-filter-repopip install git-filter-repo


第一步:重写历史,删除指定的大文件/目录

git filter-repo --path path/to/large-file --path path/to/large-dir/ --invert-paths --force
  • --path:指定要保留的路径(可重复使用)。
  • --invert-paths:反转含义,即排除这些路径,从所有历史提交中删除它们。
  • --force:当本地仓库不是全新克隆时,强制重写历史。

示例:若需要删除根目录下的 large.zipbin/ 整个目录,则写为 --path large.zip --path bin/ --invert-paths


第二步:清理无用对象,使删除真正生效

git reflog expire --expire=now --all
git gc --prune=now --aggressive

作用:重写历史后,旧的大文件对象仍残留在 .git/objects 中,并被 reflog 引用。这两条命令强制清空所有 reflog 记录,并立即修剪不可达的对象,物理删除这些大文件,从而真正缩小仓库体积。若不执行此步,推送时仍会尝试上传已删除的大文件,导致失败。


第三步:检查并重新添加远程仓库(若丢失)

git remote -v                     # 查看现有远程配置
git remote add origin <仓库地址>   # 若缺失则重新添加
git remote -v                     # 确认

注:filter-repo 可能会清除远程配置,必要时重新设置。


第四步:强制推送重写后的分支

git push origin <分支名> --force

使用 --force 是因为本地历史已被重写,需要覆盖远程分支。


注意事项

  • 操作前建议备份 .git 目录(cp -r .git /tmp/backup.git)。
  • 强制推送会改变远程历史,若多人协作,需提前通知团队成员。
  • 如果还有其他大文件,可在第一步中一并列出。

分支影响:默认重写全仓库历史(所有分支和标签)。若只想测试特定分支,可加 --refs <分支名>,但这样无法彻底回收大文件空间,后续合并时易复发。建议在操作前备份全仓库,并统一处理所有分支。