O que são “Commits Semânticos”

Commits semânticos (Semantic commits), também conhecido como Commits Convencionais (Conventional commits), são a melhor forma de documentação da execução de sua implementação de aplicações, por conferir contexto à gestão de mudanças de seu código fonte. Commits semânticos são considerados boa prática no uso de Git tanto quanto de outros VCS (sistemas de versionamento de código).

Por que usar commits semânticos

Você deve escrever em uma mensagem de commit do GIT não apenas o que você fez, mas também especificar POR QUE você fez aquela alteração no código.

Isso traz semântica para a mensagem de commit e facilitará o rastreamento de alterações ao longo do tempo e também pode ser útil na solução de problemas.

Exemplos:

❌ adiciona endpoint ✅ adiciona endpoint para permitir que os usuários baixem o histórico de compras

❌ atualiza dependências ✅ atualiza dependências para resolver vulnerabilidades de segurança

❌ corrige bug ✅ corrige bug para resolver renderização inconsistente em dispositivos móveis

Mensagens de commit claras e descritivas fazem parte da qualidade interna do software. Então, para ser semântico nos commits, você pode escrever as mensagens dando o contexto de POR QUE a mudança foi feita, e também padronizar a forma do commit usando commits convencionais.

A seguir, vamos entender o problema e, em seguida, dar uma olhada em como usar o commit convencional.

O problema quando não se usa commits semânticos

Escrever mensagens de commits nada claras, como task done ou bug fixed não auxiliam na manutenção de código e no histórico evolutivo do sistema.

Analise o histórico de mensagens de commit a seguir:

commit e71fcf2022b6135e18777bdc58c2ac3180202ec7
Author: mazerdev
Date: Tue Apr 24 01:25:48 2021 +1000
Extrair informações

commit d1952883b05b685f2d22e4c41b4fbc4362fd6bd0
Author: mazerdev
Date: Mon Apr 23 22:16:50 2021 +1000
[WIP] integração

commit 74b8920d96e3e09d5cd958ffa369a0e3c86a6851
Author: mazerdev
Date: Mon Apr 23 21:09:11 2021 +1000
Task 25 entregue

commit b02255b25eed57c7595504c66233d5ee3024190c
Author: mazerdev
Date: Mon Apr 23 18:32:40 2021 +1000
[WIP] Pesquisa nos widgets

O pensamento de quem escreve os commits assim seria: Eu nunca vou me preocupar em utilizar o commit body.

Quando você está trabalhando em uma empresa onde ao criar um PR, ou fazer revisão de código, não é uma tarefa comum, ninguém se preocupará em lhe pedir para escrever uma boa mensagem de commit.

Porém, isto muda quando você começa a trabalhar com equipes com uma boa cultura de engenharia, onde escrever uma mensagem de commit explícita e semântica, define a aceitação e qualidade de suas entregas.

Olhando novamente para as mensagens dos commits acima, quer saber por quê são “falhas”? Basta fazer a elas algumas perguntas:

  • Extrair informações: de onde está extraindo informações? QUal o formato da extração? Qual a fonte?

  • integração: de que, qual regra de negócio, integrando com qual sistema, serviço externo?

  • Task 25 entregue: vai me fazer abrir o gerenciador de demandas, que nem sei se é o mesmo usado quando finalizou a task?

  • pesquisa nos widgets: qual widget de qual tela? Terei que ler o seu código para tentar identificar?

A solução com commits semânticos

Os contribuidores de repositórios de projetos com excelência na sua gestão, sabem que uma mensagem Git commit bem elaborada é a melhor maneira de comunicar o contexto sobre uma mudança para outros desenvolvedores (e, de fato, para eles mesmos no futuro). Um diff lhe dirá o que mudou, mas apenas a mensagem de confirmação pode dizer o porquê. Peter Hutterer explica bem este ponto:

Restabelecer o contexto de um trecho de código é um desperdício. Não podemos evitá-lo completamente, então nossos esforços devem ser para reduzi-lo [o máximo] possível. As mensagens de confirmação podem fazer exatamente isso e, como resultado, uma mensagem de commit mostra se um desenvolvedor é um bom colaborador.

Eu complementaria com: se um desenvolvedor trabalha bem em equipe

A solução portanto é escrever mensagens de commit que descrevam com qualidade o contexto da implementação. Mensagens que tenham significado contextual, ou seja, mensagens semanticamente bem escritas.

