CURSOS / TECNOLOGIA / TRILHA PRO GIT (ETAPA 1 DE 4)
Controle de Versão · Etapa 1 de 4 · O Básico Essencial

Git na prática
com critério.

Entenda como o Git pensa por trás dos comandos: grave instantâneos íntegros, separe o que vai para a área de preparação, investigue o histórico sem adivinhação e desfaça enganos sem perder uma linha de trabalho.

Mesa de estúdio com caderno de diagramas de ramificação, bússola de precisão e notebook com terminal aberto
8 oficinasbaseadas nos Capítulos 1 e 2 de Pro Git
4 etapasna formação completa de Git
Seu cadernocom comandos, testes e decisões
Percurso completo em 4 cursos · Pro Git

Trilha de formação: Domínio do Git do básico à arquitetura interna

Como o livro Pro Git é extenso e denso, dividimos a formação em quatro cursos independentes e progressivos. Você está na Etapa 1.

Percurso da Etapa 1 (Capítulos 1 e 2)

Para praticar cada oficina, abra o terminal na sua máquina e crie uma pasta de laboratório. Todos os exercícios funcionam localmente sem depender de internet.

Camadas de vidro translúcido e fichas arquivísticas sobre mesa de carvalho representando snapshots de versão

“Quase todo sistema de versão guarda uma lista de diferenças por arquivo; o Git tira uma fotografia inteira do projeto a cada commit.”

Essa distinção explicada por Scott Chacon e Ben Straub no Capítulo 1 de Pro Git é a chave para entender por que trocar de versão, comparar estados e recuperar arquivos no Git é tão rápido e confiável.
Oficina 01 / 08

Entenda snapshots, integridade SHA-1 e os três estados do Git

Imagine que um colega apagou acidentalmente o servidor onde a equipe guardava o código ou que você precisa comparar duas versões do projeto dentro de um avião sem internet. Por que um repositório Git resolve os dois problemas em milissegundos?

De pastas copiadas e servidores únicos ao controle distribuído

Chacon e Straub mostram no Capítulo 1 que o controle de versão passou por três gerações. No início, desenvolvedores copiavam pastas com nomes como projeto-final-v2 ou usavam sistemas locais como o RCS, que guardava conjuntos de diferenças (patches) de um arquivo para outro no próprio disco. Depois vieram os Sistemas Centralizados (CVCS), como CVS, Subversion (SVN) e Perforce: um único servidor guardava todo o histórico e cada pessoa baixava apenas a versão atual dos arquivos. O risco era evidente: se o servidor ficasse fora do ar por uma hora, ninguém conseguia gravar histórico ou comparar versões; se o disco do servidor corrompesse sem backup atualizado, toda a história do projeto se perdia.

Nos Sistemas Distribuídos (DVCS) como o Git — criado em 2005 por Linus Torvalds e pela comunidade do kernel Linux após o fim da licença gratuita do BitKeeper —, cada cliente não baixa apenas a última foto dos arquivos: ele espelha o repositório inteiro, com todo o histórico desde o primeiro commit. Se o servidor central queimar, qualquer clone no notebook de um desenvolvedor pode restaurar o servidor completo. Além disso, quase todas as operações (ver histórico, comparar versões, criar commits) leem apenas o banco local no seu próprio disco.

Snapshots em vez de deltas, checksum SHA-1 e os três estados

Três propriedades diferenciam o Git de quase qualquer outra ferramenta:

  1. Instantâneos (Snapshots), não diferenças (Deltas). Sistemas como SVN pensam no histórico como uma lista de alterações por arquivo ao longo do tempo (Arquivo A + mudança 1 + mudança 2). O Git pensa nos dados como uma sequência de fotografias em miniatura de todo o sistema de arquivos. Sempre que você faz um commit, o Git tira um retrato de todos os arquivos naquele instante; se um arquivo não mudou desde o commit anterior, o Git não o duplica — apenas grava um ponteiro para o arquivo idêntico que já estava salvo.
  2. Integridade criptográfica em tudo. Antes de salvar qualquer arquivo ou diretório, o Git calcula um checksum SHA-1 de 40 caracteres hexadecimais (como 24b9da6552252987aa493b52f8696cd6d3b00373) baseado no conteúdo exato. É impossível alterar um byte de um arquivo ou a data de um commit no meio do caminho sem que o Git perceba a mudança do hash.
  3. Os Três Estados e as Três Seções. Esta é a regra número um do Capítulo 1: qualquer arquivo rastreado pelo Git vive em um de três estados, correspondentes a três áreas do seu projeto:
Os três estados e as três seções fundamentais de um projeto Git
Estado do arquivoSeção onde ele estáO que significa na prática
Modified (Modificado)Working Tree (Diretório de Trabalho)Você alterou o arquivo nos seus arquivos locais, mas ainda não avisou que ele entrará no próximo commit.
Staged (Preparado)Staging Area (Índice / arquivo .git/index)Você marcou o arquivo na sua versão atual para entrar na fotografia do próximo commit.
Committed (Confirmado)Git Directory (Pasta .git)Os dados estão gravados com segurança e hash SHA-1 no seu banco de dados local do Git.
Comando para experimentar
# 1. Crie uma pasta de laboratório e veja como o Git calcula o hash SHA-1 de qualquer conteúdo:
mkdir -p ~/lab-git-etapa1 && cd ~/lab-git-etapa1
echo "Relatorio de producao v1" | git hash-object --stdin

