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.
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.
Compreenda por que o Git guarda instantâneos (não diferenças) e domine Working Tree, Staging Area e Git Directory.
OFICINA 02Configurar identidade ↗Audite a precedência entre system, global e local, defina seu editor, branch inicial e consulte manuais offline.
OFICINA 03Rastrear e ignorar ↗Inicie ou clone repositórios, interprete a saída curta do git status -s e construa regras sólidas no .gitignore.
OFICINA 04Diffs, commits e arquivos ↗Diferencie git diff de git diff --staged, faça commits verificados e pare de rastrear arquivos com git rm --cached.
OFICINA 05Investigar o histórico ↗Filtre commits por data, autor e gráfico, encontre quando uma função mudou com git log -S e simule ganhos de revisão.
OFICINA 06Desfazer com segurança ↗Corrija o último commit com --amend, tire arquivos do stage com git restore --staged e saiba o que não tem volta.
OFICINA 07Sincronizar remotos ↗Adicione múltiplos remotos, compare git fetch com git pull, publique branches e inspecione o servidor com remote show.
OFICINA 08Tags de versão e aliases ↗Crie tags anotadas e leves, marque commits antigos, publique tags no servidor e crie atalhos de produtividade.
“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.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:
- 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.
- 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. - 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:
| Estado do arquivo | Seçã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. |
# 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.
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:
- 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). - 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. - Nível Local do Repositório (
git config --local): lê e grava em.git/configdentro 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.
| Flag do comando | Arquivo lido e alterado | Escopo e precedência |
|---|---|---|
--system | /etc/gitconfig | Todos os usuários da máquina (menor prioridade). |
--global | ~/.gitconfig ou ~/.config/git/config | Todos os repositórios do seu usuário; sobrescreve --system. |
--local (padrão) | .git/config no repositório atual | Apenas o repositório atual; vence todos os outros níveis. |
# 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.
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:
Saída em git status -s | Coluna 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.py | A (Adicionado ao stage) | Espaço (Sem mudanças extras) | Arquivo novo pronto para entrar no próximo commit. |
M README.md | M (Modificado no stage) | Espaço (Limpo no disco) | Alteração já preparada com git add; entrará inteira no commit. |
M README.md | Espaço (Fora do stage) | M (Modificado no disco) | Arquivo alterado no editor, mas ainda fora do próximo commit. |
MM config.py | M (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:
# 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.
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:
| Comando | O que ele compara | Pergunta que ele responde |
|---|---|---|
git diff | Working 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 -v | Abre 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).
# 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.
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.
# 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.
| Componente avaliado | Valor por entrega |
|---|---|
| Valor operacional economizado por entrega limpa em produção | R$ 180 |
Custo de tempo de revisão (git diff --staged) e validação | R$ 55 |
| Ganho líquido de contribuição por entrega | R$ 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).
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
- 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 comgit add arquivo_esquecidoe executegit 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--amendem commits que ainda estão apenas na sua máquina (antes de fazergit push), pois ele altera o SHA-1 do commit. - Tirar um arquivo da Staging Area sem perder suas edições (
git restore --staged): você modificou dois arquivos e rodougit add *por impulso, mas quer que apenas o primeiro entre no commit de agora. Rodargit restore --staged <arquivo>(ou a forma clássicagit reset HEAD <arquivo>) tira o arquivo do estado Staged e o devolve para Modified intacto. Nenhuma linha digitada no seu editor é perdida. - 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ê usagit restore <arquivo>(ou a forma antigagit 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.
# 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
| Objetivo | Comando moderno (e clássico) | Preserva as edições no disco? | Risco operacional |
|---|---|---|---|
| Corrigir mensagem ou somar arquivo ao último commit | git commit --amend | Sim (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 commit | git 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.
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.
# 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.
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".
# 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:
- Compartilhar no servidor: por padrão, o comando
git pushnã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 comgit push origin --tags(lembrando que--tagsenvia tanto tags anotadas quanto leves). - 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, executegit push origin --delete v1.4-lw(ougit push origin :refs/tags/v1.4-lw). - 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.0coloca 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 comgit checkout -b correcao-v1 v1.0.0(ougit 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.
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
- 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 aliasesst,lasteunstage. - Dias 2 e 3. Inicie ou clone o projeto, construa um
.gitignorecompleto com regras de diretório, curingas**e exceções!, e limpe qualquer arquivo indevido já rastreado usandogit rm --cached. - Dias 4 e 5. Pratique o ciclo de commits atômicos conferindo sempre
git status -s,git diffegit diff --stagedantes de cada gravação. Teste retificar um commit local comgit commit --amend. - Dia 6. Audite o histórico do projeto com
git log --pretty=format:"%h - %an, %ar : %s" --graphe use o filtro pickaxegit log -Spara localizar a origem de uma função importante. - Dia 7. Conecte o repositório remoto, inspecione com
git remote show origin, crie uma tag anotadav1.0.0e 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.
Minha síntese da Etapa 1
Checklist de domínio da Etapa 1
Consultar anotações das oito oficinas
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).