Portanto commits semânticos são a nossa solução, e se aliarmos a semântica a uma estrutura padronizada para a equipe, podemos garantir altos ganhos de qualidade nos commits. E esta é a proposta dos Conventional Commits.

Sete diretrizes para uma mensagem semântica de commit do Git

Estas sete diretrizes servem como um guia primário para escrever commits semânticos de qualidade:

  1. Separe o assunto do corpo com uma linha em branco

  2. Limite a linha de assunto a 50 caracteres

  3. Coloque a linha de assunto em maiúscula

  4. Não termine a linha de assunto com um ponto

  5. Use o modo imperativo na linha de assunto

  6. Envolva o corpo em 72 caracteres

  7. Use o corpo para explicar o quê e por quê - não explique como, isto é o código

As diretrizes devem ser aplicadas a um formato, uma convenção pré-estabelecida, leia a seguir a proposta de convenção do Conventional Commits, com alguns exemplos práticos e didáticos.

Por onde começar?

A maioria das linguagens de programação tem convenções bem estabelecidas sobre o que constitui seu estilo idiomático, ou seja, nomenclatura, formatação e assim por diante.

Existem variações dessas convenções, mas a maioria dos desenvolvedores concorda que escolher uma e cumpri-la é muito melhor do que o caos que surge quando todos fazem suas próprias escolhas em código compartilhado.

É importante então entender que a abordagem de uma equipe para seu log de commit não deve ser diferente.

Para criar um histórico de revisão útil, as equipes devem primeiro concordar com uma convenção de mensagem de commit que estabelece pelo menos as três coisas:

  • Estilo: Sintaxe de marcação, quebra de margens, gramática, capitalização, pontuação. Remova essas coisas, elimine as conjecturas e torne tudo o mais simples possível. O resultado final será um registro notavelmente consistente que não é apenas um prazer de ler, mas que na verdade é lido regularmente.

  • Conteúdo: Que tipo de informação deve conter o corpo da mensagem de commit (se houver)? O que não deve conter?

  • Metadados: Como os IDs de rastreamento de issues e tasks, os ids de Pull e Merge Requests, etc. devem ser referenciados?

Felizmente, assim como para linguagens de programação, existem convenções bem estabelecidas sobre como uma mensagem Git commit deve ser escrita para ser idiomática.

Assim, você e sua equipe não precisem reinventar nada. Basta seguir as sete regras descritas neste artigo e padronizar o formato que você e sua equipe estarão no caminho certo para se comprometer (commiting 😀 ) como a qualidade profissional do projeto.

Conventional Commits para commits semânticos

A especificação definida pelo Conventional Commits oferece uma convenção simples para utilizar nas mensagens de commit.

Ela define um conjunto de regras para criar um histórico de commit explícito, o que facilita a criação de ferramentas automatizadas baseadas na especificação.

Esta convenção se alinha com o SemVer - Semantic Versioning, descrevendo os recursos, correções e modificações que quebram a compatibilidade, tudo nas mensagens de commit.

A mensagem do commit deve ser estruturada da seguinte forma:

<tipo>[escopo opcional]: <descrição>

[corpo opcional]

[rodapé(s) opcional(is)]

Vamos entender o que cada bloco de informação e cada elemento estrutural significa e como deve ser preenchido.

Tipo

O assunto da mensagem do commit deve ser pré-ficado com um tipo para comunicar a intenção do commit:

  1. build: commits do tipo build especificam alterações que afetam a compilação do sistema ou está relacionado a dependências externas (por exemplo: composer, maven, gulp, broccoli, npm)

  2. chore: commits do tipo chore são anotados quando alterações ocorrem em atualizações que não impactam building ou o produto do código do sistema, por exemplo: tarefas grunt, .gitignore.

  3. ci: commits do tipo ci descrevem alterações nos arquivos e scripts de configuração de CI - Continuous Integration (afetam por exemplo: Travis, Circle, BrowserStack, SauceLabs, Github Actions, Gitlab CI)

  4. docs: commits do tipo doc somente possuem alterações na documentação, como README ou docblocks.

  5. feat: um commit do tipo feat inclui um novo recurso na sua base de código (isso se correlaciona com MINOR do versionamento semântico, ou MAJOR caso insira uma quebra de compatibilidade com a versão anterior - veja breaking chance mais a frente neste artigo).

  6. fix: um commit do tipo fix soluciona um problema, um erro, um bug na sua base de código (isso se correlaciona com PATCH do versionamento semântico).

  7. perf: um commit do tipo perf indicam alterações no código que melhoram o desempenho da aplicação.

  8. refactor ou refact: commits do tipo refactor devem ser anotados quando uma alteração de código não corrige um bug no sistema nem adiciona um novo recurso na aplicação.

  9. style: um commit do tipo style identifica alterações que não afetam o “significado” do código, alteram o estilo do código, como: espaço em branco, identação, formatação, falta de ponto e vírgula, etc.

  10. test: um commit do tipo test descreve a adição de testes ausentes, novos testes específicos ou correção de testes existentes.