# 2. Mude apenas uma letra e veja como o checksum de 40 caracteres muda completamente:
echo "Relatorio de producao v2" | git hash-object --stdin

# 3. Confira a versão instalada do Git na sua máquina:
git --version
Laboratório avançado · Por que o livro diz que no Git é muito difícil perder dados?

Como o Git quase apenas adiciona dados ao banco de objetos quando você executa ações, qualquer arquivo que tenha sido confirmado em um commit (e até arquivos adicionados à Staging Area com git add) recebe um objeto próprio identificado por hash dentro da pasta .git/objects. Enquanto um arquivo está apenas modificado no Working Tree sem nunca ter passado por git add ou git commit, o banco do Git ainda não guarda aquela fotografia — e é por isso que criar pequenos commits frequentes funciona como uma rede de proteção quase à prova de falhas.

Entrega da etapa

Explique com suas próprias palavras, usando um exemplo de um projeto seu, a diferença entre alterar um arquivo na Working Tree, enviá-lo para a Staging Area e confirmá-lo no Git Directory, e por que a Staging Area permite montar commits limpos mesmo quando você editou cinco arquivos diferentes na mesma manhã.

Conexão com o livro · Capítulo 1 (Seções 1.1 a 1.3) · evolução do controle de versão, história do Git, snapshots vs. deltas, integridade SHA-1 e os três estados.

Oficina 02 / 08

Configure sua identidade em três níveis e domine a ajuda offline

Você trabalha em projetos pessoais e no repositório da empresa no mesmo computador, mas descobre tarde demais que dez commits corporativos saíram assinados com seu e-mail pessoal. Como o Git decide qual configuração vence?

Os três arquivos do git config e a regra de precedência

Nas Seções 1.4 a 1.7, os autores explicam por que todo profissional deve aprender primeiro a linha de comando (o único lugar onde todos os recursos do Git estão disponíveis e que funciona igual em qualquer servidor) e como o comando git config lê e grava variáveis em três níveis hierárquicos:

  1. Nível Sistema (git config --system): lê e grava no arquivo /etc/gitconfig. Vale para todos os usuários daquele sistema operacional e todos os seus repositórios (exige permissão de administrador para editar).
  2. Nível Global do Usuário (git config --global): lê e grava em ~/.gitconfig (ou ~/.config/git/config). Vale para todos os repositórios que você abrir na sua conta de usuário.
  3. Nível Local do Repositório (git config --local): lê e grava em .git/config dentro da pasta do repositório atual. É o nível padrão quando você não passa flag alguma e vale apenas para aquele projeto específico.

A regra de ouro é que cada nível mais específico sobrescreve o anterior: uma configuração em .git/config (local) vence ~/.gitconfig (global), que por sua vez vence /etc/gitconfig (system). Como cada commit do Git grava de forma imutável o nome e o e-mail do autor nos objetos do histórico, você pode definir seu e-mail pessoal com --global e, dentro da pasta do trabalho, rodar git config --local user.email voce@empresa.com.br.

Níveis de configuração do Git e onde cada arquivo reside
Flag do comandoArquivo lido e alteradoEscopo e precedência
--system/etc/gitconfigTodos os usuários da máquina (menor prioridade).
--global~/.gitconfig ou ~/.config/git/configTodos os repositórios do seu usuário; sobrescreve --system.
--local (padrão).git/config no repositório atualApenas o repositório atual; vence todos os outros níveis.
Comando para experimentar
# 1. Configure sua identidade global, editor de texto e branch padrão inicial:
git config --global user.name "Seu Nome"
git config --global user.email "seu.email@exemplo.com.br"
git config --global init.defaultBranch main
git config --global core.editor "code --wait"

# 2. Descubra exatamente de qual arquivo cada configuração está vindo:
git config --list --show-origin

# 3. Consulte o valor específico de uma chave e teste o resumo rápido de ajuda (-h):
git config user.email
git add -h
git config -h

Como consultar o manual completo sem depender de busca na internet

Se você esquecer as opções de qualquer comando, o próprio Git traz os manuais completos embutidos offline. Você pode usar três formas equivalentes para abrir a página de manual detalhada: git help <verbo>, git <verbo> --help ou man git-<verbo> (por exemplo, git help config). Quando precisar apenas lembrar rapidamente o nome de uma flag sem sair do terminal atual, use a opção curta -h (como git commit -h ou git log -h).

Como diagnosticar quando git config --list mostra a mesma chave duas vezes?

O comando git config --list lê todos os arquivos de configuração na ordem (sistema, global e local). Se user.email estiver definido tanto no seu ~/.gitconfig quanto no .git/config do repositório atual, a chave aparecerá duas vezes na listagem! Nessa situação, o Git utiliza sempre o último valor listado. Usar git config --list --show-origin revela na hora qual arquivo está sobrescrevendo o valor.

Entrega da etapa

Execute git config --list --show-origin na sua máquina. Verifique se user.name, user.email, core.editor e init.defaultBranch estão configurados e teste sobrescrever o user.email com --local dentro de um repositório de teste para comprovar a precedência.

Conexão com o livro · Capítulo 1 (Seções 1.4 a 1.7) · linha de comando, instalação, git config (--system, --global, --local), identidade, editor, init.defaultBranch e git help.

Oficina 03 / 08

Inicie repositórios, leia o status curto e construa um .gitignore sólido

Você roda git status -s e encontra a linha MM config.py antes de commitar. O que significa ter um M na coluna da esquerda e outro M na coluna da direita ao mesmo tempo — e o que realmente entrará no commit se você rodar git commit agora?

