Uma mensagem de commit bem elaborada é a melhor forma de se comunicar sobre o contexto que ocasionou uma mudança de código, tanto para a equipe como para o próprio desenvolvedor futuramente, uma vez que relembrar o contexto de um trecho de código pode consumir tempo, além de que mensagens de commit ambíguas podem levar a erros de interpretação. O git diff
nos mostra o que mudou no código, mas somente as mensagens do commit poderão nos dar a explicação do porquê da mudança.
A boa estruturação de mensagens de commit promove uma boa legibilidade do histórico de commits, tornando o uso de comandos como git log
, shortlog
, blame
, revert
e rebase
mais úteis em aplicações como revisão de commits e pull requests, além de tornar mais fácil o entendimento de uma alteração de código ocorrida meses ou anos atrás.
Para criar um histórico de commits útil, a equipe deve concordar com uma convenção para mensagens de commit que contemple as características a seguir:
Estilo: sintaxe, margens, gramática, pontuação. Leia a mensagem, reescreva para sanar qualquer ambiguidade ou espaço para adivinhação e deixe da forma mais simples possível. O resultado final será um log consistente, fácil de entender e útil
Conteúdo: Que tipo de informação o corpo da mensagem de commit deve conter? E o que não deve?
Metadata: Como referenciar IDs das issues e número dos pull requests?
Estrutura básica para o commit:
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
Exemplo:
docs(readme): adiciona título até 50 caracteres
O corpo da mensagem de commit é usado para maiores explicações,
apenas se necessário. Explique o problema que esse commit sana,
foque em 'porquê' você está fazendo essa mudança ao invés do
'como' (isso pode ser visto no código). Existem efeitos colaterais
ou outras consequências não intuitivas dessa mudança? Aqui é
o lugar para falar disso.
Você pode criar mais parágrafos após linhas em branco. Limite a
largura da linha por volta de 72 caracteres. A linha em branco
que separa o título do corpo é crítica (ao menos que vc omita
inteiramente o corpo); ferramentas como 'log' pode se confundir
caso as linhas estejam juntas.
- Marcadores também são bem vindos
- Normalmente se utiliza hífen ou asterisco para os marcadores,
sendo precedido de um espaço, com linhas em branco entre eles,
mas a convenção pode variar aqui
Referências a issues podem ser feitas no footer, dessa forma:
Resolves: #123
Ver também: #456, #789
Regras básicas para commits
Especifique o tipo de commit
Vários são as ações que podem ser desempenhadas em um código. Da convenção de commits do Angular, temos alguns tipos:
ci: Alterações em scripts e arquivos de configurações para integração contínua
docs: Todas as alterações em documentação
feat: Uma nova feature. Se correlaciona ao MINOR
do Semantic Versioning
fix: Uma correção de bug. Se correlaciona ao PATCH
do SemVer
BREAKING-CHANGE: Se correlaciona ao MAJOR
do SemVer
perf: Uma alteração no código para otimizar performance
refactor: Uma alteração no código em que não adiciona uma feature nem corrige bug
style: Alterações em estilização ou em partes que não afetam o significado do código (espaço em branco, formatação, adicionar ponto e virgula que faltava, etc)
test: Adição ou correção de testes
Separe título do corpo com uma linha em branco
Da documentação do git commit:
Though not required, it’s a good idea to begin the commit message with a single short (less than 50 character) line summarizing the change, followed by a blank line and then a more thorough description. The text up to the first blank line in a commit message is treated as the commit title, and that title is used throughout Git. For example, git-format-patch[1] turns a commit into email, and it uses the title on the Subject line and the rest of the commit in the body.
Em primeiro lugar, nem todo commit precisa possuir título e corpo. Em muitos casos, uma linha é suficiente para descrever uma mudança, principalmente é tão simples que não precisa de contextualização adicional, por exemplo:
Fix typo in introduction to user guide
Nada mais precisa ser dito. Se o leitor estiver curioso sobre o erro, basta olhar na mudança em si, ou seja, usar git show
, git diff
ou git log -p
.
Entretanto, quando o commit precisa de maiores explicações e contextualização, vc precisa escrever um corpo. Exemplo:
Derezz the master control program
MCP turned out to be evil and had become intent on world domination.
This commit throws Tron's disc into MCP (causing its deresolution)
and turns it back into a chess game.
O corpo da mensagem aparece no log de commits, o que pode ajudar muito na revisão do código. Além disso, a opção --oneline
do git log
pode ser usada pra exibir somente os títulos dos commits. O comando git shortlog
é interessante por agrupar commits feitos por cada pessoa, além de exibir somente o título. Portanto, é muito importante o uso correto das linhas em branco.
Mensagens com corpo não são fáceis de escrever com a opção -m
. É melhor escrever em um editor de texto, que pode ser configurado para uso com git via linha de comando (o padrão utilizado é o Vim).
Limitar o título a 50 caracteres
Não precisa necessariamente ser 50 caracteres, é mais para ter uma noção de um tamanho que seja legível e força o autor a criar uma mensagem concisa e representativa para explicar a ação do commit.
Dica: se você está tendo muita dificuldade para resumir a ação, você pode estar fazendo o commit de várias mudanças de uma só vez. Busque atomizar os commits.
O próprio GitHub alerta quando é passado o limite de 50 caracteres e acaba truncando quando passa de 72. Então podemos considerar 72 caracteres como limite máximo e 50 caracteres como margem de segurança. No guideline do Angular é recomendado o limite máximo de 100 caracteres
Capitalize o título de forma consistente
Alguns guidelines, como do Angular, recomendam deixar a primeira letra do título em minúsculo. Já outros, recomendam deixar sempre maiúsculo. O importante nesse caso é escolher uma opção e ficar com ela.
Não termine a linha do título com ponto
Além de desnecessário, atrapalha a fazer uma mensagem abaixo de 50 caracteres. Da mesma forma, remova pontuações desnecessárias
Use Corrige erro de digitação
ao invés de Corrige erro de digitação.
Use o modo imperativo no título
O modo imperativo nada mais é do que falar ou escrever de forma a dar um comando ou instrução. Pode soar rude ao falar com pessoas, mas é perfeito para mensagens de commit: o próprio Git usa a forma imperativa como padrão quando um merge ou revert é feito. Então, quando se escreve em imperativo, acaba se seguindo a convenção do Git:
Refatora subsistema X para leitura
Atualiza a documentação
Pode ser estranho a princípio, pois estamos acostumados a falar no indicativo, ou criar commits escritos como uma descrição dos seus conteúdos:
Corrigido bug com Y
Mais refatorações
Para acabar com qualquer confusão, podemos estabelecer uma regra simples para ajudar a elaborar a mensagem. Um título de commit bem elaborado deverá sempre completar a seguinte frase sem perda de sentido: **Se aplicado, esse commit
Exemplos:
Se aplicado, esse commit atualiza a documentação
Observe como não funciona em modos não imperativos:
Se aplicado esse commit corrigido bug com Y
Se aplicado esse commit mais refatorações
Outras frases podem ser usadas. Da guia para commits do Go:
This change modifies Go to <título do commit>
Relembre: o uso do imperativo é importante apenas no título, apesar que os guidelines do Angular recomendam o seu uso no body.
Limite a largura do corpo a 72 caracteres
Git nunca quebra linha automaticamente. Quando vc escreve o corpo de uma mensagem de commit, vc deve ter lembrar da margem direita e quebrar as linhas manualmente
A recomendação é de fazer em até 72 caracteres, para que o git tenha espaço para fazer suas indentações mantendo um máximo de 80 caracteres
Use o corpo para explicar o que e porque x como
Normalmente, o código é autoexplicativo. Porém o corpo do commit pode ser utilizado para dar mais detalhes e especificidades sobre uma correção, para explicar o comportamento esperado, para contextualizar a mudança do código, para dar informações adicionais sobre as implicações que aqueles trechos de código terão em outras partes do sistema, entre outros.
Mais exemplos e convenções
Tanto os guidelines do Angular a documentação do Conventional Commits defendem o uso da estrutura básica para commit:
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
Dessas guidelines temos as recomendações:
body e footer não são obrigatórios, assim como o scope
revert: quando um commit reverter uma alteração anterior, seu corpo deverá conter a mensagem This reverts commit <hash>.
, onde o hash seria o SHA do commit a ser revertido.
footer: deve conter referências de fechamento de um commit, se existir. Exemplos:
Closes #19
(mesmo repositório),
Fixes octo-org/octo-repo#100
(repositório diferente),
Resolves #10, resolves #123, resolves octo-org/octo-repo#100
(múltiplas issues)
Além disso, indicativos de breaking changes e demais informações relevantes podem ser exibidas no footer (usando a formatação trailer do Git). Exemplos:
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
Reviewed-by: Z
Mais de um footer pode ser utilizado, desde que separado por uma linha e que utilize as notações acima.
scope: informa sobre o contexto. Exemplo: feat(parser): add ability to parse arrays
BREAKING CHANGE: podem ser exibidas através de um indicativo no footer ou adicionando um !
ao fim do type/scope. Exemplo:
refactor!: drop support for Node 6
BREAKING CHANGE: refactor to use JavaScript features not available in Node 6.