Olhando o histórico com Git

Uma atividade comum no dia a dia é olhar o histórico do controle de versão, onde buscamos números de atividades, assim como as alterações introduzidas por um commit. Assim pretendo mostrar alguns comandos que podem ser úteis e que poderemos usar no dia-a-dia.

Todos os comandos foram executados no repositório deste blog

git log

Com o git log é possível listar os commits em um branch, assim como filtrar por autor, data, entre outros campos.

O primeiro parâmetro útil do comando é o -n, que limita o número de commits no log.

$ git log -n 5

commit cceeefec36d9eb0461d84d59d6d5ac3e8ad7bc5a (HEAD -> master, origin/master, origin/HEAD)
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:41:34 2019 -0300

    Remoção de projetos

commit 3cc15a084c29a4b0eff462c303161fd087a69694
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:40:12 2019 -0300

    Configuração SEO e remoção de lista de projetos

commit 1a8dc6d8bace25d78dfdb2821f47de06fb9d15d1
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:37:03 2019 -0300

    Rascunhos

commit 4c9459ef22dae67937c202ddff51e45f32703a22
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Mon Jul 1 22:07:42 2019 -0300

    Elisa - Geração de código

commit 0bbb2c70702fe8d38b129a8f6fb42819e6d4479b
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Wed May 29 22:46:39 2019 -0300

    Elisa

Se quiser uma versão mais compacta do resultado, pode utilizar o argumento --oneline, mas isto só mostrará o início do hash e a mensagem do commit.

$ git log -n 5 --oneline

cceeefe (HEAD -> master, origin/master, origin/HEAD) Remoção de projetos
3cc15a0 Configuração SEO e remoção de lista de projetos
1a8dc6d Rascunhos
4c9459e Elisa - Geração de código
0bbb2c7 Elisa

Agora imagine que você precise filtrar os commits que fiz para o exame 70-483. O parâmetro --grep=<padrão> nos permite buscar um texto nas mensagens dos commits.

O valor de <padrão> pode ser uma expressão regular, portanto você pode realizar filtros mais sofisticados se precisar.

$ git log -n 5 --grep=70-483

commit 9588d9603169d5c226b74dfef792ea8fb92c2a2f
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Sat Jan 26 23:50:14 2019 -0200

    70-483 - Research about indexers and started research about IUnknown

commit d407321ba7d73ad9a743a66f9081e243cae42e80
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Sat Jan 26 23:09:03 2019 -0200

    70-483

commit 2fb8c793bff2683f7058a8fc773f67013ca2c936
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Sat Jan 26 23:05:24 2019 -0200

    70-483 renamed to have date

commit 5a6774ef9a446e3d2520c4d050fb4dbf03702d5e
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Sat Jan 26 22:54:23 2019 -0200

    Publish 70-483 annotations

commit 3fab03d2d481b4cda3147e4822dd960bfbc7bb05
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Sun Jan 20 11:00:30 2019 -0200

    70-483

Muitas vezes queremos ver commits a partir de uma data, e para isso o parãmetro --since=<data> pode ajudar.

Para o valor de <data>, utilize a data no formato yyyy-MM-ddTHH:mm:ss.

$ git log --since=2019-07-09T00:00:00

commit cceeefec36d9eb0461d84d59d6d5ac3e8ad7bc5a (HEAD -> master, origin/master, origin/HEAD)
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:41:34 2019 -0300

    Remoção de projetos

commit 3cc15a084c29a4b0eff462c303161fd087a69694
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:40:12 2019 -0300

    Configuração SEO e remoção de lista de projetos

commit 1a8dc6d8bace25d78dfdb2821f47de06fb9d15d1
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:37:03 2019 -0300

    Rascunhos

Como o git mostra os commits na ordem do mais recente para o mais antigo, podemos usar o parâmetro --reverse para inverter a ordem do resultado.

$ git log --since=2019-07-09T00:00:00 --reverse

commit 1a8dc6d8bace25d78dfdb2821f47de06fb9d15d1
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:37:03 2019 -0300

    Rascunhos

commit 3cc15a084c29a4b0eff462c303161fd087a69694
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:40:12 2019 -0300

    Configuração SEO e remoção de lista de projetos

commit cceeefec36d9eb0461d84d59d6d5ac3e8ad7bc5a (HEAD -> master, origin/master, origin/HEAD)
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:41:34 2019 -0300

    Remoção de projetos

