本文主要记录误将本地数据库等大文件纳入 Git 版本库后的处理:用 git rm --cached 停止追踪并写入 .gitignore;若需从历史中剔除则使用 filter-branch(或 git-filter-repo)并 force push;以及 Gitea 上仓库体积暂增时的 GC 说明与协作/CI 注意点。
示例文件名来自某项目误提交的 SQLite 文件:app.db、app.db-shm、app.db-wal(原文为具体业务库名,此处泛化)。改写历史会变更 commit id,需团队与 CI 配合,操作前备份仓库。
背景说明
目标通常有两层:
- 工作区保留文件,但之后不再提交(
--cached+.gitignore)。 - 历史中也不再保留大文件,以缩小
.git(filter + gc + force push)。
只做第 1 步时,旧 blob 仍在历史里,clone 体积不会明显下降。
停止追踪并忽略(保留本地文件)
在仓库根目录:
git rm --cached app.db app.db-shm app.db-wal
--cached 只从索引移除,不删工作区文件。
写入 .gitignore:
# 本地数据库(勿提交)
app.db
app.db-shm
app.db-wal
# 或:app.db*
提交:
git add .gitignore
git commit -m "chore: stop tracking local database files"
之后 git status 不应再把这些文件列为未跟踪待添加(已被 ignore)。git push 后,远端当前树不再包含它们;历史提交里若曾经加入,blob 仍在,需下一节处理。
从历史中剔除(高风险)
风险
- 重写所有相关 commit,改变 hash。
- 协作者基于旧历史的分支会分叉;错误
pull/push可能把大文件带回来。 - 必须 force push 才能更新远端默认分支。
- 操作前复制整个项目目录或确认远端可回滚。
使用 filter-branch(无额外依赖)
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch app.db app.db-shm app.db-wal" \
--prune-empty --tag-name-filter cat -- --all
清理 filter-branch 备份引用并 GC:
rm -rf .git/refs/original/
# Windows PowerShell: Remove-Item -Recurse -Force .git\refs\original\
git reflog expire --expire=now --all
git gc --prune=now --aggressive
再推远端(确认团队已知晓):
git push origin --force --all
git push origin --force --tags
更现代、通常更快的工具是 git-filter-repo,语法不同,生产团队可优先评估。
为何 Gitea 显示体积反而变大
force push 之后,服务端往往同时保留新历史与尚未回收的旧对象,体积可能短期上升(例如数 MB 涨到接近两倍)。本地 gc 不会自动等于服务端已 gc。
处理方式:
- 站点管理中对仓库执行 Garbage Collection(路径因 Gitea 版本而异,常见在管理员配置页)。
- 等待 Gitea 定时 GC cron。
- 有服务器权限时,在对应 bare 仓库目录执行
git reflog expire+git gc(路径形如<gitea-data>/gitea-repositories/<owner>/<repo>.git,以实际部署为准)。
GC 完成后体积应回落。
协作方如何同步
不要在未沟通时对已重写分支普通 git pull 再推。
可选:
A. 无本地未推送改动:删目录重 clone
git clone <repo-url>
B. 有本地修改:stash 后硬对齐远端
git stash push -u -m "before history rewrite sync"
git fetch origin
git reset --hard origin/<branch>
git stash pop
冲突时暂停推送,人工解决后再提交。
CI / Docker 注意
- Runner 缓存的旧 workspace 可能仍基于旧历史:清理 Runner 缓存,或临时将策略改为全量
clone跑通一次。 - Docker 若
COPY过含大文件的上下文,旧镜像层仍占空间:docker build --no-cache,必要时docker image prune。 - 应用若依赖仓库内 db 文件:取消追踪后,容器启动需自动初始化库或挂载独立数据卷,避免“镜像/仓库里没有 db 就起不来”。
验证结果
| 步骤 | 判断 |
|---|---|
| rm –cached | 工作区文件仍在;git ls-files 不再列出它们 |
| gitignore | 修改 db 不再出现在 git status |
| filter + gc | 本地 .git 体积下降;git log -- all -- app.db 无历史路径(或符合预期) |
| 远端 | force push 成功;GC 后 Gitea 仓库体积回落 |
注意事项
- 密码、密钥、生产库文件一旦进过 Git,即使后来删除,仍视为可能泄露,需轮换凭据。
--force推送受保护分支时需管理员权限;优先走团队约定流程。- 本文不鼓励在共享主干上频繁 rewrite;能只 untrack 就不必改历史。
参考资料
- git-rm
- gitignore
- git-filter-branch
- git-filter-repo
- Gitea 文档:仓库维护 / GC(按自建版本查阅)