4.7 KiB
4.7 KiB
id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week
| id | title | type | domain | stack | tags | level | prerequisites | est_hours | related | week | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| devops.git.scenario.hotfix-and-leaked-secret | 线上紧急修复和密钥误提交:热修复分支、cherry-pick、清理历史和轮换密钥 | scenario | devops |
|
|
intermediate |
|
1.5 |
|
|
线上紧急修复和密钥误提交:热修复分支、cherry-pick、清理历史和轮换密钥
业务背景与问题
团队按“release 分支发版”的方式工作:main 上已经合入了下个版本的多个功能(未测试完),线上运行的是 release/1.4。周五下午出现两件事:
- 线上 1.4 版本有一个金额计算的 bug,需要马上修复,但不能把 main 上未测试的功能带上线。
- 有同事把含有大模型 API Key 的
.env文件提交并推送到了远程仓库。
约束
- 热修复要在一小时内上线,而且下个版本也必须包含这个修复。
- 仓库在公司内部平台上,有十几个人已经拉取过包含密钥的提交。
方案设计
热修复
- 从线上版本的标签 / release 分支创建
hotfix/amount-rounding; - 修复 + 补测试,走合并请求和 CI,合入
release/1.4,打标签v1.4.1发布; - 把修复提交
cherry-pick到 main(或从 release 合并回 main),保证下个版本不会“复活”这个 bug。
密钥泄露——顺序很重要:
- 第一时间轮换密钥:在模型服务商控制台作废旧 Key、生成新 Key,并更新部署环境的密钥配置。只要密钥进过远程仓库,就必须当作已经泄露,清理历史不能代替轮换。
- 检查旧 Key 的调用记录,确认是否有异常使用。
- 删除文件并加入
.gitignore;提供.env.example。 - 评估是否需要清理历史:用
git filter-repo从所有历史中移除文件,强制推送,通知所有人重新克隆;托管平台上的缓存、合并请求、fork 中可能仍有副本,需要联系平台管理员。 - 预防:提交前钩子扫描密钥(本仓库的
tools/check_sensitive.py),CI 中也执行密钥扫描。
关键代码
# 热修复
git switch -c hotfix/amount-rounding v1.4.0
# ……修改代码、补测试……
git commit -am "fix(order): 金额四舍五入改为银行家舍入前先转换为分"
# 合并请求合入 release/1.4 后打标签
git tag -a v1.4.1 -m "热修复:金额计算"
git push origin v1.4.1
# 带回 main
git switch main && git cherry-pick <修复提交哈希>
# 密钥:先轮换!然后再处理仓库
git rm --cached .env
echo ".env" >> .gitignore
git commit -m "chore: 移除误提交的 .env,并忽略该文件"
# 需要清理历史时(会改写所有提交哈希,需要团队协调):
git filter-repo --path .env --invert-paths
git push --force --all && git push --force --tags
git filter-repo 需要单独安装,用法以官方说明为准:https://github.com/newren/git-filter-repo 。在临时仓库里练习 cherry-pick、revert、reflog 的脚本见 examples/git-lab。
取舍
| 做法 | 优点 | 缺点 |
|---|---|---|
| 只轮换密钥 + 删除文件 | 快、不影响团队 | 旧密钥仍留在历史里(已作废,风险可控) |
| 轮换 + 清理历史 | 历史中不再有密钥 | 所有提交哈希改变,所有人要重新克隆;平台副本仍需单独处理 |
| 只清理历史不轮换 | —— | 错误做法:密钥可能已被复制 |
热修复用 cherry-pick 还是“release 合并回 main”:cherry-pick 精确,只带修复;合并回 main 能保证 release 上所有改动都回到 main,但可能带来冲突。团队约定一种即可。
易错点
- 热修复只改了 release 分支,忘了带回 main:下个版本 bug 又出现。
- 从 main 拉热修复分支:把未测试的功能带上线。
- 以为“删除文件再提交一次”密钥就安全了:历史里仍然有。
- 先花半天清理历史再轮换密钥:轮换应该是第一步。
- 强制推送清理后的历史却没通知团队:有人基于旧历史推送,又把文件带回来。
面试怎么讲
“线上版本出 bug 时,我从线上的标签拉热修复分支,修复并补测试后合入 release 分支打补丁版本发布,再 cherry-pick 回 main,避免把 main 上未测试的功能带上线。还处理过密钥误提交:第一步是作废并轮换密钥,检查调用记录;然后删除文件、加入 .gitignore,加上提交前的密钥扫描。是否清理历史要评估成本,清理时用 filter-repo 并通知团队重新克隆。”