Skip to content
This page has been auto-translated and may contain errors.View in English

Visualizando o histórico do Git com log, show e diff ​

docs.scrimba.com

Imagine que você abre o weather-app numa segunda-feira de manhã e não lembra exatamente o que você entregou na sexta. Ou um colega de equipe pergunta por que a conversão de temperatura mudou na semana passada, e você quer a resposta real, não um palpite. O ciclo do commit explica como um commit é salvo. Este capítulo trata de ler esse histórico de volta: o que aconteceu, quem fez e quando. O comando para isso é git log, e aqui está tudo o que ele imprime para um projeto pequeno:

bash
$ git log
commit 4f2a1c9d8e7b6a5c4d3e2f1a0b9c8d7e6f5a4b3c
Author: Priya Nair <[email protected]m>
Date:   Tue Jul 14 09:12:03 2026 +0100

    Fix temperature conversion in Celsius-to-Fahrenheit formula

commit 5f3d8b21a90e7c6d5b4a3f2e1d0c9b8a7f6e5d4c
Author: Kwame Boateng <[email protected]m>
Date:   Mon Jul 13 16:45:22 2026 +0100

    Add five-day forecast to the dashboard

commit 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
Author: Kwame Boateng <[email protected]m>
Date:   Mon Jul 13 11:03:47 2026 +0100

    Set up project structure

Um comando, e toda a história do projeto está ali: três commits, do mais recente para o mais antigo, cada um com quem escreveu, quando e por quê.

Lendo o histórico com git log ​

O git log percorre para trás cada commit alcançável a partir de onde você está, do mais recente para o mais antigo. Cada entrada mostra quatro coisas: um hash (a longa sequência de letras e números que identifica exatamente aquele commit), o autor, a data e a mensagem que o autor escreveu.

Um commit é essas quatro coisas reunidas: uma foto de todos os arquivos rastreados naquele momento, a mensagem descrevendo a mudança, quem fez e um link para o commit imediatamente anterior, seu commit pai. Esse link com o pai é o que transforma um monte de fotos separadas numa linha do tempo de fato. Ler o git log de cima para baixo é ler essa linha do tempo de trás para frente, do presente até o começo.

O hash parece intimidador a princípio, mas você raramente precisa dele completo. 4f2a1c9d8e7b6a5c4d3e2f1a0b9c8d7e6f5a4b3c e 4f2a1c9 apontam para o mesmo commit. O Git só precisa de hash suficiente para diferenciá-lo de todos os outros commits do repositório, e os primeiros sete caracteres, mais ou menos, quase sempre bastam. Você vai ver essa forma curta em todo lugar, incluindo nos comandos do restante deste capítulo.

A saída padrão do git log é completa, mas ocupa muito espaço: três commits já tomaram todo o seu terminal. Algumas variações deixam o comando mais útil no dia a dia.

bash
$ git log --oneline
4f2a1c9 Fix temperature conversion in Celsius-to-Fahrenheit formula
5f3d8b2 Add five-day forecast to the dashboard
1a2b3c4 Set up project structure

--oneline reduz cada commit ao seu hash curto e à mensagem, uma linha por commit, que é o formato que você vai usar na maioria das vezes. --graph desenha o formato do histórico ao lado do log, como um conjunto de linhas e pontos. Num projeto ainda sem branches, ele desenha uma linha reta simples, mas vale a pena já ir se acostumando com essa flag: no momento em que os branches aparecerem (no próximo capítulo), é exatamente aí que esse desenho começa a valer a pena.

Você também pode filtrar o log em vez de ficar rolando a tela. git log --author="Kwame" mostra só os commits escritos pelo Kwame, útil quando você quer ver o trabalho de uma pessoa específica num projeto compartilhado. git log -- src/index.js mostra só os commits que alteraram aquele arquivo específico, ignorando tudo que nunca chegou perto dele:

bash
$ git log --oneline -- src/index.js
4f2a1c9 Fix temperature conversion in Celsius-to-Fahrenheit formula
1a2b3c4 Set up project structure

Aquele segundo commit, o da previsão do tempo, nunca alterou src/index.js, então ele não aparece. Os dois filtros combinam bem com --oneline.

Os filtros acima respondem "quais commits alteraram este arquivo". A pergunta que de fato faz você mergulhar no histórico num dia ruim é mais específica: quando exatamente esse trecho de código apareceu, ou desapareceu? É para isso que serve o git log -S, conhecido como o pickaxe (a picareta). Você passa uma string, e ele mantém só os commits em que o número de ocorrências daquela string mudou, ou seja, os commits que a adicionaram ou removeram:

bash
$ git log --oneline -S "showLoadingSpinner"
7d1e8c3 Add loading spinner while forecast data loads