Corpo

O corpo da mensagem de commit deve conter informações complementares em relação a tipo, escopo e a descrição reumida já definidas no “título” do commit.

Não utilize o corpo da mensagem para demonstrar código como foi realizada a alteração, mas sim para contextualizar “por quê”, em relação à regra de negócio, aquela implementação foi realizada.

Rodapé

  1. BREAKING CHANGE: um commit que contém no rodapé opcional o texto BREAKING CHANGE:, ou contém o símbolo ! depois do tipo/escopo, introduz uma modificação que quebra a compatibilidade da aplicação, API ou lib (isso se correlaciona com MAJOR do versionamento semântico). Uma BREAKING CHANGE pode fazer parte de commits de qualquer tipo.

  2. Outros rodapés diferentes de BREAKING CHANGE: <descrição> podem ser providos e seguem a convenção simular a git trailer format.

Observe que esses tipos adicionais não são exigidos pela especificação do Conventional Commits e não têm efeito implícito no versionamento semântico (a menos que incluam uma BREAKING CHANGE). Um escopo pode ser fornecido ao tipo do commit, para fornecer informações contextuais adicionais e está contido entre parênteses, por exemplo feat(parser): adiciona capacidade de interpretar arrays. Portanto ao utilizar escopos, de maneira geral, os rodapés não são necessários.

Porque utilizar Conventional Commits

Com a utilização de Conventional Commits, algumas vantagens e otimizações podem ser alcançadas em seu projeto, beneficiando toda a equipe:

  • Melhor comunicação

Por meio dos Conventional Commits, é possível comunicar a natureza das mudanças para colegas de equipe, o público e outras partes interessadas do projeto.

Com uma comunicação de maior qualidade, torna-se mais fácil a contribuição de outras pessoas em seus projetos, permitindo que eles explorem um histórico de commits melhor estruturado.

Inclusive, alguns destes benefícios podem ser alcançados automatizando tarefas:

  • Criação automatizada de CHANGELOGs.

Manter documentações atualizadas, além de consumir muito tempo, é uma tarefa que requer disciplina. O documento de CHANGELOG é um destes componentes documentais, necessário, porém difícil de manter.

Ao utilizar Conventional Commits é possível automatizar esta tarefa e entregar maior qualidade com relatórios de mudança para cada deploy do sistema, aumentando a visibilidade para a equipe e sponsors.

Algumas das ferramentas que podem ser utilizadas são:

Além de automatizar o report de CHANGELOG, é possível determinar automaticamente alterações no versionamento semântico (com base nos tipos de commits).

  • Automatizar processos

Além de auxiliar na comunicação, e permitir automatizar tarefas relacionadas, também é possível disparar processos de build e deploy com o uso de Conventional Commits.

Como usar Commits Convencionais no dia a dia

Ao usar ferramentas para gerenciamento de projetos, como o Jira, Gitlab, Github ou outra de gestão de tickets e demandas no trabalho, se você colocar o número do ticket (issue) em sua mensagem de commit, o Jira ou Github poderá detectá-lo automaticamente e incorporar um link direto para o card no qual você está trabalhando.

Isso funciona bem com Commit Convencional, pois é possível colocar o número do ticket do Jira (por exemplo) no da mensagem.

type(<jira/github number>): commit title

Que tal um exemplo real:

fix(#331): altera a url padrão da api de pagamento

A url padrão da API de pagamentos foi alterada no serviço X, a alteração corrige a quebra ao chamar a API.

Considerações finais

A utilização de Semant Commits por meio de Conventional Commits trás alta qualidade no acompanhamento, rastreabilidade e compartilhamento do conhecimento no processo de desenvolvimento de softwares, tanto para o desenvolvimento solo como por equipes.

Não deixe de iniciar sua prática e incorporar em seu dia a dia, quanto mais você pratica a escrita de mensagens com alta semântica, mais rapidamente aumenta a qualidade do projeto.

Referências