A dica Git da Semana é sobre usar bisect para encontrar onde uma falha foi introduzida.
Quando um problema é descoberto em um sistema existente, nem sempre fica claro o que causou a mudança de regressão. Às vezes é óbvio, mas em alguns casos a única maneira de descobrir é voltar e testar cada estágio do histórico para saber quando o código foi de ‘bom’ para ‘ruim’.
Uma vez que isso pode levar uma quantidade significativa de tempo, o git bisect pode ser usado para ajudar a automatizar a descoberta do problema. Ele se baseia na capacidade de determinar se um problema é ‘bom’ ou ‘ruim’, e usa uma espécie de binário para descobrir pelo histórico quando o erro foi introduzido. Para fazer isso, você usa git bisect start, seguido pelos comandos git bisect good e git bisect bad. Vamos usá-lo para saber quando a “linha dois” foi adicionada:
# Sample file, adding one line per commit
(master) $ git blame test
^b06000a (Alex Blewitt 2011-07-15 08:44:49 +0100 1) Line one
3c30996f (Alex Blewitt 2011-07-15 08:45:04 +0100 2) Line two
4b2a81b8 (Alex Blewitt 2011-07-15 08:45:24 +0100 3) Line three
67664b1e (Alex Blewitt 2011-07-15 08:45:32 +0100 4) Line four
50cc6273 (Alex Blewitt 2011-07-15 08:45:40 +0100 5) Line five
(master) $ git bisect start
(master|BISECTING) $ git bisect good b06000a
(master|BISECTING) $ grep two test
Line two
(master|BISECTING) $ git bisect bad
Bisecting: 1 revision left to test after this (roughly 1 step)
[4b2a81b86fcdb0e59981dc5d0ecdef5e6567c71b] Third
((4b2a81b...)|BISECTING) $ grep two test
Line two
((4b2a81b...)|BISECTING) $ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[3c30996f285905b16f1d1d8fb293372615272ce4] Second
((3c30996...)|BISECTING) $ git diff HEAD^
diff --git a/test b/test
index 67c8eb8..b8b933b 100644
--- a/test
+++ b/test
@@ -1,2 +1,2 @@
Line one
-
+Line two
Então, nós especificamos uma boa revisão (b06000a) e uma revisão ruim (50cc6273) e depois escolhemos um midpoint entre eles. Ele então usa funções recursivas até que reste apenas aquele commit e, nesse caso, é o único que apresentou o ‘bug’ (linha dois). Podemos até ver o que fizemos após o fato:
((3c30996...)|BISECTING) $ git bisect log
git bisect start
# good: [b06000a98bd9d88f71356746680404de14b68a89] First
git bisect good b06000a98bd9d88f71356746680404de14b68a89
# bad: [50cc627394f5647e16921c30e4a984b4fd76577c] Fifth
git bisect bad 50cc627394f5647e16921c30e4a984b4fd76577c
# bad: [4b2a81b86fcdb0e59981dc5d0ecdef5e6567c71b] Third
git bisect bad 4b2a81b86fcdb0e59981dc5d0ecdef5e6567c71b
Claramente, nesse caso, só poderíamos ter identificado a linha com git blame, mas ele destaca o princípio da resolução de um problema. No caso de fazer esses passos, que foram manualmente executados com grep two para descobrir se existia um problema; isso iria geralmente ser substituído com um comando de teste específico, tal como make ou equivalente. Mas espere! Podemos fazê-lo mais rápido! Em primeiro lugar, podemos especificar os parâmetros começando pelos endpoints bons e maus:
((3c30996...)|BISECTING) $ git bisect reset
Previous HEAD position was 3c30996... Second
Switched to branch 'master'
(master) $ git bisect start HEAD HEAD~5
Bisecting: 1 revision left to test after this (roughly 1 step)
[4b2a81b86fcdb0e59981dc5d0ecdef5e6567c71b] Third
Em segundo lugar, podemos executar um script que pode realizar alguns testes automatizados. Com git bisect run, podemos executar um script por commit que detecta se a condição é boa ou ruim. Isso poderia ser algum tipo de script make, ou poderia ser um script personalizado para testar uma condição particular:
((4b2a81b...)|BISECTING) $ echo 'grep two test && exit 1' > ~/test.sh
((4b2a81b...)|BISECTING) $ echo 'exit 0' >> ~/test.sh
((4b2a81b...)|BISECTING) $ chmod a+x ~/test.sh
((4b2a81b...)|BISECTING) $ git bisect run ~/test.sh
running /Users/alex/test.sh
Line two
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[3c30996f285905b16f1d1d8fb293372615272ce4] Second
running /Users/alex/test.sh
3c30996f285905b16f1d1d8fb293372615272ce4 is the first bad commit
…
bisect run success
Se o script para testar precisa ser o mesmo para todas as execuções, é melhor colocá-lo fora do repositório (que será reposto por operação bisect). Também é possível ter um script que faz um merge em correções simples ou constrói com parâmetros adicionais (por exemplo, -DDEBUG).
?
Texto original disponível em http://alblue.bandlem.com/2011/07/git-tip-of-week-git-bisect.html