Chapters ▾ 2nd Edition

2.3 Fundamentos do Git - Visualizando o Histórico de Commits

Visualizando o Histórico de Commits

Depois de criar vários commits, ou se você tiver clonado um repositório com um histórico de commits existente, você provavelmente vai querer olhar para trás para ver o que aconteceu. A ferramenta mais básica e poderosa para fazer isso é o comando git log.

Estes exemplos usam um projeto muito simples chamado “simplegit”. Para obter o projeto, execute:

$ git clone https://github.com/schacon/simplegit-progit

Quando você executa git log neste projeto, você deve obter uma saída semelhante a esta:

$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    Change version number

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    Remove unnecessary test

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    Initial commit

Por padrão, sem argumentos, o git log lista os commits feitos naquele repositório em ordem cronológica reversa; ou seja, os commits mais recentes aparecem primeiro. Como você pode ver, este comando lista cada commit com seu checksum SHA-1, o nome e e-mail do autor, a data em que foi escrito e a mensagem de commit.

Um grande número e variedade de opções para o comando git log estão disponíveis para mostrar exatamente o que você está procurando. Aqui, mostraremos a você algumas das mais populares.

Uma das opções mais úteis é -p ou --patch, que mostra a diferença (a saída do patch) introduzida em cada commit. Você também pode limitar o número de entradas de log exibidas, como usar -2 para mostrar apenas as duas últimas entradas.

$ git log -p -2
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    Change version number

diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
 spec = Gem::Specification.new do |s|
     s.platform  =   Gem::Platform::RUBY
     s.name      =   "simplegit"
-    s.version   =   "0.1.0"
+    s.version   =   "0.1.1"
     s.author    =   "Scott Chacon"
     s.email     =   "schacon@gee-mail.com"
     s.summary   =   "A simple gem for using Git in Ruby code."

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    Remove unnecessary test

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index a0a60ae..47c6340 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -18,8 +18,3 @@ class SimpleGit
     end

 end
-
-if $0 == __FILE__
-  git = SimpleGit.new
-  puts git.show
-end

Esta opção exibe as mesmas informações, mas com um diff logo após cada entrada. Isso é muito útil para revisão de código ou para navegar rapidamente pelo que aconteceu durante uma série de commits que um colaborador adicionou. Você também pode usar uma série de opções de resumo com o git log. Por exemplo, se você quiser ver algumas estatísticas abreviadas para cada commit, pode usar a opção --stat:

$ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    Change version number

 Rakefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    Remove unnecessary test

 lib/simplegit.rb | 5 -----
 1 file changed, 5 deletions(-)

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    Initial commit

 README           |  6 ++++++
 Rakefile         | 23 +++++++++++++++++++++++
 lib/simplegit.rb | 25 +++++++++++++++++++++++++
 3 files changed, 54 insertions(+)

Como você pode ver, a opção --stat imprime abaixo de cada entrada de commit uma lista de arquivos modificados, quantos arquivos foram alterados e quantas linhas nesses arquivos foram adicionadas e removidas. Ela também coloca um resumo das informações no final.

Outra opção muito útil é --pretty. Esta opção altera a saída do log para formatos diferentes do padrão. Existem alguns valores de opções predefinidos disponíveis para você usar. O valor oneline para esta opção imprime cada commit em uma única linha, o que é útil se você estiver observando muitos commits. Além disso, os valores short, full e fuller mostram a saída aproximadamente no mesmo formato, mas com menos ou mais informações, respectivamente:

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 Change version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Remove unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 Initial commit

O valor de opção mais interessante é format, que permite que você especifique seu próprio formato de saída de log. Isso é especialmente útil quando você está gerando saída para análise (parsing) por máquina — como você especifica o formato explicitamente, sabe que ele não será alterado com as atualizações do Git:

$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : Change version number
085bb3b - Scott Chacon, 6 years ago : Remove unnecessary test
a11bef0 - Scott Chacon, 6 years ago : Initial commit

Especificadores úteis para git log --pretty=format lista alguns dos especificadores mais úteis que o format aceita.

Table 1. Especificadores úteis para git log --pretty=format
Especificador Descrição da Saída

%H

Hash do commit

%h

Hash do commit abreviado

%T

Hash da árvore (tree)

%t

Hash da árvore abreviado

%P

Hashes pais (parent hashes)

%p

Hashes pais abreviados

%an

Nome do autor

%ae

E-mail do autor

%ad

Data do autor (o formato respeita a opção --date=)

%ar

Data do autor, relativa

%cn

Nome do committer

%ce

E-mail do committer

%cd

Data do committer

%cr

Data do committer, relativa

%s

Assunto

Você deve estar se perguntando qual é a diferença entre autor (author) e committer. O autor é a pessoa que escreveu o trabalho originalmente, ao passo que o committer é a pessoa que aplicou o trabalho por último. Então, se você enviar um patch para um projeto e um dos membros principais (core members) aplicar o patch, ambos receberão o crédito — você como autor e o membro principal como o committer. Abordaremos essa distinção um pouco mais em Git Distribuído.

Os valores de opção oneline e format são particularmente úteis com outra opção log chamada --graph. Esta opção adiciona um pequeno gráfico ASCII bacana mostrando o seu histórico de branches e merges:

$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 Ignore errors from SIGCHLD on trap
*  5e3ee11 Merge branch 'master' of https://github.com/dustin/grit.git
|\
| * 420eac9 Add method for getting the current branch
* | 30e367c Timeout code and tests
* | 5a09431 Add timeout protection to grit
* | e1193f8 Support for heads with slashes in them
|/
* d6016bc Require time for xmlschema
*  11d191e Merge branch 'defunkt' into local

