起因
我们小团队 5 个人维护一个 monorepo,半年下来 git log 一塌糊涂:
fix bug / WIP / 更新一下 / aaaaa。每周一次的 release notes
得人工梳理,找哪个 commit 是新功能、哪个是 bug fix,每次半小时起步。
解决方案:conventional commits + 工具链强制
约定 commit 必须以类型开头:
feat: 新功能
fix: bug 修复
docs: 文档
style: 格式化(不影响功能)
refactor: 重构
perf: 性能优化
test: 测试
chore: 构建 / CI / 依赖
revert: 回滚
可选 scope:feat(auth): add OAuth、fix(api): correct status code。
breaking change 加 !:feat!: drop Node 16 support。
装 commitlint + husky
npm i -D @commitlint/cli @commitlint/config-conventional husky
# 初始化 husky
npx husky init
# commitlint 配置
echo "export default { extends: ['@commitlint/config-conventional'] }" \
> commitlint.config.js
# git hook
echo 'npx --no -- commitlint --edit "$1"' > .husky/commit-msg
chmod +x .husky/commit-msg
之后任何不合规范的 commit 直接被拒:
$ git commit -m "update stuff"
✖ subject may not be empty
✖ type may not be empty
✖ found 2 problems, 0 warnings
配合 commitizen 让团队上手
npm i -D commitizen cz-conventional-changelog
package.json 加:
{
"scripts": { "commit": "cz" },
"config": {
"commitizen": { "path": "cz-conventional-changelog" }
}
}
npm run commit → 交互式选 type / scope / subject,新人 30 秒上手。
自动生成 changelog
npm i -D conventional-changelog-cli
npx conventional-changelog -p angular -i CHANGELOG.md -s -r 0
把所有 commit 按 type 分类、按 scope 分组、生成 markdown changelog。
更进一步用 semantic-release:基于 commit type 自动 bump 版本号 + 生成
release notes + 发到 npm + 创建 GitHub release:
npm i -D semantic-release
.github/workflows/release.yml:
- run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
merge 到 main → CI 看到 feat: 自动发 minor 版本,fix: 发 patch,
feat!: 发 major。完全无人值守。
效果
- 一周后所有人习惯了;commit log 整洁可读
- 每月 release notes 从 30 分钟人工梳理 → 0 分钟自动生成
- PR review 时只看 commit 标题就知道改动性质
- 半年后回头看 git log,能复盘"上次的 OAuth feature 是哪天合的"
踩过的坑
-
第一次接入老仓库 husky 不工作:
.husky/目录权限不对,hook 文件
要可执行(chmod +x)。CI 里npm ci后 husky install 有时不触发,
preparescript 设husky保险。 -
commitizen 卡在 monorepo:subpath 项目里 commitizen 找不到配置。
根目录 .czrc 用绝对路径或者全局装 commitizen-cli。 -
rebase 时 commit-msg hook 反复触发:rebase 多个老 commit 都
过一遍 lint,老的破格式都 fail。一次性HUSKY=0 git rebase ...
绕过,整理完后再开。 -
scope 不要太多:定义 5-7 个核心 scope 就好(如
auth/api/
ui/db/infra)。每个目录一个 scope 反而没用,commit 信息
被 scope 撑长。 -
breaking change 容易忘:仅靠
!易遗漏。配合 PR template 让
提 PR 时勾"是否含 breaking" 列表,CI lint 时校验 commit footer 有
BREAKING CHANGE:描述。
登录后参与评论。