git checkout, switch e restore: quando usar cada um
O git checkout faz duas coisas diferentes: troca de branch e restaura arquivos. Por isso, desde o Git 2.23, essas tarefas foram divididas entre o git switch (branches) e o git restore (arquivos). Para trocar de branch use git switch nome, para descartar alterações não commitadas em um arquivo use git restore arquivo, e deixe o checkout para scripts antigos e hábitos já consolidados.
Por que o git checkout tem dois papéis
Historicamente, o git checkout faz duas operações fundamentalmente diferentes. Com o nome de uma branch, ele move o HEAD e atualiza a pasta de trabalho. Com o caminho de um arquivo, ele pega a versão do arquivo do índice ou de um commit e sobrescreve suas alterações sem avisar. O mesmo comando ora troca de branch com segurança, ora joga fora de forma irreversível um trabalho não salvo.
Por isso, no Git 2.23 surgiram dois comandos separados: git switch para branches e git restore para arquivos. O checkout não foi removido e continua funcionando perfeitamente, mas o código novo, a documentação e as próprias dicas do Git usam switch e restore. Se você está aprendendo agora, comece por eles; mesmo assim, é preciso conhecer o checkout — ele aparece em tutoriais, scripts e entrevistas de emprego.
Equivalência entre os comandos
| Tarefa | git checkout | Comando novo |
|---|---|---|
| Trocar de branch | git checkout main | git switch main |
| Criar uma branch e mudar para ela | git checkout -b feature | git switch -c feature |
| Criar ou redefinir uma branch | git checkout -B feature | git switch -C feature |
| Voltar para a branch anterior | git checkout - | git switch - |
| Ir para um commit (detached HEAD) | git checkout 3f2a1c9 | git switch --detach 3f2a1c9 |
| Descartar alterações em um arquivo | git checkout -- app.js | git restore app.js |
| Tirar um arquivo do índice | git reset HEAD app.js | git restore --staged app.js |
| Pegar um arquivo de outra branch ou commit | git checkout main -- app.js | git restore --source=main --staged --worktree app.js |
| Descartar todas as alterações da pasta | git checkout -- . | git restore . |
Repare no -- nos comandos de checkout. É um separador que significa "daqui em diante vêm caminhos". Ele evita ambiguidade quando um arquivo e uma branch têm o mesmo nome. No restore esse problema não existe, porque o comando trabalha apenas com arquivos.
git checkout para branches
git checkout feature/login # trocar de branch
git checkout -b feature/login # criar a partir do commit atual e trocar
git checkout -b hotfix origin/main # criar a partir de uma branch remota
git checkout -t origin/feature/x # branch local que rastreia a remota
Se a branch local não existe, mas há uma branch com esse nome no servidor, git checkout feature/x (assim como git switch feature/x) cria a branch local sozinho e configura o rastreamento. Antes disso é preciso um git fetch, senão o Git não sabe da nova branch remota.
A troca de branch não perde alterações não commitadas: elas são levadas para a outra branch, desde que não entrem em conflito com ela. Se houver conflito, o Git recusa e sugere fazer commit ou guardar as alterações com git stash. A flag -f (--force) troca de branch descartando as alterações locais — essa já é uma operação perigosa.
git switch: só branches
O switch repete a parte do checkout ligada a branches, mas com regras mais rígidas. A principal diferença: ele não vai para um commit ou tag sem um --detach explícito. O comando git switch v1.0 dá erro em vez de entrar silenciosamente em detached HEAD, então fica mais difícil acabar "fora de uma branch" por acidente.
git switch main
git switch -c feature/cart
git switch -c feature/cart origin/main
git switch --detach v1.0
git switch - # branch anterior
git switch -m main # levar as alterações com merge de três vias
git restore: o botão de desfazer para arquivos
O restore devolve os arquivos a um estado salvo e não mexe no histórico de commits. Para usá-lo com confiança, lembre-se das três áreas do Git: a pasta de trabalho (o que você vê no editor), o índice (o que foi preparado com git add) e os commits.
Como desfazer alterações em um arquivo antes do git add
git restore app.js # voltar à versão do índice
git restore src/ # todos os arquivos da pasta
git restore . # todos os arquivos alterados do projeto
Sem flags, o restore restaura a pasta de trabalho a partir do índice. Se o arquivo não foi adicionado ao índice depois do último commit, isso equivale à versão do último commit. As alterações somem sem deixar rastro, não vão para a lixeira, então dê uma olhada no git diff antes de rodar git restore ..
Como tirar um arquivo do índice depois do git add
git restore --staged app.js
O arquivo deixa de estar preparado para o commit, mas suas alterações nele continuam. Esta é a forma mais segura do restore: nada se perde. É exatamente este comando que o git status sugere na seção "Changes to be committed".
Como desfazer tudo: no índice e no arquivo
git restore --staged --worktree app.js
# forma curta
git restore -SW app.js
Como recuperar um arquivo de outro commit ou branch
git restore --source=HEAD~2 app.js # versão de dois commits atrás
git restore --source=main config.yml # versão da branch main
git restore --source=3f2a1c9 -- docs/ # uma pasta inteira de um commit
Por padrão, com --source só a pasta de trabalho é alterada. Adicione --staged se quiser já preparar a alteração para o commit. A forma antiga git checkout main -- app.js sempre altera tanto o índice quanto a pasta de trabalho.
Como recuperar um arquivo apagado
git restore deleted.txt # apagado, mas ainda não commitado
git restore --source=HEAD~1 deleted.txt # a exclusão já foi commitada
Se você não sabe em qual commit o arquivo foi apagado, encontre-o com git log --oneline -- deleted.txt. O commit mais recente da lista é aquele em que o arquivo foi removido; a restauração deve ser feita a partir do pai dele: git restore --source=<hash>~1 deleted.txt.
restore, reset e revert: não confunda
Os três comandos "desfazem", mas em profundidades diferentes:
- restore — trabalha com arquivos na pasta de trabalho e no índice, sem alterar o histórico. Seguro para o time.
- reset — move o ponteiro da branch para trás, reescrevendo o histórico.
--softmantém as alterações no índice,--mixed(padrão) na pasta de trabalho,--hardas apaga. Perigoso para commits já enviados em branches compartilhadas. - revert — cria um novo commit que inverte o commit indicado. O histórico não é reescrito, por isso é o jeito certo de desfazer um commit que já está no servidor.
Regra simples: alterações ainda não commitadas — restore; commit só local — reset; commit que os colegas já têm — revert.
Detached HEAD depois do checkout
Ao executar git checkout 3f2a1c9 ou git checkout v1.0, você verá um longo aviso "You are in 'detached HEAD' state". Agora o HEAD aponta para um commit, e não para uma branch. Isso é prático para olhar uma versão antiga ou rodar os testes nela.
Dá para fazer commits nesse estado, mas os novos commits não vão para nenhuma branch. Se você alterou algo e quer guardar:
git switch -c fix-for-v1
Se estava só olhando, volte: git switch - ou git switch main. Se saiu sem criar a branch, os commits ainda estão acessíveis pelo git reflog: encontre o hash e execute git branch rescue <hash>.
Erros comuns
error: pathspec 'feature' did not match any file(s) known to git
O Git não encontrou nem branch nem arquivo com esse nome. Normalmente a branch existe só no servidor e o fetch não foi feito. Rode git fetch e tente de novo. Confira também a grafia: nomes de branches diferenciam maiúsculas de minúsculas.
Descartei alterações sem querer com checkout -- ou restore
Alterações não commitadas que não estavam no índice não ficam guardadas no Git, e não há como recuperá-las com ferramentas do Git. Resta o histórico local do editor ou da IDE. Já se o arquivo tinha sido adicionado com git add, o conteúdo dele está no banco de objetos como objeto "solto" e pode ser encontrado com git fsck --lost-found.
Arquivo e branch com o mesmo nome
git checkout test, quando existem uma branch test e uma pasta test, mostra um aviso de ambiguidade. Use git switch test para a branch e git restore test (ou git checkout -- test) para os arquivos.
Cenários do dia a dia
Algumas situações que aparecem o tempo todo e o comando certo para cada uma:
- Começou a editar um arquivo e percebeu que tomou o caminho errado —
git restore arquivo. - Adicionou ao índice um arquivo a mais antes do commit —
git restore --staged arquivo. - Precisa mudar de tarefa às pressas no meio do trabalho —
git stash, depoisgit switch branch; ao voltar,git switch -egit stash pop. - Quer pegar um único arquivo de uma branch vizinha sem fazer merge da branch inteira —
git restore --source=feature/x --staged --worktree caminho. - Precisa verificar se o bug existia numa versão anterior —
git switch --detach v1.0, teste e depoisgit switch -. - Quer desfazer só parte das alterações de um arquivo —
git restore -p arquivo: o Git mostra cada trecho e pergunta se deve descartá-lo.
O modo interativo -p (--patch) é especialmente útil: ele existe tanto no checkout quanto no restore e permite jogar fora a saída de depuração mantendo as alterações úteis no mesmo arquivo.
Como conferir o resultado antes de desfazer
O restore e o checkout com caminhos descartam alterações sem pedir confirmação, então vale a pena ver antes o que exatamente será perdido. git diff mostra as alterações na pasta de trabalho em relação ao índice, git diff --staged o que está preparado para o commit, git diff main -- app.js em que o arquivo difere da versão em outra branch. Na dúvida, guarde o estado atual com git stash: de lá as alterações sempre podem ser recuperadas, ao contrário do restore.
Resumo
O git checkout junta troca de branch e restauração de arquivos, e é justamente isso que o torna perigoso. Para branches use git switch, para arquivos git restore: um comando muda só a posição do HEAD, o outro só o conteúdo dos arquivos. Branches, restore, reset e revert, com bons e maus cenários, são trabalhados na prática no curso de Git.
Perguntas frequentes
O git checkout está obsoleto?
Não, ele não foi declarado obsoleto e continuará funcionando. Só que, no trabalho do dia a dia, recomenda-se usar o git switch e o git restore, que são mais específicos e seguros.
Desde qual versão do Git existem o switch e o restore?
Os dois comandos surgiram no Git 2.23 (2019). Você pode conferir sua versão com git --version.
Dá para desfazer um git restore?
Se foi restaurada a pasta de trabalho, o Git não guardou as alterações descartadas e não há como desfazer. O git restore --staged é seguro: as alterações continuam no arquivo, basta adicioná-las de novo com git add.
Como mudar para a branch de um colega?
Execute git fetch e depois git switch nome-da-branch: o Git cria uma branch local vinculada a origin/nome-da-branch.
Qual a diferença entre git checkout . e git reset --hard?
git checkout . (ou git restore .) devolve os arquivos alterados à versão do índice, sem mexer no índice nem no histórico. git reset --hard redefine o índice e a pasta de trabalho para um commit e, se você passar um commit como argumento, ainda move a branch.
Este tema é abordado em profundidade, com prática, no curso “Git do zero ao desenvolvedor confiante”.
- Branches: A Realidade Paralela do Seu Código
- Desfazendo Erros: restore, reset, revert — O Caminho Correto e os Perigos