Inicializar vs. Clonar e o ciclo de vida dos arquivos

No início do Capítulo 2 (Seções 2.1 e 2.2), você obtém um repositório Git de duas maneiras: entrando em um diretório existente e rodando git init (que cria o subdiretório .git sem rastrear nada até seu primeiro git add) ou rodando git clone <url> [nome-opcional-da-pasta], que baixa todas as versões de todos os arquivos da história do servidor e já faz o checkout da branch principal.

A partir daí, cada arquivo na sua Working Tree está em uma de duas grandes categorias: Untracked (não rastreado: arquivos novos que não estavam no último snapshot e ainda não foram enviados à Staging Area) ou Tracked (rastreado: arquivos que o Git já conhece e que podem estar Unmodified, Modified ou Staged). O comando git add é multifuncional: serve para começar a rastrear um arquivo novo, para enviar a versão atual de um arquivo já rastreado para a Staging Area e para marcar arquivos com conflito de merge como resolvidos.

A pegadinha clássica acontece quando você roda git add config.py e, dois minutos depois, faz mais um ajuste em config.py no editor sem rodar git add de novo. Como o Git coloca na Staging Area uma fotografia exata do arquivo no instante em que você rodou git add, o arquivo passa a ter uma versão preparada para o commit e outra versão mais nova apenas no diretório de trabalho. No modo compacto git status -s, a coluna da esquerda mostra o estado da Staging Area e a coluna da direita mostra o estado da Working Tree:

Decifrando as duas colunas do comando git status -s (--short)
Saída em git status -sColuna Esquerda (Staging Area)Coluna Direita (Working Tree)Significado prático
?? relatorio.log? (Não rastreado)? (Não rastreado)Arquivo novo que o Git ainda ignora nas fotografias.
A lib/auth.pyA (Adicionado ao stage)Espaço (Sem mudanças extras)Arquivo novo pronto para entrar no próximo commit.
M README.mdM (Modificado no stage)Espaço (Limpo no disco)Alteração já preparada com git add; entrará inteira no commit.
M README.mdEspaço (Fora do stage)M (Modificado no disco)Arquivo alterado no editor, mas ainda fora do próximo commit.
MM config.pyM (Primeira edição no stage)M (Segunda edição fora)Atenção: só a primeira edição entrará no commit se você não rodar git add de novo!

Padrões glob no arquivo .gitignore

Para que arquivos gerados automaticamente (logs, pastas de build, artefatos temporários e segredos locais) não apareçam o tempo todo como ?? nem sejam adicionados por engano, crie um arquivo .gitignore na raiz do repositório seguindo as regras da Seção 2.2:

Comando para experimentar
# 1. Inicie um repositório no laboratório e crie um .gitignore com todas as regras do livro:
cd ~/lab-git-etapa1
git init

cat << 'EOF' > .gitignore
# Ignora todos os arquivos terminados em .a ou .log
*.[oa]
*.log

# Mas rastreia especificamente lib.a, mesmo ignorando *.a acima (!)
!lib.a

# Ignora apenas o arquivo TODO na raiz, mas nao subdir/TODO (/)
/TODO

# Ignora qualquer diretorio chamado build em qualquer nivel (barra no final)
build/

# Ignora arquivos .pdf dentro de doc/ e em qualquer subdiretorio de doc/ (**)
doc/**/*.pdf
EOF

# 2. Reproduza o estado "MM" na prática e confira com git status -s:
echo "versao 1" > app.py
git add .gitignore app.py
echo "versao 2 editada depois do add" >> app.py
git status -s
Por que um arquivo que já foi commitado antes continua aparecendo mesmo depois de entrar no .gitignore?

As regras do .gitignore aplicam-se apenas a arquivos que ainda não são rastreados (Untracked). Se alguém fez commit de um arquivo .env ou debug.log ontem e você adicionou *.log ao .gitignore hoje, o Git continuará rastreando as modificações daquele arquivo porque ele já faz parte do catálogo de objetos rastreados. Na Oficina 04 você verá como resolver isso sem apagar o arquivo do seu disco usando git rm --cached.

Entrega da etapa

Monte o arquivo .gitignore padrão para a linguagem ou ferramenta que você usa no dia a dia (incluindo pelo menos uma regra de diretório com /, um curinga com ** e uma exceção com !) e explique em uma frase o que você deve fazer quando encontrar um arquivo marcado como MM no git status -s.

Conexão com o livro · Capítulo 2 (Seções 2.1 e 2.2) · git init, git clone, ciclo de vida dos arquivos, git add, git status -s e padrões glob no .gitignore.

Oficina 04 / 08

Compare alterações exatas com git diff, grave commits e gerencie arquivos

Você preparou dois arquivos com git add, rodou git diff para revisar antes do commit e o terminal não mostrou absolutamente nada. Por que o comando voltou vazio se há alterações prontas para entrar no commit?

A diferença crucial entre git diff e git diff --staged

enquanto o git status responde quais arquivos foram tocados, o git diff mostra exatamente quais linhas foram adicionadas ou removidas. O ponto em que muitos profissionais se confundem é que git diff sem parâmetros não mostra todas as alterações desde o último commit: ele compara apenas a sua Working Tree com a sua Staging Area. Ou seja, se você já enviou todas as suas mudanças para a área de preparação com git add, git diff retornará vazio!

