DEV Community

Denis Augusto
Denis Augusto

Posted on

"fix: ajustes": o commit que não ajuda ninguém (nem você)

Roda git log --oneline no seu projeto agora.

Vai. Roda mesmo.

Se apareceu uma sequência tipo ajustes, correção, wip, agora vai, ajustes 2, revert dos ajustes — bem-vindo ao clube. Todo mundo já escreveu essa novela.

O problema aparece três meses depois, quando você precisa entender por que aquela linha do OrderService está daquele jeito. Você roda um git blame, chega no commit e lê: "ajustes". Obrigado, eu do passado. Muito esclarecedor.

Histórico do Git não é burocracia. É a única documentação que envelhece junto com o código, porque está grudada nele. E ela custa 10 segundos a mais por commit pra ficar boa.

O problema: seu histórico não responde nenhuma pergunta

Olha esse log e tenta responder três coisas: o que entrou de novo? o que quebrou? dá pra fazer deploy?

a3f9c21 ajustes
7b2e881 correção do bug
0c41d7a wip
e91f3b2 mudanças solicitadas
5d8a04c agora vai
Enter fullscreen mode Exit fullscreen mode

Não dá. E isso tem custo real:

  • Code review — o revisor não sabe se ajustes é refactor inofensivo ou mudança de regra de negócio
  • Release — alguém tem que reler o diff inteiro pra escrever o "o que mudou nessa versão"
  • Investigação de buggit log --grep não serve pra nada quando tudo se chama a mesma coisa
  • Você mesmo, na segunda-feira — depois de um fim de semana, aquele wip não significa nada

O conceito: um prefixo, e só

Conventional Commits é uma convenção de mensagem tão simples que dá pra aprender no tempo de ler este parágrafo:

<tipo>(<escopo opcional>): <descrição>
Enter fullscreen mode Exit fullscreen mode

Os tipos que você vai usar em 95% dos casos:

  • feat — funcionalidade nova
  • fix — correção de bug
  • refactor — mudou o código sem mudar comportamento
  • test — mexeu em teste
  • docs — mexeu em documentação
  • chore — tarefa de manutenção (dependência, config, build)
  • perf — melhoria de performance

Na prática, o mesmo histórico de antes vira isto:

a3f9c21 feat(checkout): aplica cupom de desconto no total
7b2e881 fix(auth): corrige redirect após login expirado
0c41d7a refactor(orders): extrai cálculo de frete para Action
e91f3b2 test(checkout): cobre cupom expirado e cupom inválido
5d8a04c chore(deps): atualiza laravel/framework para 11.9
Enter fullscreen mode Exit fullscreen mode

Agora as três perguntas do começo se respondem só de bater o olho. E git log --oneline --grep "^feat" te dá a lista de tudo que entrou de novo desde a última tag. Sem esforço.

O escopo, o corpo e o !

O escopo entre parênteses é opcional, mas vale muito num projeto Laravel: checkout, auth, api, admin. É o "onde" da mudança, e permite filtrar por área.

Quando a mensagem de uma linha não conta a história toda, o corpo entra. Regra de ouro: o título diz o que, o corpo diz por quê.

fix(pedidos): usa transaction ao confirmar pedido

Sem a transaction, uma falha no gateway deixava o pedido como
confirmado e o estoque já debitado. Agora ou tudo entra ou nada entra.

Refs #412
Enter fullscreen mode Exit fullscreen mode

Esse commit vale ouro no git blame daqui a um ano. O diff mostra o que mudou; ele explica por quê.

E tem o caso da mudança que quebra compatibilidade — sinalizada com ! antes dos dois-pontos:

feat(api)!: remove campo legacy_id do UserResource
Enter fullscreen mode Exit fullscreen mode

Isso é um aviso gritante pra quem consome a sua API, e é o que separa uma release menor de uma release maior.

O CHANGELOG de graça

Aqui é onde o padrão deixa de ser organização e vira ferramenta.

Como a mensagem passa a ser legível por máquina, dá pra derivar a versão automaticamente, seguindo Semantic Versioning:

  • fix, chore, refactor → sobe o patch (1.2.3 → 1.2.4)
  • Tem feat no meio → sobe o minor (1.2.3 → 1.3.0)
  • Tem ! ou BREAKING CHANGE → sobe o major (1.2.3 → 2.0.0)

Ferramentas como o release-please ou o git-cliff leem o histórico, calculam a nova versão, geram o CHANGELOG.md agrupado por tipo e criam a tag. Num workflow do GitHub Actions, isso roda sozinho a cada merge na main.

Você não escreve release notes nunca mais. Elas são um subproduto de você ter escrito commits decentes.

Se quiser garantir o padrão no time, o commitlint rejeita mensagem fora do formato no hook commit-msg. Só uma dica: comece pela convenção combinada com o time e só depois automatize a validação. Ferramenta antes de acordo vira briga no PR.

Pegadinha: o prefixo não é mágico

Esse é o mal-entendido mais comum, e eu já vi acontecer:

fix: ajustes
feat: mudanças
chore: coisas
Enter fullscreen mode Exit fullscreen mode

Parabéns, agora seu histórico é inútil e padronizado. 😅

O prefixo é a menor parte do valor. O que faz diferença é a descrição ser específica: fix(auth): corrige redirect após login expirado conta uma história. fix: ajustes não.

Duas outras convenções que ajudam:

  • Imperativo, sem "eu"adiciona, corrige, remove. Completa a frase "esse commit ___ o quê?"
  • Commit atômico — uma mudança lógica por commit. Se você precisa de um "e" no meio da mensagem, provavelmente eram dois commits

E fica tranquilo: bagunçou na hora de escrever? git commit --amend conserta o último, e git rebase -i conserta o resto antes de virar PR.

Bônus: e agora?

Adota no próximo commit. Não precisa reescrever o passado nem convencer o time inteiro numa reunião — o histórico melhora a partir de hoje, e a diferença aparece sozinha no primeiro git log que alguém rodar.

Depois de um mês, roda isso e vê o que o seu projeto anda fazendo de verdade:

git log --oneline --since="1 month ago" | cut -d' ' -f2 | sort | uniq -c | sort -rn
Enter fullscreen mode Exit fullscreen mode

Se chore e fix dominam e mal aparece feat, você acabou de descobrir algo importante sobre onde o seu tempo está indo.

Antes de você fechar a aba

Vai lá, roda o git log --oneline de novo e me conta nos comentários: qual é a pior mensagem de commit que você encontrou (bônus se for sua)? 😄


Top comments (0)