不能直接在main上改,因为会污染主干历史、无法追溯修复来源、破坏ci/cd稳定性;必须基于问题版本创建hotfix分支隔离修复,再通过cherry-pick合入develop、--no-ff合并回main并打新tag,最后清理分支。

紧急修复时为什么不能直接在 main 上改
因为线上出问题,你第一反应可能是切到 main 分支改完立刻 push——但这样会污染主干历史,且无法回溯“这次 hotfix 是哪次部署引入的”。Git 的分支本质是轻量指针,main 应该只承载经过验证的、可部署的代码。临时修复必须隔离,否则 CI/CD 流水线可能因未测试的提交触发异常构建。
实操建议:
- 从出问题的 tag 或 commit(比如
v2.3.1)拉出新分支,命名用hotfix/xxx格式,例如git checkout -b hotfix/login-500 v2.3.1 - 修复后立即 commit,消息带
fix:前缀和 issue 编号,如fix: login 500 error (#427) - 不要合并回
main,先推送到远端:git push origin hotfix/login-500
如何让 hotfix 同时生效于线上和开发主线
hotfix 不止要上线,还得合入后续开发分支(比如 develop),否则下次发版又会复现。但不能简单 git merge hotfix/xxx 到 develop,因为 hotfix 基于旧版本,直接合并会把 develop 里已有的改动也带进来,造成冲突或重复变更。
正确做法是「cherry-pick」:只取修复 commit,不带分支上下文。
- 先查出 hotfix 的修复 commit hash:
git log --oneline hotfix/login-500 - 切到
develop,执行:git cherry-pick <commit-hash></commit-hash> - 如果冲突,手动解决后
git add . && git cherry-pick --continue - 再推送到远端:
git push origin develop
修复上线后怎么安全合并回 main 并打新 tag
hotfix 分支本身是临时产物,上线验证通过后,必须合入 main 并打新 patch 版本 tag(如 v2.3.2)。但注意:不能用 fast-forward 合并,否则 main 上看不到 hotfix 是一个独立逻辑单元。
强制创建 merge commit,保留上下文:
git checkout main-
git merge --no-ff hotfix/login-500(--no-ff是关键) - 提交信息默认是
Merge branch 'hotfix/login-500',可编辑补充上线时间、影响范围 - 打 tag:
git tag -a v2.3.2 -m "fix: login 500 error, deployed 2024-06-12" - 推送:
git push origin main v2.3.2
容易被忽略的清理与同步细节
很多人 merge 完就以为结束了,结果下次切分支发现 hotfix 还在本地,或者远端分支残留。更麻烦的是,CI 系统可能误触发 hotfix/* 分支的构建任务。
- 本地删分支:
git branch -d hotfix/login-500 - 远端删分支:
git push origin --delete hotfix/login-500 - 通知团队成员更新本地
main和develop:git fetch --prune(--prune会自动清理已删除的远端跟踪分支) - 检查 CI 配置是否 exclude 了
hotfix/*分支,避免误构建
真正麻烦的不是操作步骤,而是忘记 --no-ff 或漏掉 --prune——前者让历史不可追溯,后者导致本地分支列表越来越乱,直到某天 git checkout hotfix/xxx 成功却拉不到最新提交,才意识到远端早删了。