Para ver exatamente o que está na Staging Area prestes a entrar no próximo commit (comparando a Staging Area com o último commit), você deve usar git diff --staged (ou seu sinônimo git diff --cached). Quando o mesmo arquivo tem parte das mudanças no stage e parte fora (o caso MM da oficina anterior), os dois comandos mostram metades diferentes do seu trabalho:

O que cada comando de comparação inspeciona no Git
ComandoO que ele comparaPergunta que ele responde
git diffWorking Tree ↔ Staging Area“O que eu editei no disco que ainda não enviei para o git add?”
git diff --staged (ou --cached)Staging Area ↔ Último Commit“O que já está preparado e entrará na fotografia se eu rodar git commit agora?”
git commit -vAbre o editor com o diff do stage no rodapé“Posso revisar linha por linha enquanto escrevo a mensagem do commit?”

Gravar commits, pular o stage (-a), remover (--cached) e renomear (git mv)

Ao confirmar suas alterações com git commit (ou git commit -m "mensagem"), o Git grava o snapshot e retorna a branch, o checksum curto SHA-1 (como 463dc4f) e a contagem de arquivos e linhas alteradas. Se você quiser pular a etapa do git add para todos os arquivos que já são rastreados, pode usar git commit -a -m "mensagem" — mas tome cuidado: ele inclui qualquer modificação em arquivos rastreados naquela pasta e ignora arquivos novos (Untracked).

Para remover um arquivo do projeto, apagar apenas no sistema operacional com rm deixa a exclusão fora da Staging Area. Rodar git rm <arquivo> remove do disco e já prepara a exclusão para o próximo commit. Mas a joia operacional do Capítulo 2 é git rm --cached <arquivo>: ele remove o arquivo da Staging Area e do controle do Git daqui para frente, mas mantém o arquivo intacto no seu disco local — perfeito quando alguém deu git add em um arquivo de configuração local ou log pesado que deveria estar no .gitignore. Já para renomear ou mover arquivos em um único passo, use git mv arquivo_antigo arquivo_novo (que executa exatamente o equivalente a mv, git rm e git add).

Comando para experimentar
# 1. Compare o que está fora do stage (git diff) com o que já está no stage (git diff --staged):
cd ~/lab-git-etapa1
git diff
git diff --staged

# 2. Faça o primeiro commit e simule o erro clássico de versionar um arquivo de segredo local:
git add app.py
git commit -m "Adiciona script inicial de processamento"
echo "SENHA_LOCAL=12345" > .env
git add .env && git commit -m "Adiciona arquivo por engano"

# 3. Pare de rastrear o .env no Git SEM apagá-lo da sua máquina (--cached):
echo ".env" >> .gitignore
git rm --cached .env
git add .gitignore
git commit -m "Remove .env do controle de versao mantendo copia local"
ls -la .env
Por que usar git mv se o Git guarda snapshots e não rastreia movimentos explicitamente?

Embora o Git armazene snapshots completos e descubra sozinho a posteriori que um arquivo foi renomeado ao comparar o conteúdo idêntico entre dois commits, rodar git mv README.md LEIAME.md economiza três comandos manuais (renomear no sistema operacional, rodar git rm no nome antigo e rodar git add no nome novo) e já deixa a renomeação pronta na Staging Area.

Entrega da etapa

Pratique o fluxo completo de inspeção antes de commitar: modifique dois arquivos, envie apenas um para a Staging Area, compare a saída de git diff com git diff --staged e teste remover um arquivo do rastreamento usando git rm --cached sem perdê-lo no diretório local.

Conexão com o livro · Capítulo 2 (Seção 2.2) · git diff, git diff --staged/--cached, git difftool, git commit (-v, -m, -a), git rm (--cached) e git mv.

Oficina 05 / 08

Investigue o histórico com git log forense e simule o ganho na revisão

Da busca por uma linha alterada ao cálculo do tempo da equipe

Marina lidera uma equipe de seis pessoas que mantém o sistema de faturamento de uma distribuidora em Belo Horizonte. Na segunda-feira de manhã, o cálculo de desconto por lote começou a arredondar centavos para baixo. O repositório tem mais de dois mil commits, mas muitas entregas antigas foram salvas em commits gigantescos de 40 arquivos com a mensagem “ajustes gerais”. Antes de sair abrindo arquivo por arquivo, Marina usa os filtros forenses do git log ensinados na Seção 2.3 do livro para encontrar exatamente qual commit tocou na função de desconto.

Transforme o git log em uma lente de precisão

Sem argumentos, git log lista os commits em ordem cronológica reversa (do mais recente para o mais antigo) com SHA-1, autor, data e mensagem. Para investigar problemas reais, Chacon e Straub combinam quatro famílias de opções:

Primeiro, para ver o conteúdo alterado, use git log -p -2 (que mostra o patch/diff completo dos últimos 2 commits) ou git log --stat (que lista quais arquivos mudaram e quantas linhas foram somadas ou subtraídas em cada commit). Segundo, para formatar e desenhar a árvore, use git log --pretty=oneline ou um formato personalizado como git log --pretty=format:"%h - %an, %ar : %s" --graph (onde %h é o hash abreviado, %an o nome do autor, %ar a data relativa e %s o assunto). Terceiro, para filtrar por tempo, autor e mensagem, combine --since=2.weeks (ou datas exatas como --since="2026-10-01" e --before="2026-11-01"), --author="Marina", --grep="fatura" e --no-merges (que oculta commits de merge para limpar a leitura).

