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

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

docs.scrimba.com

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

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

    Fix temperature conversion in Celsius-to-Fahrenheit formula

commit 5f3d8b21a90e7c6d5b4a3f2e1d0c9b8a7f6e5d4c
Author: João Santos <[email protected]m>
Date:   Mon Jul 13 16:45:22 2026 +0100

    Add five-day forecast to the dashboard

commit 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
Author: João Santos <[email protected]m>
Date:   Mon Jul 13 11:03:47 2026 +0100

    Set up project structure

Um comando, e a história inteira do projeto está ali: três commits, os mais novos primeiro, cada um com quem o escreveu, quando, e por quê.

Lendo o log com git log

git log volta através de cada commit que pode ser alcançado de onde você está, o mais recente primeiro. Cada entrada mostra quatro coisas: um hash (a longa string de letras e números que identifica aquele commit exato), o autor, a data, e a mensagem que seu autor escreveu.

Um commit é todas essas quatro coisas agrupadas: um snapshot de cada arquivo rastreado naquele momento, a mensagem descrevendo a mudança, quem a fez, e um link para o commit que veio bem antes dele, seu commit pai. Esse link pai é o que transforma uma pilha de snapshots separados em um timeline real. Leia git log de cima para baixo e você está lendo aquele timeline para trás, do agora até o começo.

O hash parece intimidador no começo, mas você raramente precisa da coisa inteira. 4f2a1c9d8e7b6a5c4d3e2f1a0b9c8d7e6f5a4b3c e 4f2a1c9 apontam para o mesmo commit. Git só precisa de o suficiente do hash para distingui-lo de todo outro commit no repositório, e os primeiros sete ou mais caracteres são quase sempre o suficiente. Você verá a forma curta em todo lugar, incluindo os comandos no resto deste capítulo.

A saída padrão de git log é completa mas longa: três commits já ocuparam seu terminal inteiro. Algumas formas a tornam 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 colapsa cada commit em seu hash curto e mensagem, um commit por linha, que é a forma que você vai usar na maioria das vezes. --graph desenha a forma do histórico junto ao log como um conjunto de linhas e pontos. Em um projeto sem branches ainda, desenha uma linha reta simples, mas mantenha isso em seus dedos cedo: o momento em que branches aparecerem (o próximo capítulo) é exatamente quando aquele desenho começa a se pagar.

Você também pode filtrar o log em vez de passar por ele. git log --author="João" mostra apenas commits escritos por João, útil quando você quer ver o trabalho de uma pessoa em um projeto compartilhado. git log -- src/index.js mostra apenas commits que tocaram aquele arquivo específico, ignorando tudo que nunca se aproximou 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 do forecast, nunca tocou src/index.js, então ele não aparece. Ambos os filtros se combinam com --oneline perfeitamente.

Os filtros acima respondem "quais commits tocaram esse arquivo". A pergunta que realmente o envia para o histórico em um dia ruim é mais aguda: quando esse exato pedaço de código apareceu, ou desapareceu? É para isso que serve git log -S, conhecido como o pickaxe. Dê a ele uma string, e ele mantém apenas os commits onde o número de ocorrências daquela string mudou, significando os commits que a adicionaram ou removeram:

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

Um commit, de todo o histórico: o momento em que aquela chamada entrou na base de código. Essa é a forma mais rápida de responder "quando essa linha de bug foi introduzida" sem verificar nada. A regra de contagem tem uma consequência que vale a pena conhecer: um commit que apenas move a linha dentro de um arquivo deixa a contagem de ocorrências inalterada, então -S o pula. Quando você quer cada commit cujo diff sequer toca o texto, movimentos incluídos, use git log -G com uma expressão regular no lugar. Vá para -S primeiro; é a ferramenta mais afiada na pergunta que você costuma ter.

JunoLendo o loggit log lista cada commit, o mais novo primeiro, com seu hash, autor, data, e mensagem. Um commit é aquele snapshot mais sua mensagem mais um link para o commit anterior. Você quase nunca precisa do hash completo, os primeiros vários caracteres são suficientes para Git saber exatamente qual commit você quer dizer.
JunoLendo o loggit log --oneline é a forma que você usará diariamente, um commit por linha. Adicione --author ou um -- caminho no final para filtrar até o trabalho de uma pessoa ou o histórico de um arquivo, e vá para --graph uma vez que branches entrem na figura.
JunoLendo o log O hash de cada commit é uma impressão digital de seu próprio conteúdo mais o hash de seu 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", git log -S "texto" caminha pelo histórico inteiro para você e mantém apenas os commits que a adicionaram ou removeram. Entre isso e o link pai, este capítulo é a maior parte de meu kit de ferramentas de debugging.

Inspecionando um commit com git show

git log diz a você que um commit aconteceu. git show <hash> diz a você exatamente o que ele fez:

