GitHub 大文件推送避坑指南
问题现象
当你执行 git push 时,可能会遇到类似以下错误提示:
remote: error: File data/wmt_zh_en_training_corpus.csv is 1968.67 MB; this exceeds GitHub's file size limit of 100.00 MB
remote: error: GH001: Large files detected. You may want to try Git Large File Storage.
! [remote rejected] master -> master (pre-receive hook declined)
根本原因
GitHub 对单个文件的大小限制为 ≤ 100MB。即使你在后续提交中删除了该大文件,它在 Git 的历史记录中仍然存在,导致推送失败。解决此问题的关键在于清理仓库历史中的大文件记录,或者使用 Git LFS(Large File Storage)来管理大文件。
方案一:Git LFS(官方推荐,保留完整版本历史)
Git LFS 的核心思想是将仓库中的大文件替换为轻量级的指针文件,实际的大文件内容则存储在远端的 LFS 服务器上。这样,你的 Git 仓库体积就能保持轻量。
步骤 1 · 安装并初始化 LFS
- 访问 https://git-lfs.github.com/ 下载并安装对应你操作系统的 Git LFS。
安装完成后,在终端(命令行)中执行一次全局初始化:
git lfs install
步骤 2 · 跟踪大文件类型(或单个文件)
假设你的大文件是 .csv 格式(请根据实际情况替换扩展名或路径),使用以下命令跟踪:
git lfs track "*.csv" # 或者精确指定文件路径
# git lfs track "data/wmt_zh_en_training_corpus.csv"
此命令会在你的仓库根目录生成或修改 .gitattributes 文件。必须将此文件加入版本库并提交:
git add .gitattributes
git commit -m "chore: 配置 Git LFS 跟踪 csv 文件"
步骤 3 · 迁移已有历史中的大文件到 LFS(关键!)
由于大文件已经存在于之前的提交历史中,我们需要使用 git lfs migrate 命令重写历史,将这些文件替换为 LFS 指针:
git lfs migrate import --include="data/wmt_zh_en_training_corpus.csv" --everything
--include:指定要转换的文件路径(支持逗号分隔多个文件,也支持通配符*)。--everything:转换所有分支和标签的历史记录。- 注意:此操作会修改历史提交的 SHA 哈希值,后续需要强制推送。
执行后,验证迁移结果:
git lfs ls-files # 应列出被 LFS 管理的文件
步骤 4 · 强制推送到远程
由于本地仓库的历史记录已被重写,必须使用 --force 选项覆盖远程仓库的分支:
git push origin master --force
- 重要提示:如果远程分支(如
master)设置了保护规则,你可能需要先在 GitHub 仓库的Settings→Branches中临时禁用分支保护,才能执行强制推送。也可以尝试使用更安全的--force-with-lease。
后续协作提醒
其他协作者在拉取更新前,需要执行:
git fetch --all
git reset --hard origin/master # 强制将本地分支重置到远程状态
或者,更推荐的做法是让协作者重新克隆仓库(git clone),以确保历史记录完全一致。克隆后,使用 git lfs pull 来拉取 LFS 管理的实际文件内容。
方案二:备选方法(不保留大文件历史)
如果不想使用 Git LFS,或者文件过大超出 LFS 配额限制,可以考虑以下方法。⚠️ 注意:这些方法会丢失该大文件在 Git 中的版本历史,仅保留最后一次提交的快照。
方法 A:彻底移除大文件历史 (git filter-repo / BFG)
使用强大的 git filter-repo 工具(需单独安装)从所有历史提交中删除指定的大文件:
git filter-repo --path data/wmt_zh_en_training_corpus.csv --invert-paths
- 此命令会彻底删除历史中该文件的记录,同样会改变所有相关提交的哈希值。
- 执行后,如果需要保留这个大文件的最新版本(但不再追踪其历史),可以重新添加它(并考虑用 LFS 或方法 B 处理),或者直接删除它。之后也需要强制推送 (
git push --force)。
方法 B:分割大文件 + 外部存储
- 分割文件:使用工具(如 Linux/macOS 的
split命令或 Windows 的 7-Zip)将大文件分割成多个小于 100MB 的分片文件(例如file.part1,file.part2)。 - 提交分割文件:将这些小文件添加到 Git 仓库并提交。同时,添加一个
README.md文件说明如何合并这些分片(例如使用cat file.part* > original_file或 7-Zip 解压)。 - 或使用外部存储:将原始大文件上传至云存储服务(如 Google Drive, Dropbox, 腾讯云 COS 等),在仓库中提供一个下载链接的说明文件。
- 缺点:完全失去了对该文件的版本控制能力。使用者需要手动操作才能获得完整文件。
常见错误 & 注意事项
- 只删文件再提交无效:如果在本地删除了大文件然后提交,Git 历史中该文件之前的版本记录依然存在。必须使用
git lfs migrate或git filter-repo等工具重写历史才能彻底解决。 - Git LFS 配额限制:GitHub 为免费用户提供的 Git LFS 存储空间为 1GB,每月带宽也为 1GB。对于非常大的文件或项目,可能需要购买 GitHub Pro/Team 套餐,或者考虑自建 LFS 服务器。
- 强制推送后的团队协作:强制推送 (
git push --force) 会覆盖远程历史。务必通知所有协作者。建议他们备份本地更改后,重新克隆仓库 (git clone),或者极其谨慎地使用git fetch --force配合git reset --hard。 - 受保护分支:如果目标分支(如
master)在 GitHub 上受保护,默认禁止强制推送。需要在仓库的Settings→Branches中临时调整分支保护规则,或者使用--force-with-lease(它会在覆盖前检查远程分支是否是你期望的状态,相对安全一些)。
极简回退操作(仅适用于未分享的、仅一次的误提交)
如果你刚刚不小心提交了一个大文件,并且还没有进行任何 git push 操作,也没有其他协作者拉取过你的这次提交,那么一个简单的回退方法是:
git reset --soft HEAD~1 # 撤销上一次提交,但保留工作区的文件改动
撤销后,你可以按照方案一的步骤(安装 LFS、跟踪文件、添加 .gitattributes、提交),或者用 git rm --cached 彻底移除大文件(如果不需要它)后再做一次新的提交。然后正常推送(无需强制)。
完整命令速查表 (Git LFS 方案)
# 1. 初始化 LFS
git lfs install
# 2. 跟踪大文件 (以 .csv 为例,根据实际情况修改)
git lfs track "*.csv"
git add .gitattributes
git commit -m "setup lfs"
# 3. 迁移历史中的大文件 (替换路径)
git lfs migrate import --include="data/*.csv" --everything
# 或者只针对单个文件
# git lfs migrate import --include="data/wmt_zh_en_training_corpus.csv" --everything
# 4. 强制推送
git push origin master --force
# 5. 验证
git lfs ls-files