Quarto, a ferramenta mais poderosa da Seção 2.3 é o filtro pickaxe (-S): rodar git log -S calcular_desconto -p não busca apenas onde a palavra existe hoje — ele vasculha a história e mostra apenas os commits que adicionaram ou removeram aquela string ou função do código, podendo ainda restringir a um arquivo ou pasta com -- src/faturamento.py no final do comando.

Comando para experimentar
# 1. Visualize o histórico em formato compacto com gráfico ASCII, autor e data relativa:
git log --pretty=format:"%h - %an, %ar : %s" --graph

# 2. Veja o resumo estatístico (--stat) e o diff completo (-p) apenas dos últimos 2 commits:
git log --stat -2
git log -p -2

# 3. Busca forense (Pickaxe -S): encontre exatamente qual commit adicionou ou removeu
#    uma função ou variável específica nos últimos 30 dias, ignorando commits de merge:
git log -S "SENHA_LOCAL" --since=30.days --no-merges -p

Meça o impacto operacional de commits atômicos e bem descritos

Para convencer a equipe a abandonar commits gigantescos de fim de expediente e adotar commits pequenos e focados (revisados com git diff --staged), Marina mede o custo da rotina de auditoria e lançamento de versões durante um mês piloto. Cada entrega quinzenal homologada gera um benefício operacional estimado (em horas de engenharia poupadas e chamados evitados) equivalente a R$ 180 por pacote entregue. O tempo de revisão e execução de testes por pacote consome R$ 55 variáveis. Treinar a equipe, configurar os templates e padronizar o repositório levou R$ 400 iniciais. Porém, sempre que um commit mistura arquivos indevidos ou quebra a versão e exige investigação manual e reversão de emergência, o retrabalho custa R$ 90.

Balanço operacional por entrega no piloto de padronização Git
Componente avaliadoValor por entrega
Valor operacional economizado por entrega limpa em produçãoR$ 180
Custo de tempo de revisão (git diff --staged) e validaçãoR$ 55
Ganho líquido de contribuição por entregaR$ 125

A conta é direta: 180 − 55 = R$ 125 de ganho líquido por entrega. Para cobrir os R$ 400 de estruturação inicial da equipe, bastam 4 entregas limpas (4 × 125 = R$ 500). Em um mês com 10 entregas realizadas e apenas 1 reversão causada por arquivo não revisado (1 × R$ 90), o saldo líquido do piloto fecha em 10 × 125 − 400 − 90 = R$ 760 positivos.

Sua decisão sobre o padrão de commits da equipe

Antes do piloto, Marina combinou que o novo fluxo seria aprovado se atingisse pelo menos 8 entregas no mês, saldo positivo e zero commits com arquivos de configuração local vazados. O mês fechou com 10 entregas, R$ 760 de saldo, mas 1 reversão porque um desenvolvedor usou git commit -a e incluiu um arquivo alterado sem querer. Registre em três linhas que regra prática você ajustaria para a semana seguinte.

Conferir uma decisão possível

O ganho do fluxo ficou evidente no saldo positivo e na rapidez de achar problemas com git log -S. Como a única falha veio do uso automático de git commit -a sem conferência prévia, a correção mais simples e eficaz é desencorajar o atalho -a em favor de revisar sempre com git status -s e git diff --staged (ou usar git commit -v para ver o diff dentro do editor antes de salvar a mensagem).

Três filtros de git log para guardar no bolso

Descobrir tudo o que mudou em um único arquivo crítico

Quando um arquivo de configuração ou módulo específico começa a apresentar erro, adicione -- caminho/do/arquivo após as opções do comando: git log -p --no-merges -- src/calculo.py. O duplo traço (--) avisa explicitamente ao Git que o que vem depois é um caminho de arquivo e não o nome de uma branch ou tag.

Cruzar autor, janela de datas e palavra-chave na mensagem

Se você sabe quem fez a alteração e aproximadamente quando ela entrou, combine os filtros na mesma chamada: git log --pretty="%h - %s" --author="Lucas" --since="2026-10-01" --before="2026-11-12" --grep="frete". Por padrão, passar múltiplos --grep ou --author busca qualquer um deles; adicione --all-match quando quiser exigir que todos os filtros sejam verdadeiros no mesmo commit.

Diferenciar Autor (Author) de Confirmador (Committer)

Na tabela de formatadores do Capítulo 2, o Git separa %an (nome do Author: quem originalmente escreveu o código) de %cn (nome do Committer: a última pessoa que aplicou o commit ao repositório, por exemplo ao aplicar um patch por e-mail ou reescrever um commit). Saber que os dois campos existem evita confusão ao auditar projetos colaborativos.

Simule o saldo de produtividade e retrabalho no controle de versão

Os valores iniciais reproduzem o piloto da equipe de Marina. Altere um número por vez para observar como o custo de reversões e commits mal revisados afeta o retorno da equipe.

Saldo = entregas × (ganho − custo de revisão) − investimento inicial − reversões × custo por reversão. O ponto de equilíbrio exibido considera o investimento inicial antes das reversões.

Conexão com o livro · Capítulo 2 (Seção 2.3) · git log (-p, --stat, --pretty=oneline/format, --graph, --since/--until, --author, --grep, --no-merges e pickaxe -S).

Oficina 06 / 08

Desfaça enganos com segurança usando --amend e git restore

Saiba exatamente o que pode ser revertido e o que apaga trabalho para sempre

Na Seção 2.4, Chacon e Straub fazem um alerta direto: esta é uma das poucas áreas do Git em que uma escolha precipitada pode custar trabalho perdido. Isso acontece porque dois comandos muito parecidos atuam em zonas completamente diferentes — um apenas move um arquivo de volta da Staging Area para o diretório de trabalho sem tocar nas linhas que você digitou, enquanto o outro sobrescreve o seu arquivo no disco com a cópia antiga do último commit.

