改写历史的风险
改写历史会改变提交哈希,进而影响所有克隆、分支、标签、评审记录、镜像仓库与构建缓存。它不是一条命令就能收尾的动作:参考引用更新、旧对象清理、强制推送与团队通知都要纳入计划,中段任何一步漏掉都会留下旧历史的入口。
基本信息
| 影响面 | 分支、标签、评审记录、镜像仓库、流水线缓存、外部链接 |
|---|---|
| 清理陈旧引用 | git reflog expire --expire=now --all 清除可恢复指针 |
| 回收对象 | git gc --prune=now 删除不再可达的对象 |
| 推送方式 | 按仓库策略强推分支与标签,并通知所有人重新克隆或重置 |
| 前置准备 | 在裸克隆上操作,冻结推送并约定时间窗 |
典型使用场景
- 误提交了包含密码或密钥的文件,需要彻底移除
- 仓库体积过大,需要剥离历史中的大文件
- 目录结构调整需要重写文件路径
- 拆分仓库或把多个仓库合并成一个
- 合规要求彻底删除特定内容并留下处理记录
收尾命令示例
收尾命令示例
git clone --no-local /srv/git/app.git app-rewrite # 在裸克隆上操作
git filter-repo --path configs/prod.env --invert-paths # 删除该文件的历史
git for-each-ref --format='%(refname)' refs/original/ | xargs -r -n1 git update-ref -d
git reflog expire --expire=now --all # 让旧对象失去引用保护
git gc --prune=now
git push --force-with-lease --all # 强推分支
git push --force-with-lease --tags # 强推标签旧历史残留的原因
| 原因 | 说明 | 处理 |
|---|---|---|
| 日志仍指向旧提交 | 对象被引用保护,回收不会删除 | 先让日志过期再回收 |
| 标签未更新 | 旧历史仍可由标签访问到 | 同步强推标签 |
| 镜像仓库未同步 | 其他分发源仍是旧历史 | 逐个镜像重写并通知 |
| 评审记录仍可访问 | 平台缓存的差异仍指向旧提交 | 按平台策略处理并说明 |
在共享仓库操作前先冻结推送、发公告并约定时间窗:改写历史无法低调完成,晚发现的人会带着旧历史继续开发,之后还要再清一遍。
重写后所有人需要重新克隆或按说明重置本地分支,团队要提前准备通知模板,写清新的克隆方式与本地未推送改动的处理办法。