Conventional Commits: padronizando mensagens

1. O que são Conventional Commits?

Conventional Commits é uma especificação leve para estruturar mensagens de commit em projetos Git. Criada por colaboradores do AngularJS e formalizada em 2019, essa convenção estabelece um formato padronizado que facilita a automação de tarefas como geração de changelogs e versionamento semântico.

O objetivo principal é criar um histórico de commits legível tanto para humanos quanto para máquinas. Enquanto um commit comum pode ser algo como "arrumei uns bagulhos", um commit convencional segue uma estrutura previsível que permite identificar rapidamente o tipo de mudança realizada.

A diferença fundamental está na consistência: commits convencionais seguem regras explícitas de formatação, enquanto commits comuns são livres e frequentemente ambíguos.

2. Estrutura básica de uma mensagem Conventional Commit

A estrutura padrão de um commit convencional é:

tipo(escopo opcional): descrição

[corpo opcional]

[rodapé opcional]

Exemplos práticos de mensagens válidas:

feat: adicionar validação de email no formulário de cadastro
fix(auth): corrigir falha de autenticação em sessões expiradas

O token JWT não estava sendo renovado corretamente após 30 minutos.
Isso causava logout inesperado para usuários ativos.

Closes #234
docs(readme): atualizar instruções de instalação

3. Tipos de commit mais comuns

A especificação define tipos obrigatórios e recomenda outros. Os principais são:

feat — nova funcionalidade para o usuário final:

feat: implementar busca por filtros avançados

fix — correção de bug:

fix: resolver crash ao carregar imagens grandes

docs — alterações em documentação:

docs: adicionar seção de contribuição no README

style — formatação de código (espaços, vírgulas, etc.), sem alterar lógica:

style: aplicar ESLint em todo o módulo de autenticação

refactor — refatoração de código sem adicionar funcionalidade ou corrigir bug:

refactor: extrair lógica de validação para helper separado

test — adição ou correção de testes:

test: adicionar testes unitários para função de parse

chore — tarefas de manutenção (dependências, build, configuração):

chore: atualizar dependências do projeto para versões recentes

4. Escopo e descrição: detalhando o commit

O escopo é opcional e indica a área afetada pelo commit. Deve ser um substantivo que nomeie o módulo, componente ou camada alterada:

feat(api): adicionar endpoint de listagem de usuários
fix(ui): corrigir alinhamento do botão de submit em mobile
refactor(database): otimizar consulta de relatórios mensais

Regras para a descrição:
- Usar verbo no imperativo ("adicionar", "corrigir", "remover")
- Não usar ponto final no final
- Limite de 50 caracteres (recomendação, não regra absoluta)
- Primeira letra minúscula
- Explicar O QUE foi feito, não COMO

Diferença entre descrição curta e corpo detalhado:

feat: implementar cache em memória para consultas frequentes

A implementação utiliza um Map simples com TTL de 5 minutos.
Isso reduz a carga no banco de dados em aproximadamente 40%
para consultas repetidas.

O cache é invalidado automaticamente quando há alterações
nos dados subjacentes via hooks do ORM.

5. Rodapé: referências e breaking changes

O rodapé é usado para informações extras, principalmente:

Breaking changes — mudanças que quebram compatibilidade:

feat(api): alterar formato de resposta de usuários

BREAKING CHANGE: O campo "nome_completo" foi substituído por
"nome" e "sobrenome" separadamente. Aplicações clientes
precisam ser atualizadas.

Referências a issues e pull requests:

fix: corrigir cálculo de frete para regiões remotas

Closes #89
Refs #45, #67

A formatação correta do rodapé exige uma linha em branco antes do rodapé, e cada metadado em sua própria linha. O token BREAKING CHANGE: deve estar em maiúsculas.

6. Ferramentas e automação com Conventional Commits

commitlint — valida mensagens de commit automaticamente:

# Instalação
npm install --save-dev @commitlint/{config-conventional,cli}

# Configuração no package.json
"commitlint": {
  "extends": ["@commitlint/config-conventional"]
}

standard-version — geração automática de changelog e versionamento:

# Instalação
npm install --save-dev standard-version

# Adicionar script no package.json
"scripts": {
  "release": "standard-version"
}

# Executar
npm run release

Integração com CI/CD — ferramentas como Husky podem executar commitlint antes de cada commit:

npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'

A combinação com versionamento semântico funciona assim:
- feat → incrementa versão minor (1.2.0 → 1.3.0)
- fix → incrementa versão patch (1.2.0 → 1.2.1)
- BREAKING CHANGE → incrementa versão major (1.2.0 → 2.0.0)

7. Boas práticas e exemplos reais

Erros comuns a evitar:

# RUIM: descrição vaga
fix: arrumar coisas

# RUIM: tipo incorreto
feat: corrigir bug no login

# RUIM: escopo confuso
chore(geral): várias alterações

Exemplos de commits bons:

feat(payment): adicionar suporte a pagamento via PIX

Implementa integração com API do Banco Central para
geração de QR Code dinâmico.

Closes #156
fix(api): retornar 404 quando usuário não encontrado

O endpoint /users/:id estava retornando 500 quando
o ID não existia no banco de dados.

Fixes #203

Adaptação para times específicos:

Times podem estender a especificação adicionando tipos customizados, desde que mantenham os tipos obrigatórios. Exemplos comuns:

  • perf: melhorias de performance
  • ci: alterações em configurações de CI
  • build: mudanças no sistema de build

O importante é documentar as regras do time em um arquivo CONTRIBUTING.md e garantir que todos sigam o padrão através de ferramentas automatizadas.

Referências