Os três cenários clássicos de correção local

  1. Retificar o último commit (git commit --amend): você acabou de fazer um commit e percebeu um erro de digitação na mensagem ou esqueceu de adicionar um arquivo modificado. Em vez de criar um segundo commit chamado “ops, esqueci um arquivo”, prepare o arquivo esquecido com git add arquivo_esquecido e execute git commit --amend. O Git pega o que está na Staging Area e usa para substituir o último commit como se o anterior nunca tivesse existido. Regra de segurança: só use --amend em commits que ainda estão apenas na sua máquina (antes de fazer git push), pois ele altera o SHA-1 do commit.
  2. Tirar um arquivo da Staging Area sem perder suas edições (git restore --staged): você modificou dois arquivos e rodou git add * por impulso, mas quer que apenas o primeiro entre no commit de agora. Rodar git restore --staged <arquivo> (ou a forma clássica git reset HEAD <arquivo>) tira o arquivo do estado Staged e o devolve para Modified intacto. Nenhuma linha digitada no seu editor é perdida.
  3. Descartar alterações locais no arquivo (git restore <arquivo> — CUIDADO): se você editou um arquivo na Working Tree e quer jogar fora todas as alterações feitas desde o último commit, você usa git restore <arquivo> (ou a forma antiga git checkout -- <arquivo>). O livro destaca que esse é um comando perigoso: como aquelas edições nunca chegaram a virar um commit no banco do Git, sobrescrever o arquivo faz com que elas desapareçam sem possibilidade de recuperação pelo Git.
Comando para experimentar
# 1. Corrija o último commit incluindo um arquivo esquecido sem criar um commit extra:
cd ~/lab-git-etapa1
echo "modulo extra" > util.py
git commit -m "Adiciona utilitario (faltou dar git add no util.py)" --allow-empty
git add util.py
git commit --amend -m "Adiciona utilitario completo no mesmo commit"

# 2. Envie um arquivo para o stage e retire-o com segurança preservando o código no disco:
echo "nova linha em teste" >> app.py
git add app.py
git status -s
git restore --staged app.py
git status -s

# 3. Confira que a linha continua salva no arquivo local antes de decidir se quer descartá-la:
cat app.py
Comparar os comandos antigos (reset / checkout) com o git restore (Git 2.23+)

Historicamente, o Git usava git reset HEAD <arquivo> para tirar do stage e git checkout -- <arquivo> para descartar mudanças no disco. Como reset e checkout também acumulam dezenas de funções de manipulação de branches e commits, a partir do Git 2.23 foi introduzido o comando dedicado git restore, que inclusive aparece nas dicas do próprio git status atual. Vale conhecer ambos porque você encontrará os dois em documentações e servidores diferentes.

Tabela de segurança antes de desfazer qualquer ação

Comparação de risco ao desfazer alterações locais no Git
ObjetivoComando moderno (e clássico)Preserva as edições no disco?Risco operacional
Corrigir mensagem ou somar arquivo ao último commitgit commit --amendSim (substitui o último commit local)Baixo se o commit ainda não foi enviado via git push
Retirar arquivo da Staging Area (Unstage)git restore --staged <arq>
(ou git reset HEAD <arq>)
Sim (arquivo volta para Modified intacto)Seguro — nenhum texto digitado é apagado
Reverter arquivo modificado ao último commitgit restore <arq>
(ou git checkout -- <arq>)
Não (sobrescreve o arquivo no disco)Alto — mudanças não commitadas são perdidas

Defina seu protocolo de recuperação sem perda

Imagine que você escreveu 80 linhas de código experimental em um arquivo e quer voltar o arquivo ao estado original para testar outra abordagem, mas tem receio de precisar daquelas 80 linhas à tarde. Baseado no fato de que tudo o que é commitado no Git pode ser recuperado, escreva uma alternativa mais segura do que rodar git restore <arquivo> direto.

Conexão com o livro · Capítulo 2 (Seção 2.4) · desfazer alterações, git commit --amend, unstage com git reset HEAD / git restore --staged e descarte com git checkout -- / git restore.

Oficina 07 / 08

Trabalhe com repositórios remotos e diferencie fetch de pull

Dois desenvolvedores clonaram o mesmo projeto às 9h. Às 10h, sua colega enviou dois commits para o servidor. Às 10h05, você tenta rodar git push origin main e o servidor rejeita o envio. Por que essa rejeição protege a equipe e por que usar git fetch primeiro dá mais controle que git pull?

Gerenciar múltiplos remotos e entender o ponteiro origin

Na Seção 2.5, os autores esclarecem que um repositório remoto é apenas outra cópia do seu projeto hospedada na internet, na rede da empresa ou até em outra pasta do seu próprio computador. Quando você clona um repositório com git clone, o Git dá automaticamente ao servidor de origem o apelido curto origin e aponta sua branch local para acompanhar a branch principal remota.

Você pode listar os servidores configurados com git remote -v (que exibe as URLs de fetch e push), adicionar repositórios de outros colaboradores do projeto com git remote add <apelido> <url> (permitindo buscar contribuições diretamente com git fetch <apelido>), renomear um apelido com git remote rename antigo novo, remover com git remote remove <apelido> e inspecionar todos os detalhes de rastreamento do servidor usando git remote show origin.

