Oh Shit, Git!?!

Git é difícil: é muito fácil cagar tudo e impossível descobrir como arrumar. A documentação do Git é como o problema do ovo e da galinha, onde você não consegue pesquisar como resolver a sua cagada a não ser que você já saiba o nome do que você precisa para resolver o seu problema.

Então aqui estão algumas situações complicadas em que me meti e como me safei delas, em português claro.

Merda, eu caguei tudo. Por favor, me diz que o git tem uma máquina do tempo mágica?!?!

git reflog
# Você vai ver uma lista de tudo o que fez 
# em todos os branches no git!
# Cada alteração tem um índice HEAD@{índice}
# Encontre a alteração feita antes de você 
# cagar tudo 
git reset HEAD@{índice}
# máquina do tempo mágica 

Você pode utilizar isso para recuperar coisas excluídas por acidente, ou apenas remover algo que tentou e quebrou o repositório, ou recuperar coisas depois de um merge com problemas, ou, simplemesmente, voltar no tempo para quando as coisas realmente funcionavam. Eu utilizo o reflog PRA CARAMBA. Eu tiro o chapéu para as várias várias várias várias pessoas que sugeriram adicioná-lo!

Merda, acabei de fazer um commit e percebi que tenho que fazer uma pequena alteração

# faça a sua alteração
git add . # ou adicione arquivos individualmente
git commit --amend --no-edit
# agora o seu último commit contém a alteração
# AVISO: nunca faça alterações em commits públicos

Isso normalmente acontece quando eu faço commit, executo testes/linters e... PQP, eu esqueci de colocar um espaço depois de um sinal de igual. Você também pode fazer a alteração como um novo commit e, então, utilizar o rebase -i para fazer o squash desse commit com o anterior, mas o amend é um milhão de vezes mais rápido.

Aviso: Você nunca deve fazer um amend em commits que já foram enviados (push) para uma branch public/compartilhada! Somente faça isso em commits que existem apenas na sua cópia local ou você poderá ter problemas.

Merda, preciso alterar a mensagem do meu último commit!

git commit --amend
# siga as instruções na tela para alterar o commit

Malditas regras idiotas de formatação de mensagens de commit.

Merda, eu fiz um commit na master por engano e deveria ter feito commit em uma branch nova!

# Crie a nova branch a partir da master atual 
git branch minha-nova-branch
# remova o último commit da master
git reset HEAD~ --hard
git checkout minha-nova-branch
# o seu commit está nessa branch agora :)

Nota: isso não funciona se você já fez push do commit para a master. Se você já tentou outras coisas antes, pode utilizar git reset HEAD@{numero-de-commits-anteriores} em vez HEAD~. Muito triste. Muitas muitas muitas pessoas sugeriram um jeito foda para fazer isso que eu mesmo não conhecia. Obrigado!

Merda, fiz commit na branch errada!

# desfaça o último commit, mas mantenha as alterações 
git reset HEAD~ --soft
git stash
# mova as alterações para a branch correta
git checkout nome-da-branch-correta
git stash pop
git add . # ou adicione arquivos individualmente
git commit -m "sua mensagem aqui";
# agora as suas alterações estão na branch correta 

Muitas pessoas sugeriram utilizar cherry-pick para essa situação, então escolha ai o que faz mais sentido para você!

git checkout nome-da-branch-correta 
# pegue o último commit da master 
git cherry-pick master
# remova-o da master
git checkout master
git reset HEAD~ --hard

Merda, tentei fazer um diff e não aconteceu nada?!

Se você sabe que alterou alguns arquivos, mas o diff não retorna nada, você provavelmente já adicionou (git add) esses arquivos na área de staging e, então, vai precisar utilizar uma flag especial.

git diff --staged

Arquivar em ¯\_(ツ)_/¯ (sim, eu sei que isso é uma funcionalidade e não um bug, mas é frustrante pra caralho e totalmente não óbvio na primeira vez que acontece com você!)

