Boas práticas ao escrever commits no Git
O Git é uma ferramenta bem conhecida para o controle de versões. Uma de suas principais capacidades é a de manter o registro histórico das mudanças de um projeto. Um desenvolvedor recém-chegado a um novo trabalho, por exemplo, apenas lendo os textos renderizados em seu terminal conseguirá entender as decisões técnicas tomadas pelos mantenedores como se antes estivesse sentado ao lado dos mesmos quando a decisão foi tomada.
Claro que não seria exatamente assim, por isso que esse artigo tem como foco fornecer um caminho para podermos melhorar (ou errar menos) e também relembrar a dimensão e a importância que um simples commit tem no âmbito de um projeto ou pessoa.
O que é um commit
O commit do Git representa um snapshot do seu repositório em determinado momento. Desta forma, toda mudança em um projeto é representada por um commit e todo commit, com exceção do primeiro, tem um commit "pai" que salva o estado anterior e, seguindo sucessivamente esse "pai", chegaremos ao início do projeto.
Sempre que criamos um commit precisamos gravar uma mensagem nele, e a mesma será salva no histórico do projeto permanentemente. Essa marca será acessível para todos que tenham acesso ao projeto. Futuramente, uma boa mensagem de commit sempre irá ajudar a todos que virão colaborar no projeto.
A importância de um bom commit
Todo “software” é um projeto colaborativo e até mesmo nos projetos mais isolados há uma constante mudança no desenvolvimento e decisões no projeto. Isso pode acontecer de várias formas, seja a necessidade de mudança diante de um problema, uma adaptação para o projeto adquirir novas funcionalidades ou até mesmo a mudança de mantenedores. Para cada uma dessas mudanças, as pessoas que estão atuando precisam buscar o contexto desses pequenos blocos de código aonde as mesmas devem atuar e a única maneira de salvar esse contexto de forma efetiva sem consumir horas de algum desenvolvedor ou contar com a resposta de um e-mail de algum antigo mantenedor, é que os projetos desde seu início até o fim tenham boas mensagens de commits que nos permitam acessar esse conhecimento de cada iteração de uma forma legível e organizada.
Compondo uma mensagem de commit
Visto a importância do contexto nas mudanças em cada projeto, caso quisermos deixar bem documentadas e apresentáveis, podemos tomar dois exemplos de pessoas que trabalharam em projetos onde a disciplina de commit é essencial.
Peter Hutterer, o principal mantenedor da libinput (Se você usou o mouse no Linux para acessar esse artigo pode agradecer a esse homem) conta em um artigo em seu blog:
Uma boa mensagem de commit deve responder as essas três questões sobre determinada mudança:
Por que essa mudança é necessária? A mesma pode corrigir um bug, adicionar uma feature, melhorar a performance ou a segurança.
Como a mesma resolve o problema? Para mudanças pequenas e óbvias essa parte pode ser omitida, mas a mesma consiste em uma descrição de alto nível de qual foi a abordagem usada para tratar o determinado problema.
Quais os efeitos essas mudanças tem? Além das óbvias, isso pode incluir benchmarks, efeitos colaterais, etc.
E para um exemplo mais estático, Linus Torvalds (Criador do Git e Linux) na sua pagina de contribuição para seu outro projeto Subsurface, comentou um modelo de uma boa mensagem de commit:
Cabeçalho: Explique esse commit em uma linha (Use a linguagem imperativa)
O corpo da mensagem de commit são algumas linhas de texto, explicando
em mais detalhes e possivelmente apresentando mais contexto sobre o
problema sendo tratado.
O corpo da mensagem de commit pode ser diversos paragráfos e
por favor façam corretamente a quebra de linha e mantenham as
colunas menos que 74 caracteres. Assim, o comando "git log"
irá mostrar a mensagem de forma agradavel mesma que esteja identada.
Faça questão de explicar a sua solução e por que voce está fazendo
o que está fazendo, ao invés de apenas descrever o que está fazendo de forma superficial.
Pense que revisores e o seu eu-futuro irão ler essas mudanças, mas podem não entender
por que determinada solução foi implementada.
Reported-by: quem-reportou
Signed-off-by: Seu Nome [email@host.com](mailto:email@host.com)
Conventional Commits
Acredito que os exemplos acima são mais que o suficiente para podermos dar início a essa disciplina de commit, como diz Hutterer. Porém, com o tempo, já foram desenvolvidas diversas convenções que nos apresentam um conjunto de regras fáceis de serem adotadas e que, tendo elas como base, se erguem poderosas ferramentas que irão nos auxiliar a elevar nosso patamar de desenvolvimento. A convenção que veremos nesse artigo é a Conventional Commits.
A Conventional Commits foi criada com base nas diretrizes de commit do Angular e o primeiro rascunho foi redigido em conjunto com colaboradores das ferramentas conventional-changelog, parse-commit-message, bumped, unleash e lerna.
O que essas ferramentas têm em comum? Todas trazem em alguma parte do seu fluxo alguma automação, seja gerando changelogs automáticos ou por uma mensagem de commit que define a importância de uma nova versão do pacote.
Com essa formação de base, o Conventional Commits já nasce como estandarte para ferramentas que procuram automatizar e retirar a complexidade do processo de desenvolvimento enquanto aumenta a organização do projeto.
Aqui listo as principais vantagens que ganhamos por adotar essa convenção:
Comunicar as mudanças aos colegas de equipe, ao público e demais.
A mensagem de commit deve ser estruturada da seguinte maneira:
<tipo>[escopo opcional]: <descrição>
[corpo opcional]
[rodapé opcional(s)]
E deve usar os seguintes elementos para comunicar a intenção ao leitor do commit:
fix: corrige um bug no seu código.
feat: adiciona uma nova funcionalidade no seu código.
BREAKING CHANGE: um commit que tem o texto BREAKING CHANGE no rodapé do commit ou usa um ! depois do tipo/escopo, introduz uma grande mudança no código.
Exemplo:
chore!: remove suporte ao Node 14
Para suportar novas funcionalidades que vão
agregar mais desempenho a aplicação como o
`Promises.any` estamos subindo o requerimento
mínimo do projeto.
BREAKING CHANGE: a versão minima do Node agora é a 16.
Outros tipos além do fix: e feat: são permitidos, como, por exemplo:
- chore: Mudanças de configuração ou de código que não entra em produção;
- ci: Alteração em algum arquivo de CI do projeto;
- docs: Mudanças na documentação;
- style: Alteração apenas no estilo do código, sem mudança de algoritmo;
- refactor: Refatoração de determinado bloco de código;
- perf: Alterações que impactam o desempenho da aplicação;
- test: Mudanças na estrutura ou na forma de testar o projeto.
Exemplo:
docs: adiciona stack de Pyhon e Ruby a documentação
Atualiza a tabela de "detalhe das stacks" com as
ferramentas PyLint para Python e RuboCop para Ruby
ref #12
Facilite para as pessoas contribuírem com seus projetos
Imagine que você é um desenvolvedor que vai ajudar a manter um projeto mais antigo, quando você rodar o comando git log
qual das imagens abaixo você gostaria de se deparar?
Ou
Um commit bem estruturado facilita o trabalho de leitura e atuação de todos que pretendem colaborar com um projeto. Não e atoa que grandes projetos colaborativos sempre priorizam o uso de mensagens bem estruturadas.
Com base nos commits estruturados, automatize o aumento da versão semântica
Podemos usar o projeto semantic-release para automatizar o lançamento de versões do nosso pacote conforme a mensagem de commit. A automação é bem simples. Através da mensagem de commit, o semantic-release define que incremento ele deve fazer conforme a imagem abaixo:
Isso nos permite atualizar consistentemente os nossos pacotes de maneira muito rápida e organizada o que nos salva muito tempo.
Gere de forma automática changelogs aos seus projetos
E para colocar a cereja no bolo, podemos gerar um changelog completo e formatado conforme as mensagens do projeto usando o conventional-changelog. Com essa ferramenta, podemos fechar um ciclo de publicação apenas com o poder de uma mensagem de commit bem estruturada!
Como não errar!
Se escolhermos seguir o Conventional Commits é possível impor de forma definitiva no nosso código o mesmo.
Podemos impedir que enviemos commits que não atendem as especificações da convenção com o Commitlint e assim extrair o máximo das vantagens apresentadas acima.
Commitlint
Esse é um projeto com uma premissa muito objetiva. O Commitlint simplesmente verifica se o seu commit atende as especiações da convenção. O interessante é que é possível configurar um hook pré-commit usando o husky , desta forma, sempre que terminarmos o commit, ele irá informar se houver erros da mensagem e não irá fazer o commit caso tenha.
Vejamos como configurar o Commitlint:
yarn add --dev @commitlint/{config-conventional,cli}
# Usa regras do Conventional Commits
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
Configure o Pre-Hook do Git com o Husky:
yarn add husky --dev
yarn husky install
yarn husky add .husky/commit-msg 'yarn commitlint --edit $1'
Agora tente errar o commit para testar:
➜ git commit -m "ajuste"
yarn run v1.22.17
$ /home/joao/Documents/projetos/pipelinit-sample-vue-html/node_modules/.bin/commitlint --edit .git/COMMIT_EDITMSG
⧗ input: ajuste
✖ subject may not be empty [subject-empty]
✖ type may not be empty [type-empty]
✖ found 2 problems, 0 warnings
ⓘ Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint
Pronto!
Considerações finais
Os nossos commits conseguem interferir com nossos colegas de equipe do presente e futuro, e estão presentes no desenvolvimento de cada mudança no projeto. Desta forma, se faz necessário que os projetos cada vez mais tenham padrões de contribuição e mensagens de commits bem definidos e organizados.
Com a evolução nos métodos de organizações de projetos, algumas convenções apresentam uma nova visão para os commits no qual integram a eles a possibilidade de completar o fluxo de desenvolvimento da primeira mudança até a publicação e divulgação do pacote de maneira completamente automatizada, rápida e fácil.
Esperamos que você possa seguir algumas das ideais apresentadas e que ajude a fomentar melhores padrões de commits em seus projetos. Acreditamos que o resultado seja uma melhor colaboração por todos que estão dispostos a trabalhar de maneira séria, produtiva e eficiente.
Referencias
- Site oficial do Conventional Commits com sua convenção
- Manual do Git para usuários
- Postagem no blog do Peter Hutterer sobre mensagens de commit
- Commit do Linus Torvalds falando sobre as mensagens de commit
- Repositório do Semantic-Release
- Repositório do Conventional Commits
- Como o Semantic-Release usa as mensagens de commit para definir uma nova versão
- Pacote do Husky que auxilia a configurar pre-hooks de commits
- Repositório do Commitlint