Desenvolvimento

14 out, 2013

Todo commit deve compilar?

Publicidade

Em uma recente conversa no Twitter, foi discutida a questão se todos os git commits individuais devem compilar*.

Há duas respostas para isso:

  • Sim
  • Não

e qualquer uma que você escolher é mais uma função do seu fluxo de trabalho e práticas do que uma resposta definitiva de uma forma ou de outra.

Para explicar o que quero dizer com o “não”: se você tem uma série de commits em um repositório (vamos chamá-los de a→b→c para denotá-los), sendo que o commit final c compila*, com sucesso ou não, realmente importa se a ou b o fazem também?

Para um repositório local no qual você está trabalhando, isso não importa muito; afinal, o histórico local do git é mutável. É quando você começa a empurrar para branches remotos – especialmente os que os outros podem ver – que rescrever o histórico se torna algo mal visto.

Esses dois padrões colidem quando se trata de revisões de códigos compartilhados. Você gostaria de ter um feedback antecipado sobre uma implementação, assim você o compartilharia com outras pessoas através de algum tipo de repositório/branch remoto; mas quando você fizer isso, a expectativa é de que você vá construir sobre ele, acrescentando ainda mais commits (c→d→e) em vez de substituir aqueles em que você já fez push (a→b’→c’).

Esses dois padrões são exemplificados por pull requests do GitHub e reviews do Gerrit.

Um branch ou pull request no GitHub é tipicamente aditivo; novos commits promovem mudanças até que o recurso esteja completo, no qual o pull request é mesclado. Nesse caso, o que está sendo revisado não é necessariamente a história que chegou a esse ponto, mas o efeito resultante que essa mudança tem sobre o branch que está sendo incorporado. O resultado do efeito pull, e não como ele chegou lá, é o que está sendo medido.

Os reviews do Gerrit, por outro lado, permitem que você revise commits em uma base commit-a-commit, ou seja, rever o histórico. Implicitamente, isso acaba revendo a mudança resultante, através de uma visão de baixo pra cima, ao invés de cima pra baixo. Se um problema for encontrado, o commit original precisa ser editado e rebaseado antes de ser feito push novamente.

Em ambos os casos, é possível a criação de um trigger, de tal forma que, quando ocorre uma alteração, o compilador* é invocado e marca a mudança como verificada ou não; mas, no caso de Gerrit, ele vai fazer isso para cada commit no histórico, enquanto que no caso do GitHub ele só vai fazer isso para o branch como um todo.

Há algumas razões para essas diferenças, que têm mais a ver com o ambiente do que qualquer outra coisa.

Em primeiro lugar, o site do GitHub é formado principalmente por backends Ruby e JavaScript. Nesses casos, não há nenhuma etapa “compile” (daí as anotações de compilação* acima); e, como resultado, há menos mérito para determinar se um commit individual é bem sucedido ou não. Gerrit, por outro lado, saiu do Google, e é usado para a árvore do fonte do Android, que faz uso de uma linguagem compilada (e por isso tem uma etapa “compile”).

Em segundo lugar, a capacidade de cada commit de ser compilado ou não é de assistência ao usar git bisect. Para aqueles que não o usaram antes (ou leia a dica git da semana sobre o assunto), git bisect permite que você execute um programa para determinar se ele é ‘bom’ ou ‘ruim’ e , em seguida, realizar uma busca binária para saber quando ‘boas’ mudam para ‘ruins’ .

No caso do código, pelo menos na compilação correta, é possível executar a saída de algum tipo de ferramenta de teste ou contra um caso de teste para determinar se o código resultante é bom ou não; mas se o código não compila corretamente, então o problema pode ser mais difícil de resolver.

Como resultado, aqueles que usam git bisect tendem a valorizar os benefícios de cada commit individual compilar corretamente, enquanto que aqueles que não usam ou não precisam fazer um passo de compilação tendem a não precisar dele.

Então, se você estiver usando uma linguagem compilada, e você quer ser capaz de usar git bisect efetivamente, então ter todo commit compilado pode ser uma ferramenta valiosa. Mas se você não está usando uma linguagem compilada, e não tem uma sequência de testes que podem ser executados, então ignorar o estado intermediário e focar no resultado final pode ser mais ágil.

Atualizado Graças a @martiell por apontar  que eu quis dizer git bisect em vez de git blame.

***

Artigo traduzido pela Redação iMasters, com autorização do autor. Publicado originalmente em http://alblue.bandlem.com/2013/08/should-every-commit-compile.html