Um único commit, em todo o histórico: o momento exato em que aquela chamada entrou no código. Essa é a forma mais rápida de responder "quando essa linha com bug foi introduzida" sem precisar fazer checkout de nada. A regra de contagem tem uma consequência que vale conhecer: um commit que só move a linha dentro de um arquivo não altera o número de ocorrências, então o -S o ignora. Quando você quiser todo commit cujo diff sequer toque no texto, incluindo movimentações, use o git log -G com uma expressão regular em vez disso. Prefira o -S primeiro; é a ferramenta mais precisa para a pergunta que você normalmente tem.

JunoLendo o históricogit log lista todo commit, do mais recente para o mais antigo, com seu hash, autor, data e mensagem. Um commit é essa foto do projeto, mais a mensagem, mais um link para o commit anterior. Você quase nunca precisa do hash completo: os primeiros caracteres já bastam para o Git saber exatamente qual commit você quer dizer.
JunoLendo o históricogit log --oneline é o formato que você vai usar todo dia, uma linha por commit. Adicione --author ou um -- caminho no final para filtrar pelo trabalho de uma pessoa ou pelo histórico de um arquivo, e use o --graph assim que os branches entrarem em cena.
JunoLendo o histórico O hash de cada commit é uma impressão digital do seu próprio conteúdo somado ao hash do pai, então dois commits nunca colidem por acaso e um prefixo curto é seguro de digitar. E quando a pergunta é "quando essa linha apareceu ou desapareceu", o git log -S "texto" percorre todo o histórico por você e mantém só os commits que a adicionaram ou removeram. Entre isso e o link com o pai, este capítulo é boa parte do meu arsenal de depuração.

Inspecionando um commit com git show ​

O git log te diz que um commit aconteceu. O git show <hash> te diz exatamente o que ele fez:

bash
$ git show 4f2a1c9
commit 4f2a1c9d8e7b6a5c4d3e2f1a0b9c8d7e6f5a4b3c
Author: Priya Nair <[email protected]m>
Date:   Tue Jul 14 09:12:03 2026 +0100

    Fix temperature conversion in Celsius-to-Fahrenheit formula

