
Git Pt.2
5 min read
Comandos Avançados: Quando as Coisas Ficam Complicadas
O básico (add, commit, push, pull) resolve 90% dos casos. Mas os outros 10% são onde os problemas críticos acontecem. Dominar os comandos a seguir é o que diferencia um usuário iniciante de um expert.
git stash: Salvando seu Trabalho Temporariamente
Cenário: Você está no meio da configuração de uma nova política de BGP (feature/bgp-policy), mas um incidente urgente acontece e você precisa verificar o estado de uma configuração no branch main imediatamente. Seu trabalho está incompleto e você não quer fazer um commit "WIP" (Work in Progress).
O git stash salva suas modificações não commitadas em uma "pilha" temporária e limpa seu diretório de trabalho, deixando-o no estado do último commit (HEAD).
graph TD
A[Diretório de Trabalho com Mudanças] -- git stash --> B(Pilha de Stash);
B -- git stash pop --> C[Diretório de Trabalho Restaurado];
Cheatsheet do stash:
| Comando | Descrição |
git stash | Salva as mudanças atuais na pilha de stash. |
git stash list | Lista todos os stashes salvos. |
git stash pop | Aplica o stash mais recente e o remove da pilha. |
git stash apply | Aplica o stash mais recente, mas o mantém na pilha. |
git stash drop | Descarta o stash mais recente. |
Exemplo de fluxo:
# Você está no branch 'feature/bgp-policy' com trabalho não salvo
git status # Mostra arquivos modificados
# Salva o trabalho para atender a uma emergência
git stash
# Muda para o branch principal para investigar
git checkout main
# ... faz a investigação ...
# Volta para seu branch de feature
git checkout feature/bgp-policy
# Restaura seu trabalho não salvo
git stash pop
git status # Seus arquivos modificados estão de volta!
git revert vs git reset: A Batalha pela História do Git
Ambos os comandos desfazem mudanças, mas de maneiras fundamentalmente diferentes. A escolha errada aqui pode causar grandes problemas para sua equipe.
| Característica | git revert <commit> | git reset --hard <commit> |
| Ação | Cria um novo commit que é o inverso do commit especificado. | Move o ponteiro do branch para um commit anterior, descartando todos os commits posteriores. |
| Histórico | Não reescreve o histórico. Adiciona ao histórico. É seguro. | Reescreve (destrói) o histórico. É perigoso. |
| Uso Principal | Reverter um commit que já foi compartilhado com a equipe (ex: já está no main). | Desfazer commits locais que ainda não foram compartilhados. |
| Colaboração | Seguro para branches compartilhados. | NUNCA use em branches compartilhados (como main). |
Visualizando git revert:
Imagine que o commit C introduziu um bug em produção.
gitGraph
commit id: "A"
commit id: "B"
commit id: "C" type: HIGHLIGHT
commit id: "D"
commit id: "C'" type: REVERSE msg: "Revert feat: Adiciona bug"
O git revert C cria um novo commit C' que desfaz as mudanças de C. O histórico é preservado e a mudança é transparente para todos.
Visualizando git reset:
Agora, imagine que C e D são commits ruins que você fez localmente e ainda não compartilhou.
gitGraph
commit id: "A"
commit id: "B"
commit id: "C"
commit id: "D"
Executar git reset --hard B moverá o HEAD do main de volta para B, e os commits C e D serão perdidos (ou, mais precisamente, se tornarão órfãos, aguardando para serem limpos pelo garbage collector do Git).
gitGraph
commit id: "A"
commit id: "B"
Regra de ouro: Se o commit está no repositório remoto (GitHub/GitLab), use git revert. Se o commit só existe na sua máquina local, git reset é uma opção.
git rebase: Reescrevendo a História para um Futuro Mais Limpo
Cenário: Você criou seu branch feature/nova-firewall-policy a partir do main. Enquanto você trabalhava, outros engenheiros mesclaram várias outras mudanças no main. Seu branch de feature agora está desatualizado, e um git merge main criaria um "merge commit" que polui o histórico.
O git rebase resolve isso. Ele pega todos os commits do seu branch e os reaplica "em cima" do estado mais recente do branch alvo (main).
graph TD
subgraph "Antes do Rebase"
A((A)) --> B((B)) --> C((C<br>main))
B --> D((D)) --> E((E<br>feature))
end
subgraph "Depois de 'git rebase main'"
A2((A)) --> B2((B)) --> C2((C<br>main)) --> D2((D')) --> E2((E'<br>feature))
end
style C fill:#f9f,stroke:#333
style E fill:#f9f,stroke:#333
style C2 fill:#f9f,stroke:#333
style E2 fill:#f9f,stroke:#333
Fluxo de trabalho com rebase:
# No seu branch de feature
git checkout feature/nova-firewall-policy
# Busca as últimas mudanças do remoto
git fetch origin
# Rebase do seu branch em cima do 'main' mais recente
git rebase origin/main
# Agora seu branch está atualizado e pronto para um merge limpo (fast-forward)
Aviso: Assim como o
reset, orebasereescreve o histórico (os hashes dos commitsDeEmudam paraD'eE'). Nunca faça rebase de um branch que é compartilhado e usado por múltiplos desenvolvedores (como omain). É seguro para seus próprios branches de feature antes de abrir um PR.
git reflog e git bisect: As Ferramentas do Detetive
git reflog(Reference Log): Seu salva-vidas. O Git mantém um registro de quase tudo que você faz (commits, resets, checkouts). Se você usougit resete acha que perdeu um commit para sempre, ogit reflogmostrará o hash daquele commit perdido, e você pode recuperá-lo comgit checkout <hash>ougit cherry-pick <hash>. É a sua rede de segurança pessoal.git bisect: O caçador de bugs. Se você sabe que um bug foi introduzido em algum momento nos últimos 100 commits, mas não sabe onde, ogit bisectautomatiza a busca. Você informa um commit "bom" (onde o bug não existia) e um commit "ruim" (onde o bug existe). O Git então faz uma busca binária, fazendo checkout de commits no meio do caminho e perguntando a você se o bug está presente. Em poucos passos, ele aponta o commit exato que introduziu a regressão. Isso é incrível para encontrar qual mudança de configuração quebrou a conectividade.
