
事故發生時最怕三件事:不知道現在跑的是哪個版本、不知道是誰什麼時候改的、不知道回滾要回到哪裡。Git、CI、Release、Rollback 這四件事串在一起,就是為了讓你永遠不會遇到這三種恐慌。
先講結論
main 永遠可部署、版本號是合約(不是裝飾)、Release 必須可重現、Rollback 必須在事故之前就準備好。四條規則,缺一不可。
分支策略:不要過度設計
小團隊用 trunk-based:main + feature branch + tag 觸發 release。大團隊用簡化版 Git Flow:main(穩定)+ develop(整合)+ feature/*。
不管哪種,核心原則就一個:main 永遠可部署。任何未完成的功能都不能直接進 main。如果你的 main 時不時會壞,那不是分支策略的問題,是你沒有 CI gate。
版本號:SemVer 是給人看的合約
v1.6.0 不是流水號,它告訴所有人:major 是破壞性變更、minor 是新功能、patch 是修 bug。
tag 打錯或忘了打?後果就是你不知道 prod 跑的到底是哪個版本。所以 pipeline 要設規則:只有 tag 才允許 deploy。
git checkout main
git pull --rebase
git merge --no-ff develop
git tag -a v1.6.0 -m "Release v1.6.0"
git push origin main
git push origin v1.6.0Release Notes:寫給「半夜被叫起來的人」看的
好的 Release Notes 要回答:這版改了什麼、有沒有破壞性變更、出事要怎麼回退。
## v1.6.0
### New Features
- [EC-245] Checkout 支援折扣碼
### Bug Fixes
- [EC-239] 修正訂單金額四捨五入錯誤
### Breaking Changes
- API /v1/orders 回傳結構調整
### Rollback Plan
- Image 回滾至 v1.5.2
- Migration 為 additive,可安全回退看到了嗎?最後一定有 Rollback Plan。沒有 rollback plan 的 release,就像沒有降落傘的跳傘——你很有信心,但出事的時候你會後悔。
CI Gate:沒過就不能部署
CI 是 Release 的強制閘門。Lint、測試、安全掃描、build——任何一個失敗都不能部署。
stages:
- lint
- test
- build
- deploy
lint:
stage: lint
script:
- npm ci
- npm run lint
build:
stage: build
script:
- docker build -t registry.example.com/app/api:$CI_COMMIT_TAG .
- docker push registry.example.com/app/api:$CI_COMMIT_TAG
rules:
- if: $CI_COMMIT_TAGRollback:兩條路線
路線 A:Image 回退(最快)——直接把 image tag 換回上一版,不重 build。適合程式 bug。
路線 B:版本回退(完整)——checkout 舊 tag、重新 build、重新 deploy。適合需要同步 config 或 migration 的情況。
# 找上一個穩定 tag
git tag --sort=-creatordate | head -n 5
# 改 docker-compose 的 image tag 回 v1.5.2
# image: registry.example.com/app/api:v1.5.2
docker compose up -d
# 驗證
curl -sf https://api.example.com/health最容易踩的坑
Hotfix 沒有回合 develop:修了 prod 的 bug,但忘了 merge 回 develop。下次 release 又把 bug 帶回來。Hotfix PR 的 checklist 必須包含 merge back。
DB migration 不可回退:drop column、rename table 放在 release 裡,rollback 的時候 DB 回不去。原則是 migration 只做 additive,破壞性操作留到下一個 major。
Tag 被覆蓋:有人 force push 了一個已存在的 tag,prod 的版本跟 registry 裡的不一致。解法:禁止覆蓋 tag,prod 只允許 v* tag。
Release 不是「把 code 推上去」。Release 是「我有信心推上去,而且出事我知道怎麼退回來」。