diff --git a/src/index.js b/src/index.js
index 3f2c1a9..7b8e2d4 100644
--- a/src/index.js
+++ b/src/index.js
@@ -12,7 +12,7 @@ function celsiusToFahrenheit(celsius) {
-  return celsius * (9 / 5 + 32)
+  return (celsius * 9) / 5 + 32

A metade de cima é a mesma informação que o git log mostra. Embaixo dela está a mudança propriamente dita: uma linha que começa com - é uma linha que o commit removeu, uma linha que começa com + é uma linha que ele adicionou, e as linhas sem marcação são contexto que permaneceu igual. Aqui está bem claro: a linha antiga agrupava o 32 dentro dos parênteses, então ele era somado antes mesmo da multiplicação acontecer. A correção reagrupa os parênteses em torno de celsius * 9 para que o 32 seja somado por último, o bug de precedência de operadores que a mensagem da Priya descreve.

Adicione um caminho para ver só uma parte de um commit maior: git show 4f2a1c9 -- src/index.js mostra só a parte da mudança referente a esse arquivo, o que importa quando um único commit altera vários arquivos e você só se importa com um deles.

JunoInspecionando um commitgit show <hash> mostra um commit por completo: quem fez, quando e as linhas que de fato mudaram. Linhas removidas começam com um sinal de menos, linhas adicionadas começam com um sinal de mais. É a forma mais rápida de responder "o que esse commit realmente fez".
JunoInspecionando um commitgit show <hash> te dá as informações e o diff completo de um commit. Aponte também para um caminho específico, git show <hash> -- caminho/do/arquivo, quando um commit alterou vários arquivos e você só precisa da parte referente a um deles.
JunoInspecionando um commit O git show está comparando a foto salva de um commit com a do seu pai, e imprimindo só as linhas que diferem. Depois que você começa a ler diffs assim, um commit deixa de ser uma caixa misteriosa e passa a ser duas fotos com uma diferença entre elas.

O que o git diff mostra, e a pegadinha em que quase todo mundo cai ​

O git log e o git show leem o histórico já commitado. O git diff lê o que ainda não foi commitado: as mudanças que estão agora no seu diretório de trabalho, comparadas com o seu último commit.

bash
$ git diff
diff --git a/README.md b/README.md
index 1c2d3e4..9f8a7b6 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
 # weather-app
+A five-day weather dashboard built with vanilla JavaScript.

Essa é a edição que você fez no README.md, mostrada antes de você ter dado stage ou commit em qualquer coisa. Aqui vem a parte que pega quase todo mundo na primeira semana: rode git add . para dar stage nessa mesma mudança e, em seguida, rode git diff de novo — ele não mostra nada.

bash
$ git add .
$ git diff

Nada é impresso. A edição não desapareceu, e nada deu errado. O git diff simples compara o seu diretório de trabalho com a área de staging, e, depois que você deu stage em tudo, esses dois agora coincidem, então não sobra diferença nenhuma para mostrar ali. Para ver as mudanças que estão esperando na área de staging, use git diff --staged.

bash
$ git diff --staged
diff --git a/README.md b/README.md
index 1c2d3e4..9f8a7b6 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
 # weather-app
+A five-day weather dashboard built with vanilla JavaScript.

A mesma mudança, agora visível, porque o --staged compara a área de staging com o seu último commit, em vez do diretório de trabalho.

O git diff simples e o git diff --staged respondem a duas perguntas diferentes, e ajuda nomear cada uma com precisão. O git diff simples compara seu diretório de trabalho com a área de staging: mostra edições que você fez mas ainda não deu stage. O git diff --staged compara a área de staging com o seu último commit: mostra exatamente o que entraria no seu próximo commit se você rodasse git commit agora. Nenhum dos dois mostra as duas coisas ao mesmo tempo, e é exatamente por isso que uma mudança totalmente staged deixa o git diff simples mudo. Você vai ver --cached de vez em quando em tutoriais e documentações mais antigas; significa a mesma coisa que --staged.

Rodar os dois antes de commitar é um bom hábito: o git diff simples confirma que nada importante ficou fora do staging, e o git diff --staged confirma exatamente o que está prestes a ser salvo.

JunoVendo o que mudougit diff mostra edições no seu diretório de trabalho que ainda não foram staged. Depois que você dá stage em tudo com git add, o git diff simples fica mudo. Isso é esperado, suas mudanças continuam lá. Use git diff --staged para ver o que está esperando para ser commitado.
JunoVendo o que mudou O git diff simples compara o diretório de trabalho com a área de staging, o git diff --staged compara a área de staging com o seu último commit, duas comparações diferentes. Rodar os dois antes de commitar te diz o que está fora do staging e o que está prestes a ser salvo. Materiais mais antigos às vezes usam --cached, a mesma flag, com outro nome.
JunoVendo o que mudou Os dois diffs são a mesma operação aplicada a pares diferentes de fotos: diretório de trabalho contra área de staging, ou área de staging contra o último commit. Saber nomear quais duas coisas você está comparando é todo o truque para nunca mais ficar confuso com um git diff vazio.

Por que o histórico do Git forma um grafo ​

Todo commit que você viu até agora aponta para exatamente um pai, e ler o git log de cima para baixo tem parecido como ler uma linha reta. Isso vale para um projeto solo, com uma única linha de trabalho. Isso deixa de valer no momento em que branches e merges entram em cena, assunto do próximo capítulo, Branches, porque o histórico real de um projeto pode se dividir em linhas separadas e depois voltar a se juntar.

É exatamente para isso que serve a flag --graph de antes. No weather-app, agora, ela desenha uma única coluna, porque só existe uma linha de commits para desenhar. Quando um branch se separa e depois se junta de volta, o --graph passa a desenhar a separação e o reencontro como colunas distintas que se encontram, o que é muito mais fácil de ler do que tentar imaginar isso a partir de uma lista plana de hashes.

Rode o git show num commit de merge e, por padrão, ele imprime só as informações do commit: nenhum diff. Adicione -m e ele imprime um diff separado para cada pai, um por vez. Os dois comportamentos vêm da mesma estrutura de fundo: o histórico do Git é um DAG, um grafo acíclico dirigido. "Dirigido" significa que todo link aponta numa única direção, de um commit para o seu pai, nunca para frente. "Acíclico" significa que esses links nunca formam um ciclo, então percorrê-los sempre te leva em direção ao início do projeto, nunca de volta a um commit que você já passou. Um commit normal tem exatamente um pai, e é por isso que o log de um projeto solo se lê como uma linha reta. Um commit de merge é a exceção: ele carrega dois hashes de pai em vez de um, e, com dois pais, o git show simples não tem "o diff" único para imprimir até que o -m diga a ele para comparar contra cada pai separadamente. Branches e merge, os próximos dois capítulos, se apoiam diretamente nesse mesmo grafo.

JunoO histórico como um grafo Agora mesmo, todo commit que você viu aponta para um único pai, então o log se lê como uma linha reta. Isso muda quando branches se separam e depois se juntam de novo, algo que você vai ver a seguir. A estrutura por baixo disso tudo, commits ligados ao commit anterior, é o que torna tudo isso possível.
JunoO histórico como um grafo Uma linha solo de commits parece reta porque cada um tem um único pai. A flag --graph é o que torna essa estrutura visível quando os branches começam a aparecer, desenhando separações e junções em vez de uma lista plana. Vale a pena já ir se acostumando com ela, mesmo antes de precisar dela.
JunoO histórico como um grafo O histórico do Git é um grafo acíclico dirigido: os ponteiros de pai sempre apontam para trás, e nunca formam um ciclo. Um commit de merge é o único caso em que um commit tem dois pais em vez de um, e é por isso que o git show simples não imprime diff nenhum ali até você adicionar -m para escolher um pai. Branches e Merge te ensinam o resto desse mesmo grafo, sob ângulos diferentes.