Git Debugging: blame e bisect

Introdução

editar

Durante a produção de software é muito comum a inserção de bugs. E a probabilidade de isso acontecer aumenta, caso o projeto possua um time grande. Quando isso acontece, muitas vezes é difícil reconhecer o que está errado no código-fonte. Essa busca acaba se tornando cara, pois leva tempo. Para evitar o desperdício de tempo o Git traz algumas ferramentas de depuração que auxiliam nessa caçada: os comandos blame e bisect.

Git Blame: Quem Foi?

editar

Às vezes há a necessidade de saber o porquê que um determinado trecho de código foi alterado. Isso é explicado no texto do commit, no entanto, essa informação fica difícil de ser encontrada, principalmente em projetos grande, onde a pilha de commits cresce rápido. Para situações como essa foi criado o comando blame. Essencialmente, a definição para esse comando é a seguinte:

git blame
Comando de depuração que mostra o autor e revisão de cada modificação do arquivo, linha por linha.

Uso Básico: Um Exemplo

editar

Suponha que você esteja num projeto simples, que envolve a criação de um programa que faz as quatro operações matemáticas básicas. Ao abrir o código-fonte uma função chama a atenção:

int div( int dividend, int divider )
{
  int quotient = 0;

  if( divider != 0 )
  {
    quotient = dividend/divider;
  } else
  {
    quotient = -1;
  }

  return quotient;
}

"Por que fazer a verificação antes de efetivamente fazer a divisão"?

Para isso utiliza-se do comando blame para identificar qual o commit que alterou essa linha. Para isso, usa-se a seguinte linha de comando:

$ git blame arquivo

O resultado para essa função em específico é esse:

38a056ad (TomazMartins  2016-03-21 17:22:21 -0300 45) int div( int dividend, int divider )
38a056ad (TomazMartins  2016-03-21 17:22:21 -0300 46) {
76f678d5 (Thaiane Braga 2016-03-21 17:26:30 -0300 47)   int quotient = 0;
76f678d5 (Thaiane Braga 2016-03-21 17:26:30 -0300 48) 
76f678d5 (Thaiane Braga 2016-03-21 17:26:30 -0300 49)   if( divider != 0 )
76f678d5 (Thaiane Braga 2016-03-21 17:26:30 -0300 50)   {
76f678d5 (Thaiane Braga 2016-03-21 17:26:30 -0300 51)     quotient = dividend/divider;
76f678d5 (Thaiane Braga 2016-03-21 17:26:30 -0300 52)   } else
76f678d5 (Thaiane Braga 2016-03-21 17:26:30 -0300 53)   {
76f678d5 (Thaiane Braga 2016-03-21 17:26:30 -0300 54)     quotient = -1;
76f678d5 (Thaiane Braga 2016-03-21 17:26:30 -0300 55)   }

A partir disso, é possível buscar pela hash que identifica o commit e saber o porquê dessa alteração, caso isso esteja esclarecido na mensagem de commit. Caso não, basta entrar em contato com o autor dessa alteração para esclarecimentos.

Uso Avançado

editar

Algumas opções úteis oferecidas pelo blame são indicadas abaixo:

Não quero saber o autor, apenas o commit

editar

Para isso, basta usar o seguinte comando:

$ git blame -s arquivo

Assim, o git vai suprimir o autor e o timestamp' da mensagem.

Arquivo grande demais, quero o blame para parte dele apenas

editar

Use o seguinte comando:

$ git blame -L linha-inicial,linha-final arquivo

Assim, o git vai mostrar a mensagem apenas para o intervalo de linhas passado para ele como parâmetro. Por exemplo, quer-se apenas saber sobre as linhas 456 e 470, então usa-se $ git blame -L 456,470 arquivo.

Não quero saber sobre as alterações em linhas brancas

editar

Usa-se a opção:

$ git blame -w arquivo

O git irá suprimir as mensagens relativas a alterações em linhas em branco.

Git Bisect: Onde Está Quebrado?

editar

Há situações em que o código disponibilizado no repositório, remoto ou local, não está funcionando. E o bug não foi inserido por você, mas anterior às suas alterações. Às vezes, muitos commits atrás. Há duas formas de encontrar o problema: a maneira bruta, voltando os commits até encontrar aquele que contem a falha, ou utilizando o comando bisect.

git bisect
Comando que utiliza-se da busca binária para encontrar o commit que insere o bug ao projeto.

Usando Bisect: Um Exemplo

editar

Você está mexendo no mesmo projeto do exemplo anterior, sobre as operações aritméticas básicas. Você inicia os trabalhos verificando se o commit atual gera um programa com bom funcionando. Com a confirmação você faz uma série de alterações, cada uma gerando um commit novo. Depois de alguns commit resolve verificar se o programa funciona corretamente e percebe que não.

Como saber qual foi o commit que danificou o código?

Bem, você sabe qual foi o último commit em que o código estava saudável. Faz um pequeno gráfico para ilustrar isso.

--W--*--*--*--A
W: Último commit que estava funcionando.
A: Commit Atual.

Você resolve então utilizar o comando bisect. Digita as seguintes linhas de comando:

$ git bisect start
  Esse comando diz ao git iniciar uma busca binária.
$ git bisect bad
  Esse comando declara ao git que o commit atual está danificado.
$ git bisect good 7f0d8c87611b1d6af5f57a29c9a3e41b67d32844
  Esse comando diz ao git que a última vez que você viu o código saudável.

Agora, graficamente, estamos assim:

      você
        |
        v
--W--*--*--*--G
W: Último commit que estava funcionando.
G: Commit bom.
B: Commit ruim.

Com isso, o git inicia uma busca binária. Ele coloca você, por meio de um checkout no commit central entre o commit declarado e o commit atual. Nesse instante, você tem acesso ao commit e pode fazer testes para verificar se é nesse commit que encontra-se o bug. Você percebe que nesse commit ainda há erro. então você declara isso ao git.

$ git bisect bad

O git, então, posiciona você agora entre o último commit visitado e o commit tido como funcionando. Graficamente fica assim:

    você
     |
     v
--W--*--B--*--G
W: Último commit que estava funcionando.
G: Commit bom.
B: Commit ruim.

Como falta apenas esse commit, o git já declara para você que este é o commit em que o bug foi inserido. Você pode analisar quais as alterações que ele faz e terminar a busca com o comando:

$ git bisect reset

O git reposiciona você para o último commit na pilha, mas agora você sabe o qual é o problema e pode consertar.

Referências

editar

Depurando com o Git

Documentação do Bisect

Documentação do Blame