Já sabemos como filtrar a atividade e até como ordenar os resultados, mas como identificamos os arquivos que foram modificados?

O argumento --name-only lista o nome de todos os arquivos que fazem parte do commit.

$ git log -n 3 --name-only

commit cceeefec36d9eb0461d84d59d6d5ac3e8ad7bc5a
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:41:34 2019 -0300

    Remoção de projetos

_layouts/projeto.html
_projetos/hermes1.md
_projetos/hermes2.md
_projetos/popularmovies.md
img/projetos/hermes_1_00.png
img/projetos/hermes_1_01.png
img/projetos/hermes_1_02.png
img/projetos/hermes_1_03.png
img/projetos/hermes_1_04.png
img/projetos/hermes_2_00.png
img/projetos/hermes_2_01.png
img/projetos/hermes_2_02.png
img/projetos/hermes_2_03.png
img/projetos/hermes_2_04.png
img/projetos/hermes_2_05.png
img/projetos/hermes_2_06.png
img/projetos/pop_00.png
img/projetos/pop_01.png
img/projetos/pop_02.png
projetos/index.html

commit 3cc15a084c29a4b0eff462c303161fd087a69694
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:40:12 2019 -0300

    Configuração SEO e remoção de lista de projetos

_config.yml

commit 1a8dc6d8bace25d78dfdb2821f47de06fb9d15d1
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:37:03 2019 -0300

    Rascunhos

_drafts/assemblies-net-core-mono-cecil.md
_drafts/csharp-e-tipos.md
_drafts/tres-arvores-git.md

Se precisar saber de quantos arquivos foram alterados, incluídos ou removidos, use o argumento --stat.

$ git log -n 3 --stat

commit cceeefec36d9eb0461d84d59d6d5ac3e8ad7bc5a
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:41:34 2019 -0300

    Remoção de projetos

 _layouts/projeto.html        |  18 ------------------
 _projetos/hermes1.md         |  18 ------------------
 _projetos/hermes2.md         |  19 -------------------
 _projetos/popularmovies.md   |  15 ---------------
 img/projetos/hermes_1_00.png | Bin 9062 -> 0 bytes
 img/projetos/hermes_1_01.png | Bin 10023 -> 0 bytes
 img/projetos/hermes_1_02.png | Bin 14474 -> 0 bytes
 img/projetos/hermes_1_03.png | Bin 10319 -> 0 bytes
 img/projetos/hermes_1_04.png | Bin 7236 -> 0 bytes
 img/projetos/hermes_2_00.png | Bin 7241 -> 0 bytes
 img/projetos/hermes_2_01.png | Bin 64307 -> 0 bytes
 img/projetos/hermes_2_02.png | Bin 14679 -> 0 bytes
 img/projetos/hermes_2_03.png | Bin 8975 -> 0 bytes
 img/projetos/hermes_2_04.png | Bin 17347 -> 0 bytes
 img/projetos/hermes_2_05.png | Bin 11774 -> 0 bytes
 img/projetos/hermes_2_06.png | Bin 13746 -> 0 bytes
 img/projetos/pop_00.png      | Bin 255147 -> 0 bytes
 img/projetos/pop_01.png      | Bin 177859 -> 0 bytes
 img/projetos/pop_02.png      | Bin 123061 -> 0 bytes
 projetos/index.html          |  17 -----------------
 20 files changed, 87 deletions(-)

commit 3cc15a084c29a4b0eff462c303161fd087a69694
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:40:12 2019 -0300

    Configuração SEO e remoção de lista de projetos

 _config.yml | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

commit 1a8dc6d8bace25d78dfdb2821f47de06fb9d15d1
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:37:03 2019 -0300

    Rascunhos

 _drafts/assemblies-net-core-mono-cecil.md | 10 ++++++++++
 _drafts/csharp-e-tipos.md                 |  9 ---------
 _drafts/tres-arvores-git.md               |  8 ++++++++
 3 files changed, 18 insertions(+), 9 deletions(-)

Para identificar a alteração, podemos usar o argumento -p.

Alguns commits foram removidos para encurtar o post

$ git log -n 3 -p

commit 3cc15a084c29a4b0eff462c303161fd087a69694
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date:   Tue Jul 9 10:40:12 2019 -0300

    Configuração SEO e remoção de lista de projetos

diff --git a/_config.yml b/_config.yml
index 519dd2e..79d08d7 100644
--- a/_config.yml
+++ b/_config.yml
@@ -1,6 +1,7 @@
 permalink: '/:title'
 title: João Vitor Retamero
 url: 'http://joaoretamero.com.br'