Comando para experimentar
# 1. Simule um servidor remoto local (--bare) para testar fetch, push e remote show sem internet:
mkdir -p ~/servidor-remoto.git && git init --bare ~/servidor-remoto.git

# 2. Conecte seu repositório de laboratório ao remoto "origin" e envie a branch principal:
cd ~/lab-git-etapa1
git remote add origin ~/servidor-remoto.git
git remote -v
git push -u origin main

# 3. Inspecione o relatório completo do remoto e teste buscar atualizações com git fetch:
git remote show origin
git fetch origin

Teste de raciocínio: git fetch vs. git pull

Muitos tutoriais tratam git fetch e git pull como quase sinônimos, mas o Capítulo 2 enfatiza uma diferença operacional decisiva. Imagine que você está no meio de uma refatoração delicada na sua branch main e quer verificar o que seu colega acabou de subir para o servidor origin sem misturar nada com os seus arquivos atuais ainda. Qual dos dois comandos você deve rodar e onde os commits baixados ficam guardados?

Consultar uma pista

Lembre-se de que o Git separa as referências remotas (como origin/main) da sua branch de trabalho local (main). Qual comando atualiza apenas o banco de objetos `.git` e o ponteiro `origin/main` sem tocar na sua Working Tree?

Conferir a solução comentada

Você deve rodar git fetch origin. O comando git fetch conecta-se ao servidor, baixa todos os commits e arquivos novos que você ainda não possui no seu banco local e atualiza o ponteiro remoto origin/main, mas jamais modifica sua Working Tree nem faz merge automático na sua branch atual. Assim, você pode inspecionar o que chegou com git log main..origin/main ou git diff main origin/main e integrar quando estiver pronto. Já o comando git pull executa um git fetch seguido imediatamente de um git merge (ou rebase) na sua branch atual.

Para testar a transferência do conceito, analise outra situação: você tenta executar git push origin main, mas recebe um erro informando que a ponta da sua branch atual está atrás da contraparte remota (non-fast-forward). Por que o Git recusa o envio por padrão e qual é a sequência segura para publicar seu trabalho?

Conferir a transferência

O Git recusa o push porque outra pessoa enviou commits para origin/main depois da última vez que você sincronizou; se o servidor aceitasse sua versão diretamente, sobrescreveria os commits do seu colega. A sequência correta é buscar o trabalho remoto primeiro (git fetch origin), inspecionar e integrar as mudanças do colega ao seu histórico local e só então executar git push origin main.

Entrega da etapa

Execute git remote -v e git remote show origin em um projeto real (ou no laboratório local acima). Anote qual branch é o HEAD branch do servidor, quais branches estão configuradas para git pull e git push e adicione um segundo remoto de teste para praticar git fetch.

Conexão com o livro · Capítulo 2 (Seção 2.5) · repositórios remotos, git remote (-v, add, rename, remove, show), git fetch vs. git pull e regras de git push.

Oficina 08 / 08

Marque versões oficiais com Tags e acelere o fluxo com Aliases

Você criou a tag v1.0.0 na sua máquina para marcar o lançamento do sistema, rodou git push origin main e avisou a equipe — mas quando o servidor de deploy foi buscar a tag v1.0.0 no repositório remoto, ela não existia lá. Por que as tags não sobem no git push comum?

Tags Anotadas vs. Tags Leves e marcação retroativa

Na Seção 2.6, aprendemos a marcar pontos específicos da história como versões de lançamento (como v1.0 ou v2.4.1). Para listar as tags existentes em ordem alfabética, basta rodar git tag; para filtrar por padrão (curinga), o Git exige a flag -l ou --list, como em git tag -l "v1.8.5*". Ao criar uma tag, o Git oferece dois tipos com estruturas internas diferentes:

Uma Tag Anotada (Annotated Tag), criada com git tag -a v1.4 -m "Versão 1.4 de produção", é armazenada como um objeto completo no banco de dados do Git: ela possui checksum próprio, guarda o nome, o e-mail e a data da pessoa que criou a tag, armazena uma mensagem descritiva e pode ser assinada e verificada criptograficamente com GPG. Já uma Tag Leve (Lightweight Tag), criada apenas com git tag v1.4-lw (sem -a, -s ou -m), é apenas um ponteiro estático que guarda o checksum de um commit em um arquivo, sem metadados extras. Para lançamentos oficiais, o livro recomenda sempre usar tags anotadas para preservar quem lançou a versão e quando.

Se você esqueceu de marcar uma versão na sexta-feira e já fez outros cinco commits depois, não há problema: consulte o histórico com git log --pretty=oneline, copie o início do checksum SHA-1 daquele commit de sexta-feira e passe-o no final do comando: git tag -a v1.2 9fceb02 -m "Versão de sexta-feira".

Comando para experimentar
# 1. Crie uma tag anotada (-a) na versão atual e inspecione seus metadados com git show:
cd ~/lab-git-etapa1
git tag -a v1.0.0 -m "Primeiro lancamento oficial da Etapa 1"
git show v1.0.0

# 2. Envie a tag explicitamente para o servidor remoto (git push comum não envia tags!):
git push origin v1.0.0

# 3. Configure os aliases clássicos do Capítulo 2.7 para acelerar o trabalho diário:
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'

# Teste seu novo comando "git last" e "git st":
git last
git st -s

Publicação, exclusão, Detached HEAD e Git Aliases

