Commits que geram changelog
Mensagem de commit é a única documentação que sempre acompanha o código. “ajustes”,
“fix”, “wip” custam caro no dia em que você faz git log procurando quando um
comportamento mudou — e impedem qualquer automação em cima do histórico.
Conventional Commits é uma convenção mínima que resolve as duas coisas: o histórico fica legível para pessoas e processável por máquina.
A convenção
Seção intitulada “A convenção”<tipo>(<escopo>)!: <descrição no imperativo, minúscula, sem ponto final>
<corpo opcional: por que, não o quê — o diff já mostra o quê>
<rodapé opcional: BREAKING CHANGE, Refs: #482>feat(checkout): aceitar pagamento em duas etapasfix(api): tratar timeout do gateway sem derrubar a requisiçãoperf(consulta): usar índice parcial em pedidos por statusdocs(readme): explicar variáveis de ambiente obrigatóriasrefactor(auth)!: remover suporte a token v1
BREAKING CHANGE: clientes com token v1 precisam reautenticar.Os tipos que cobrem quase tudo: feat, fix, docs, refactor, perf, test,
build, ci, chore. O ! (ou o rodapé BREAKING CHANGE:) marca quebra de
compatibilidade — é o que dispara o major.
Escreva a descrição como se completasse “Se aplicado, este commit vai…”. Isso resolve sozinho a dúvida entre imperativo e passado.
SemVer: o que cada número promete
Seção intitulada “SemVer: o que cada número promete”MAJOR.MINOR.PATCH é um contrato com quem consome:
- PATCH (1.4.2 → 1.4.3): correção compatível. Atualizar deveria ser seguro.
- MINOR (1.4.3 → 1.5.0): funcionalidade nova, compatível.
- MAJOR (1.5.0 → 2.0.0): quebra. Quem consome precisa agir.
O mapeamento com a convenção é direto: fix → patch, feat → minor, ! → major.
SemVer faz sentido para biblioteca, API pública, módulo, chart e imagem base — coisas que outras pessoas consomem. Para uma aplicação implantada só por você, versionar por data ou pelo commit costuma ser mais honesto: ninguém precisa negociar compatibilidade com você mesmo.
Changelog e release automatizados
Seção intitulada “Changelog e release automatizados”Com a convenção no lugar, versão e changelog deixam de ser trabalho manual:
on: push: { branches: [main] }permissions: contents: writejobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: { fetch-depth: 0 } # o histórico completo é o insumo - uses: googleapis/release-please-action@v4 with: { release-type: node }A ferramenta lê os commits desde a última tag, calcula a versão, gera o CHANGELOG.md,
abre o PR de release e cria a tag no merge. release-please, semantic-release e
changesets (bom para monorepo) resolvem o mesmo problema com estilos diferentes.
Para que isso não quebre, valide a mensagem antes do merge:
npx commitlint --from origin/main --to HEAD # no CInpx commitlint --edit "$1" # em commit-msg, localmenteO ponto crítico é a estratégia de merge. Com squash merge, o que vira commit no tronco é o título do PR — então é o título que precisa seguir a convenção, e é ele que o CI deve validar. Com merge normal, valide os commits da branch.
Quando a convenção atrapalha
Seção intitulada “Quando a convenção atrapalha”Ela custa pouco, mas não é gratuita, e há casos em que só gera fricção:
- Repositório de infraestrutura ou de conteúdo sem consumidores externos: o changelog automático não é lido por ninguém.
- Time que ainda escreve “fix bug” com tipo na frente:
fix: fixnão é melhor quefix. A convenção organiza, não substitui o hábito de explicar. - Commits de bot (atualização de dependência) inflando o changelog: filtre por tipo,
agrupe, ou marque como
chore.
Se você adotar, adote com verificação automática. Convenção opcional produz metade do histórico organizado, que é pior que nenhum — porque a automação em cima dele passa a mentir.
Próximo passo: a mensagem entra pelo pull request, e o pull request passa por revisão. Continue em Revisão de código que agrega.