+lang: pt-BR
 encoding: utf-8
 plugins:
   - jekyll-paginate
@@ -11,14 +12,10 @@ paginate: 5
 paginate_path: '/pagina/:num'
 sass:
   style: compressed
-collections:
-  projetos:
-    output: true
-    permalink: '/projetos/:path'
 author: João Vitor Retamero
 twitter:
   username: jvretamero
-logo: /images/foto.png
+logo: /img/foto.png
 social:
   name: João Vitor Retamero
   links:

Como o resultado do comando pode ser muito grande, recomendo redirecionar o resultado para um arquivo com o >.

$ git log -n 3 -p > log.txt

git show

Já vimos como localizar alguns commits, agora podemos ver melhor o que foi modificado em um arquivo específico e até como este arquivo era antes do commit.

Em muitos casos teremos commits com vários arquivos alterados, então para ver um arquivo específico do commit é possível usar o git show <hash> -- <arquivo>. Como o comando mostra os dados completos do commit, pode-se usar o argumento --oneline para deixar o resultado menos verboso.

$ git show --oneline 3cc15a084c29a4b0eff462c303161fd087a69694 -- _config.yml

3cc15a0 Configuração SEO e remoção de lista de projetos
diff --git a/_config.yml b/_config.yml
index 519dd2e..79d08d7 100644
--- a/_config.yml
+++ b/_config.yml
@@ -1,6 +1,7 @@
 permalink: '/:title'
 title: João Vitor Retamero
 url: 'http://joaoretamero.com.br'
+lang: pt-BR
 encoding: utf-8
 plugins:
   - jekyll-paginate
@@ -11,14 +12,10 @@ paginate: 5
 paginate_path: '/pagina/:num'
 sass:
   style: compressed
-collections:
-  projetos:
-    output: true
-    permalink: '/projetos/:path'
 author: João Vitor Retamero
 twitter:
   username: jvretamero
-logo: /images/foto.png
+logo: /img/foto.png
 social:
   name: João Vitor Retamero
   links:

Bom, já sabemos o que foi alterado, mas e se precisarmos ver o arquivo completo antes deste commit? Com o show isto é possível e a sintaxe é git show <hash>~<qtde_revisoes>:<arquivo>.

Então o comando que podemos usar é o git show 3cc15a084c29a4b0eff462c303161fd087a69694~1:_config.yml que nos mostrará o arquivo completo antes daquele commit.

Algumas linhas foram omitidas para não deixar o texto muito extenso, mas é possível notar que a linha introduzida no commit não apareceu.

$ git show 3cc15a084c29a4b0eff462c303161fd087a69694~1:_config.yml

permalink: '/:title'
title: João Vitor Retamero
url: 'http://joaoretamero.com.br'
encoding: utf-8
plugins:
  - jekyll-paginate
  - jekyll-seo-tag
  - jemoji
excerpt_separator: <!--more-->
paginate: 5
paginate_path: '/pagina/:num'
sass:
  style: compressed
collections:
  projetos:
    output: true
    permalink: '/projetos/:path'
author: João Vitor Retamero
twitter:
  username: jvretamero
logo: /images/foto.png
social:
  name: João Vitor Retamero
  links:
    - 'https://github.com/jvretamero'
    - 'https://twitter.com/jvretamero'
    - 'https://www.linkedin.com/in/jvretamero'
    - 'http://stackoverflow.com/users/5554570/jvretamero'

git blame

Inúmeras vezes precisamos saber qual commit introduziu ou modificou determinado trecho de um arquivo. Então podemos usar o comando git blame -- <arquivo>, que irá gerar anotações no arquivo indicando o commit e o autor daquela linha.

$ git blame -- _config.yml

