Git stash: guardando trabalho inacabado

1. O que é o Git stash e por que usá-lo?

O Git stash é uma funcionalidade que permite salvar temporariamente alterações não commitadas em uma pilha (stack) isolada, liberando o diretório de trabalho para outras operações. Pense nele como um "rascunho" que você pode guardar e recuperar depois, sem precisar criar commits incompletos.

Cenários típicos de uso:

  • Você está trabalhando em uma feature e precisa trocar de branch urgentemente para corrigir um bug.
  • Precisa puxar atualizações do repositório remoto (git pull), mas há mudanças locais que causariam conflitos.
  • Recebeu uma solicitação para revisar um PR e seu diretório de trabalho está sujo.

Diferença entre stash e commit:

Stash Commit
Rascunho temporário local Registro permanente no histórico
Não aparece no log do repositório Fica visível para toda a equipe
Pode ser descartado facilmente Requer git revert ou git reset para remover
Ideal para trabalho em andamento Ideal para trabalho concluído

2. Comandos básicos: git stash push e git stash pop

Salvando alterações:

O comando mais simples é git stash, que salva todas as mudanças em arquivos rastreados:

# Suponha que você modificou o arquivo app.js
$ git status
On branch feature-x
Changes not staged for commit:
  modified:   app.js

$ git stash
Saved working directory and index state WIP on feature-x: 1a2b3c4 Commit message

$ git status
On branch feature-x
nothing to commit, working tree clean

Para adicionar uma mensagem descritiva:

$ git stash push -m "Ajustes parciais no formulário de login"

Recuperando a stash mais recente:

$ git stash pop
On branch feature-x
Changes not staged for commit:
  modified:   app.js
Dropped refs/stash@{0} (a1b2c3d4e5f6...)

O git stash pop aplica a stash mais recente e a remove da pilha. Se quiser manter a stash para uso futuro, use git stash apply.

Comportamento com arquivos staged e unstaged:

Por padrão, o stash salva tanto arquivos staged quanto unstaged. Arquivos não rastreados (untracked) não são salvos a menos que você use a flag -u.

3. Gerenciando múltiplas stashes

Listando stashes:

$ git stash list
stash@{0}: On feature-x: Ajustes parciais no formulário de login
stash@{1}: On main: Correção temporária no CSS
stash@{2}: On feature-y: Experimentos com API

Aplicando uma stash específica:

$ git stash apply stash@{1}

Removendo stashes:

# Remove uma stash específica
$ git stash drop stash@{1}

# Remove todas as stashes (cuidado!)
$ git stash clear

4. Opções avançadas do stash

Salvando apenas arquivos rastreados (mantendo staged):

$ git stash --keep-index

Isso salva as mudanças não staged, mas mantém os arquivos staged prontos para commit. Útil quando você quer commitar apenas parte do trabalho.

Salvando arquivos não rastreados:

$ git stash --include-untracked
# ou a forma abreviada
$ git stash -u

Salvando tudo, inclusive arquivos ignorados (.gitignore):

$ git stash --all

Atenção: --all inclui arquivos que normalmente seriam ignorados, como node_modules/. Use com moderação.

5. Criando um branch a partir de uma stash

Às vezes, ao tentar aplicar uma stash em um branch diferente, ocorrem conflitos. A solução elegante é criar um novo branch a partir da stash:

$ git stash branch nova-feature stash@{0}
Switched to a new branch 'nova-feature'
On branch nova-feature
Changes not staged for commit:
  modified:   app.js
Dropped refs/stash@{0} (a1b2c3d4e5f6...)

Vantagens:

  • O branch é criado exatamente no commit onde a stash foi originada.
  • Conflitos são resolvidos de forma organizada, como em um merge normal.
  • A stash é automaticamente removida após a criação do branch.

6. Stash parcial com git stash --patch

O stash interativo permite selecionar partes específicas de arquivos:

$ git stash --patch
diff --git a/app.js b/app.js
index abc123..def456 100644
--- a/app.js
+++ b/app.js
@@ -10,7 +10,7 @@
 function calculateTotal(items) {
-  return items.reduce((sum, item) => sum + item.price, 0);
+  return items.reduce((sum, item) => sum + item.price * 1.1, 0); // Adiciona imposto
 }

 function formatDate(date) {
+  // Nova função de formatação (experimental)
+  return date.toLocaleDateString('pt-BR');
 }

Stage this hunk [y,n,q,a,d,s,e,?]?

Opções de navegação:

Tecla Ação
y Incluir este trecho na stash
n Pular este trecho
s Dividir o trecho em partes menores
e Editar manualmente o trecho
q Sair do modo interativo
? Ajuda com todas as opções

Caso de uso prático:

Você está trabalhando em duas correções no mesmo arquivo. Uma correção está pronta para commit, a outra é experimental. Use --patch para guardar apenas a experimental na stash e commitar a correção finalizada.

7. Boas práticas e armadilhas comuns

Sempre nomeie suas stashes:

# Ruim
$ git stash

# Bom
$ git stash push -m "WIP: refatorando módulo de autenticação"

Cuidado com git stash pop em branches diferentes:

# Você está no branch main e aplica uma stash criada no branch feature-x
$ git stash pop
# Pode causar conflitos inesperados

Sempre verifique em qual branch você está antes de aplicar uma stash.

Stash não substitui commits:

# Perigoso: manter trabalho importante apenas em stashes por dias
$ git stash push -m "Feature quase pronta"
# ... dias depois ...
$ git stash drop  # Trabalho perdido!

Risco de perda com git stash drop acidental:

Se você remover uma stash sem querer, há uma chance de recuperação com git fsck, mas é um processo complexo. Para trabalho importante, faça commits temporários:

$ git commit -m "WIP: salvando progresso"
# Depois, use git reset para desfazer se necessário

Resumo de boas práticas:

  1. Use stashes para trabalho temporário (horas, não dias).
  2. Sempre nomeie suas stashes com -m.
  3. Prefira git stash apply em vez de pop quando não tiver certeza.
  4. Para trabalho complexo, considere criar um branch temporário.
  5. Revise periodicamente sua lista de stashes com git stash list.

O Git stash é uma ferramenta poderosa para gerenciar interrupções no fluxo de trabalho, mas não deve substituir commits regulares. Use-o com sabedoria para manter seu repositório organizado e seu trabalho seguro.

Referências