bash
$ git show 4f2a1c9
commit 4f2a1c9d8e7b6a5c4d3e2f1a0b9c8d7e6f5a4b3c
Author: Maria Silva <[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 superior é o mesmo metadado que git log mostra. Abaixo dela está a mudança real: uma linha começando com - é uma linha que o commit removeu, uma linha começando com + é uma linha que foi adicionada, e linhas sem marca são contexto que permaneceu igual. Aqui isso lê claramente: a linha velha agrupou 32 dentro dos parênteses, então foi adicionada antes da multiplicação acontecer. O fix agrupa os parênteses novamente ao redor de celsius * 9 então 32 é adicionado por último, o bug de precedência de operador que a mensagem de Maria descreve.

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

JunoInspecionando um commitgit show <hash> mostra um commit em cheio: quem o fez, quando, e as linhas reais que mudou. 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> dá a você o metadado e o diff completo de um commit. Aponte-o para um caminho específico também, git show <hash> -- caminho/para/arquivo, quando um commit tocou vários arquivos e você só precisa da fatia de um arquivo.
JunoInspecionando um commitgit show está comparando o snapshot salvo de um commit contra o de seu pai, e imprimindo apenas as linhas que diferem. Uma vez que você começa a ler diffs dessa forma, um commit deixa de ser uma caixa misteriosa e começa a ser dois snapshots com uma diferença entre eles.

O que git diff mostra, e a confusão que quase todo mundo tem

git log e git show leem histórico commitado. git diff lê o que não foi commitado ainda: as mudanças sentadas em seu diretório de trabalho agora, comparadas contra 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 em README.md, mostrada antes de você ter staged ou commitado qualquer coisa. Aqui está a parte que pega quase todo mundo em sua primeira semana: execute git add . para fazer stage daquela mesma mudança, depois execute git diff novamente, e ele não mostra nada.

bash
$ git add .
$ git diff

Nada foi impresso. A edição não desapareceu, e nada deu errado. git diff simples compara seu diretório de trabalho contra a staging area, e uma vez que você tem tudo em stage, aqueles dois agora combinam, então não há diferença esquerda para mostrar ali. Para ver mudanças esperando na staging area, use git diff --staged em vez disso.

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.

Mesma mudança, agora visível, porque --staged compara a staging area contra seu último commit em vez disso.

git diff simples e git diff --staged estão respondendo duas perguntas diferentes, e ajuda nomeá-las com precisão. git diff simples compara seu diretório de trabalho para a staging area: ele mostra edições que você fez mas ainda não fez stage. git diff --staged compara a staging area para seu último commit: mostra exatamente o que entraria em seu próximo commit se você executasse git commit agora. Nenhum um mostra ambas de uma vez, que é exatamente por que uma mudança totalmente em stage faz git diff simples ficar em silêncio. Você às vezes verá --cached em tutoriais e docs mais antigos; significa a mesma coisa que --staged.

Executar ambos antes de você committar é um bom hábito: git diff simples confirma que nada importante ficou sem stage, e git diff --staged confirma exatamente o que está prestes a ser salvo.

JunoVendo o que mudougit diff mostra edições em seu diretório de trabalho que ainda não foram feitas stage. Uma vez que você faz stage de tudo com git add, git diff simples fica em silêncio. Isso é esperado, suas mudanças ainda estão ali. Use git diff --staged para ver o que está esperando para ser commitado.
JunoVendo o que mudougit diff simples é diretório de trabalho contra staging area, git diff --staged é staging area contra seu último commit, duas comparações diferentes. Executar ambos antes de você committar diz a você o que está sem stage e o que está prestes a ser salvo. Material mais antigo às vezes diz --cached, mesma flag, nome diferente.
JunoVendo o que mudou Ambos os diffs são a mesma operação aplicada a diferentes pares de snapshots: árvore de trabalho contra staging area, ou staging area contra o último commit. Nomear quais dois arquivos você está comparando é o truque inteiro para nunca ser confundido por um git diff vazio novamente.

Por que o histórico do Git forma um gráfico

Cada commit que você viu até agora aponta para exatamente um pai, e ler git log de cima para baixo parecia estar lendo uma linha reta. Isso se sustenta para um projeto solo trabalhando em uma linha de trabalho. Deixa de se sustentar o momento em que branches e merges entram na figura, coberto depois em Branches, porque o histórico real de um projeto pode se dividir em linhas separadas e se juntar novamente.

Isso é para o que a flag --graph de antes é realmente. Em weather-app agora ela desenha uma coluna única, porque há apenas uma linha de commits para desenhar. Uma vez que um branch diverge e depois faz merge novamente, --graph começa a desenhar a divergência e a rejunção como colunas separadas que se encontram, que é muito mais fácil de ler do que tentar imaginar a partir de uma lista plana de hashes.

Execute git show em um commit de merge e, por padrão, ele imprime apenas o metadado: nenhum diff. Adicione -m e ele imprime um diff separado para cada pai por sua vez. Ambos os comportamentos rastreiam até a mesma forma: o histórico do Git é um DAG, um grafo acíclico direcionado. "Direcionado" significa que cada link aponta de um jeito, um commit de volta para seu pai, nunca para frente. "Acíclico" significa que aqueles links nunca fazem loop, então caminhar através deles sempre move em direção ao começo do projeto, nunca de volta para um commit que você já passou. Um commit normal tem exatamente um pai, que é por que o log de um projeto solo 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, git show simples não tem um único "o diff" para imprimir até -m dizer a ele para comparar contra cada pai separadamente. Branches e merging, os próximos dois capítulos, constroem diretamente sobre este mesmo gráfico.

JunoHistórico como um gráfico Agora cada commit que você viu aponta para um pai, então o log lê como uma linha reta. Isso muda uma vez que branches divergem e fazem merge de volta junto, que você vai encontrar depois. A forma embaixo, commits ligados ao commit antes deles, é o que torna qualquer um desses possível.
JunoHistórico como um gráfico Uma linha solo de commits parece reta porque cada um tem um pai único. A flag --graph é o que torna a forma visível uma vez que branching começa, desenhando divergências e merges em vez de uma lista plana. Mantenha-a em seu kit de ferramentas mesmo antes de você precisar dela.
JunoHistórico como um gráfico O histórico do Git é um grafo acíclico direcionado: ponteiros de pai só apontam para trás, e eles nunca fazem loop. Um commit de merge é o único lugar onde um commit recebe dois pais em vez de um, que é por que git show simples não imprime diff ali até você adicionar -m para escolher um pai. Branches e Merging ensinam a você o resto deste mesmo gráfico, de diferentes ângulos.