Merda, preciso desfazer um commit feito 5 commits atrás!

# encontre o commit que você precisa desfazer
git log
# utilize as setas para navegar pelo histórico 
# quando encontrar o commit, salve o hash 
git revert [hash salvo]
# o git vai criar um commit que desfaz o commit
# siga as instruções para alterar a mensagem de commit
# ou apenas salve e faça o commit

Parece que não é necessário encontrar, copiar e colar o conteúdo antigo do arquivo para desfazer as alterações! Se você fez commit de um bug, é possível desfazer a alteração de uma vez só com o revert.

Você também pode fazer revert de um único arquivo em vez do commit inteiro! Mas, claro, como tudo no git, você precisa de uma caralhada de comandos diferentes para isso...

Merda, preciso desfazer as alterações em um arquivo!

# encontre o hash de um commit feito antes do arquivo ser alterado
git log
# utilize as setas para navegar pelo histórico
# quando encontrar o commit, salve o hash
git checkout [hash salvo] -- caminho/para/o/arquivo
# a versão antiga do arquivo estará no seu índice
git commit -m "Uau, você não precisa copiar e colar para desfazer!"

Quando eu finalmente descobri isso foi SENSACIONAL. SENSACIONAL. S-E-N-S-A-C-I-O-N-A-L. Mas, falando sério, em que merda de planeta que checkout -- faz sentido como a melhor maneira de desfazer alterações em um arquivo? :ameaca-um-soco-no-linus-torvalds:

Foda-se essa merda, eu desisto.

cd ..
sudo rm -r repositorio-git-maldito
git clone https://some.github.url/repositorio-git-maldito.git
cd repositorio-git-maldito

Agradecimentos ao Eric V. por essa. Reclamações sobre a utilização do sudo devem ser enviadas para ele.

Agora, falando sério, se a sua branch está tão cagada que você precisa resetar o seu repositório local para ficar igual ao repositório remoto, tente essa maneira "aprovada pelo git" de fazer isso. Mas lembre que esses comandos são destrutivos e não será possível recuperar as alterações!

# recupere a versão mais atual do repositório remoto 
git fetch origin
git checkout master
git reset --hard origin/master
# remova arquivos e diretórios não rastreados pelo git
git clean -d --force
# repita a sequência checkout/reset/clean para cada branch cagado

*Aviso legal: Este site não pretende ser uma referência completa. Sim, existem outras maneiras de se fazer as mesmas coisas com uma maior pureza teórica ou sei la o quê, mas eu aprendi esses passos através de tentativa e erro, muitos palavrões e socos na mesa, então tive essa ideia maluca de compartilha-los com uma dose saudável de xingamentos. É pegar ou largar!

Muito obrigado a todos os voluntários que traduziram o site para novos idiomas. Vocês são fodas! Michael Botha (af) · Khaja Md Sher E Alam (bn) · Eduard Tomek (cs) · Moritz Stückler (de) · Franco Fantini (es) · Hamid Moheb (fa) · Senja Jarva (fi) · Michel (fr) · Alex Tzimas (gr) · Elad Leev (he) · Aryan Sarkar (hi) · Ricky Gultom (id) · fedemcmac (it) · Meiko Hori (ja) · Zhunisali Shanabek (kk) · Gyeongjae Choi (ko) · Rahul Dahal (ne) · Martijn ten Heuvel (nl) · Łukasz Wójcik (pl) · Davi Alexandre (pt_BR) · Catalina Focsa (ro) · Daniil Golubev (ru) · Nemanja Vasić (sr) · Björn Söderqvist (sv) · Kitt Tientanopajai (th) · Taha Paksu (tr) · Andriy Sultanov (ua) · Tao Jiayuan (zh) . Com a ajuda adicional de Allie Jones · Artem Vorotnikov · David Fyffe · Frank Taillandier · Iain Murray · Lucas Larson · Myrzabek Azil

Se você gostaria de ajudar e traduzi-lo para o seu idioma, envie uma PR em GitHub