Este tipo de saída se tornará mais interessante conforme passarmos por branches e merges no próximo capítulo.

Essas são apenas algumas opções simples de formatação de saída para o git log — há muitas outras. Opções comuns para git log lista as opções que cobrimos até agora, bem como algumas outras opções comuns de formatação que podem ser úteis, junto com a forma como elas alteram a saída do comando log.

Table 2. Opções comuns para git log
Opção Descrição

-p

Mostra o patch introduzido com cada commit.

--stat

Mostra estatísticas de arquivos modificados em cada commit.

--shortstat

Exibe apenas a linha changed/insertions/deletions do comando --stat.

--name-only

Mostra a lista de arquivos modificados após as informações do commit.

--name-status

Mostra a lista de arquivos afetados com informações de added/modified/deleted também.

--abbrev-commit

Mostra apenas os primeiros caracteres do checksum SHA-1 em vez de todos os 40.

--relative-date

Exibe a data em um formato relativo (por exemplo, “2 weeks ago”) em vez de usar o formato de data completo.

--graph

Exibe um gráfico ASCII da história de branches e merges ao lado da saída de log.

--pretty

Mostra commits em um formato alternativo. Os valores de opções incluem oneline, short, full, fuller e format (onde você especifica seu próprio formato).

--oneline

Uma forma abreviada de --pretty=oneline --abbrev-commit usados em conjunto.

Limitando a Saída do Log

Além das opções de formatação de saída, o git log aceita várias opções úteis de limitação; ou seja, opções que permitem exibir apenas um subconjunto de commits. Você já viu uma dessas opções — a opção -2, que exibe apenas os dois últimos commits. De fato, você pode usar -<n>, onde n é qualquer número inteiro para mostrar os últimos n commits. Na realidade, é improvável que você o use com frequência, porque, por padrão, o Git envia (pipes) toda a saída por meio de um pager para que você veja apenas uma página de saída de log por vez.

No entanto, as opções de limite de tempo, como --since e --until, são muito úteis. Por exemplo, este comando obtém a lista de commits feitos nas últimas duas semanas:

$ git log --since=2.weeks

Este comando funciona com vários formatos — você pode especificar uma data específica como "2008-01-15", ou uma data relativa como "2 years 1 day 3 minutes ago".

Você também pode filtrar a lista para os commits que correspondam a alguns critérios de pesquisa. A opção --author permite filtrar um autor específico, e a opção --grep permite pesquisar palavras-chave nas mensagens de commit.

Note

Você pode especificar mais de uma instância dos critérios de pesquisa --author e --grep, o que limitará a saída dos commits aos commits que correspondem a qualquer um dos padrões --author e qualquer um dos padrões --grep; no entanto, adicionar a opção --all-match limita ainda mais a saída apenas aos commits que correspondem a todos os padrões --grep.

Outro filtro realmente útil é a opção -S (coloquialmente chamada de opção “pickaxe” do Git), que recebe uma string e mostra apenas os commits que alteraram o número de ocorrências dessa string. Por exemplo, se você quisesse encontrar o último commit que adicionou ou removeu uma referência a uma função específica, você poderia chamar:

$ git log -S function_name

A última opção realmente útil para passar para git log como filtro é um caminho. Se você especificar um diretório ou nome de arquivo, poderá limitar a saída do log aos commits que introduziram uma alteração nesses arquivos. Essa é sempre a última opção e geralmente é precedida por dois hifens (--) para separar os caminhos das opções:

$ git log -- path/to/file

Em Opções para limitar a saída de git log, listaremos estas e algumas outras opções comuns para sua referência.

Table 3. Opções para limitar a saída de git log
Opção Descrição

-<n>

Mostra apenas os últimos n commits.

--since, --after

Limita os commits aos feitos após a data especificada.

--until, --before

Limita os commits aos feitos antes da data especificada.

--author

Mostra apenas os commits em que a entrada do autor corresponda à string especificada.

--committer

Mostra apenas os commits em que a entrada do committer corresponda à string especificada.

--grep

Mostra apenas os commits com uma mensagem de commit contendo a string.

-S

Mostra apenas os commits adicionando ou removendo código correspondente à string.

Por exemplo, se você quiser ver quais commits que modificaram os arquivos de teste no histórico de código-fonte do Git foram commitados por Junio Hamano no mês de outubro de 2008 e não são commits de mesclagem (merge commits), você pode executar algo assim:

$ git log --pretty="%h - %s" --author='Junio C Hamano' --since="2008-10-01" \
   --before="2008-11-01" --no-merges -- t/
5610e3b - Fix testcase failure when extended attributes are in use
acd3b9e - Enhance hold_lock_file_for_{update,append}() API
f563754 - demonstrate breakage of detached checkout with symbolic link HEAD
d1a43f2 - reset --hard/read-tree --reset -u: remove unmerged new paths
51a94af - Fix "checkout --track -b newbranch" on detached HEAD
b0ad11e - pull: allow "git pull origin $something:$current_branch" into an unborn branch

Dos quase 40.000 commits no histórico do código-fonte do Git, esse comando mostra os 6 que correspondem a esses critérios.

Tip
Prevenindo a exibição de commits de mesclagem (merge commits)

Dependendo do fluxo de trabalho usado no seu repositório, é possível que uma porcentagem considerável dos commits no seu histórico de log sejam apenas commits de mesclagem, que normalmente não são muito informativos. Para evitar que a exibição de commits de mesclagem sobrecarregue (cluttering up) seu histórico de log, basta adicionar a opção --no-merges de log.