Três cuidados completam o domínio das tags no Capítulo 2:

  1. Compartilhar no servidor: por padrão, o comando git push não transfere tags para os servidores remotos. Você precisa enviá-las explicitamente como faz com uma branch (git push origin v1.0.0) ou enviar todas as tags locais de uma vez com git push origin --tags (lembrando que --tags envia tanto tags anotadas quanto leves).
  2. Apagar tags locais e remotas: para remover uma tag da sua máquina, use git tag -d v1.4-lw. Isso não apaga a tag no servidor remoto; para removê-la do servidor, execute git push origin --delete v1.4-lw (ou git push origin :refs/tags/v1.4-lw).
  3. Cuidado com o estado Detached HEAD ao fazer checkout de uma tag: como uma tag não pode ser movida como uma branch, rodar git checkout v1.0.0 coloca seu repositório em modo detached HEAD (cabeçalho destacado). Se você fizer um commit nesse estado, ele não pertencerá a nenhuma branch e ficará acessível apenas pelo hash exato. Quando precisar corrigir um bug em cima de uma versão antiga marcada por tag, crie uma branch nova a partir da tag com git checkout -b correcao-v1 v1.0.0 (ou git switch -c correcao-v1 v1.0.0).

Por fim, na Seção 2.7, o livro mostra como criar Git Aliases para evitar digitação repetitiva e até melhorar a usabilidade do próprio Git, como criar git unstage (`git config --global alias.unstage 'reset HEAD --'`) e git last (`git config --global alias.last 'log -1 HEAD'`), ou executar comandos externos prefixando com ponto de exclamação (`git config --global alias.visual '!gitk'`).

Entrega da etapa

Crie uma tag anotada v0.1.0 no seu repositório de prática, confira a diferença no git show em relação a uma tag leve, configure os aliases st, last e unstage no seu --global e registre como sua equipe padronizará a publicação e correção de versões com tags.

Conexão com o livro · Capítulo 2 (Seções 2.6 a 2.8) · git tag (-l, -a, leve, retroativa), git show, git push origin <tag>/--tags, exclusão remota, detached HEAD e Git Aliases.

Projeto de aplicação · Etapa 1

Estruture e audite um repositório profissional do zero.

Escolha um projeto real (ou crie um repositório de referência para sua equipe) aplicando todos os fundamentos dos Capítulos 1 e 2. Sua entrega é um guia operacional enxuto que evita os erros mais comuns de versionamento.

Roteiro de prática de uma semana

  1. Dia 1. Audite a configuração da sua máquina com git config --list --show-origin, ajuste sua identidade global/local, o editor padrão e os aliases st, last e unstage.
  2. Dias 2 e 3. Inicie ou clone o projeto, construa um .gitignore completo com regras de diretório, curingas ** e exceções !, e limpe qualquer arquivo indevido já rastreado usando git rm --cached.
  3. Dias 4 e 5. Pratique o ciclo de commits atômicos conferindo sempre git status -s, git diff e git diff --staged antes de cada gravação. Teste retificar um commit local com git commit --amend.
  4. Dia 6. Audite o histórico do projeto com git log --pretty=format:"%h - %an, %ar : %s" --graph e use o filtro pickaxe git log -S para localizar a origem de uma função importante.
  5. Dia 7. Conecte o repositório remoto, inspecione com git remote show origin, crie uma tag anotada v1.0.0 e publique código e tag no servidor.

Decisões para praticar

Escolha uma resposta em cada situação real do dia a dia. A correção explica o funcionamento interno dos Capítulos 1 e 2 e permite tentar novamente.

1. Você editou o arquivo "calculo.py", rodou "git add calculo.py" e, logo em seguida, editou mais três linhas em "calculo.py" sem rodar "git add" de novo. O que acontece se você rodar "git commit -m 'Ajusta cálculo'" agora?
2. Um colega comitou sem querer o arquivo "config.local.json" na semana passada. Hoje você quer adicionar esse arquivo ao ".gitignore" para que o Git pare de rastreá-lo, mas sem apagá-lo do disco de ninguém. Qual comando resolve?
3. Qual comando permite encontrar no histórico apenas os commits que adicionaram ou removeram as ocorrências da função "calcular_frete" no código?
4. Qual é a diferença prática entre rodar "git fetch origin" e "git pull" ao trabalhar com um repositório remoto?

Minha síntese da Etapa 1

Checklist de domínio da Etapa 1

Consultar anotações das oito oficinas
Suas anotações ficam neste navegador.
Próximo passo na Trilha Pro Git · Etapa 2 de 4

Pronto para dominar ramificações (branches) e trabalho em equipe?

Na Etapa 2: Trabalho em Equipe e Fluxos (Capítulos 3, 5 e 6), você vai aprender como o Git cria branches leves em milissegundos, como resolver conflitos de merge e rebase e como operar fluxos distribuídos e Pull Requests.

Continuar para a Etapa 2 →
Livro-base e mapa das 4 etapas do curso

Scott Chacon e Ben Straub. Pro Git, 2ª edição. Apress, 2014 (com atualizações contínuas da comunidade). Esta Etapa 1: O Básico Essencial cobre integralmente os Capítulos 1 (Getting Started) e 2 (Git Basics) em uma adaptação didática e prática em português brasileiro. Edição oficial aberta em git-scm.com.

Mapa das próximas etapas desta formação: Etapa 2: Trabalho em Equipe e Fluxos (Caps. 3, 5 e 6) · Etapa 3: Produtividade e Limpeza de Histórico (Cap. 7) · Etapa 4: Administração e Arquitetura Interna (Caps. 4, 8, 9 e 10).