2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200  1) permalink: '/:title'
4a78da50 (João Vitor Retamero 2017-11-26 23:58:30 -0200  2) title: João Vitor Retamero
4a78da50 (João Vitor Retamero 2017-11-26 23:58:30 -0200  3) url: 'http://joaoretamero.com.br'
3cc15a08 (João Vitor Retamero 2019-07-09 10:40:12 -0300  4) lang: pt-BR
^ce2adae (João Vitor          2016-01-31 18:51:10 -0200  5) encoding: utf-8
1178f341 (João Vitor Retamero 2018-01-01 13:25:26 -0200  6) plugins:
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200  7)   - jekyll-paginate
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200  8)   - jekyll-seo-tag
dc42595a (João Vitor Retamero 2019-05-26 10:36:57 -0300  9)   - jemoji
^ce2adae (João Vitor          2016-01-31 18:51:10 -0200 10) excerpt_separator: <!--more-->
4a78da50 (João Vitor Retamero 2017-11-26 23:58:30 -0200 11) paginate: 5
447f9eff (João Vitor Retamero 2017-11-27 00:13:19 -0200 12) paginate_path: '/pagina/:num'
c1db10fb (João Vitor          2016-07-07 23:09:22 -0300 13) sass:
c1db10fb (João Vitor          2016-07-07 23:09:22 -0300 14)   style: compressed
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 15) author: João Vitor Retamero
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 16) twitter:
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 17)   username: jvretamero
3cc15a08 (João Vitor Retamero 2019-07-09 10:40:12 -0300 18) logo: /img/foto.png
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 19) social:
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 20)   name: João Vitor Retamero
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 21)   links:
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 22)     - 'https://github.com/jvretamero'
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 23)     - 'https://twitter.com/jvretamero'
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 24)     - 'https://www.linkedin.com/in/jvretamero'
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 25)     - 'http://stackoverflow.com/users/5554570/jvretamero'

Note que o resultado é o hash do commit que introduziu/modificou a linha, seguido pelo autor, data e número da linha. Com o hash do commit, podemos aplicar os comandos conhecidos anteriormente neste texto.

Como o arquivo inteiro é anotado, podemos limitar o resultado por faixa de linhas com o argumento -L.

$ git blame -L 17,19 -- _config.yml

2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 17)   username: jvretamero
3cc15a08 (João Vitor Retamero 2019-07-09 10:40:12 -0300 18) logo: /img/foto.png
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 19) social:

É importante lembrar que o comando da maneira que usamos, mostrará o último commit que você tiver no seu repositório local. Caso seja necessário anotar um arquivo antes de um commit, podemos passar o hash do commit como parâmetro.

$ git blame 3cc15a08~1 -- _config.yml

2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200  1) permalink: '/:title'
4a78da50 (João Vitor Retamero 2017-11-26 23:58:30 -0200  2) title: João Vitor Retamero
4a78da50 (João Vitor Retamero 2017-11-26 23:58:30 -0200  3) url: 'http://joaoretamero.com.br'
^ce2adae (João Vitor          2016-01-31 18:51:10 -0200  4) encoding: utf-8
1178f341 (João Vitor Retamero 2018-01-01 13:25:26 -0200  5) plugins:
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200  6)   - jekyll-paginate
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200  7)   - jekyll-seo-tag
dc42595a (João Vitor Retamero 2019-05-26 10:36:57 -0300  8)   - jemoji
^ce2adae (João Vitor          2016-01-31 18:51:10 -0200  9) excerpt_separator: <!--more-->
4a78da50 (João Vitor Retamero 2017-11-26 23:58:30 -0200 10) paginate: 5
447f9eff (João Vitor Retamero 2017-11-27 00:13:19 -0200 11) paginate_path: '/pagina/:num'
c1db10fb (João Vitor          2016-07-07 23:09:22 -0300 12) sass:
c1db10fb (João Vitor          2016-07-07 23:09:22 -0300 13)   style: compressed
b5b24d2e (João Vitor          2016-05-15 00:23:51 -0300 14) collections:
b5b24d2e (João Vitor          2016-05-15 00:23:51 -0300 15)   projetos:
b5b24d2e (João Vitor          2016-05-15 00:23:51 -0300 16)     output: true
4a78da50 (João Vitor Retamero 2017-11-26 23:58:30 -0200 17)     permalink: '/projetos/:path'
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 18) author: João Vitor Retamero
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 19) twitter:
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 20)   username: jvretamero
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 21) logo: /images/foto.png
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 22) social:
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 23)   name: João Vitor Retamero
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 24)   links:
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 25)     - 'https://github.com/jvretamero'
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 26)     - 'https://twitter.com/jvretamero'
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 27)     - 'https://www.linkedin.com/in/jvretamero'
2bc32527 (João Vitor Retamero 2017-12-31 19:29:37 -0200 28)     - 'http://stackoverflow.com/users/5554570/jvretamero'

Conclusão

Neste post vimos alguns comandos básico para ver o histórico de um repositório no Git. A ferramenta tem comandos mais avançados, mas isso fica para um próximo post.

Até mais.