git stash arquiva (ou faz o stash) de alterações que você fez na cópia de trabalho durante um determinado período, para que você possa trabalhar em outra coisa, depois voltar e fazer a reaplicação mais tarde. O stashing é útil quando você precisa alternar com rapidez o contexto e trabalhar em outra coisa, mas está no meio da alteração de código e não está pronto para fazer commit.

Fazer stash no trabalho

O comando git stash salva as alterações sem commit (tanto as preparadas quanto as não preparadas) para uso posterior e as reverte da cópia de trabalho. Por exemplo:

$ git status
On branch master
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

$ git stash
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage

$ git status
On branch master
nothing to commit, working tree clean

Nesse ponto, você está livre para fazer alterações, criar novos commits, alternar ramificações e executar quaisquer outras operações do Git. Quando estiver terminado, volte e aplique mais uma vez seu stash quando estiver pronto.

Observe que o stash é local no seu repositório Git; stashes não são transferidos para o servidor quando você envia por push.

Reaplicar as alterações com stash

Você pode então aplicar mais uma vez as alterações que passaram por stashing antes com o git stash pop:

$ git status
On branch master
nothing to commit, working tree clean
$ git stash pop
On branch master
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Dropped refs/stash@{0} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

Executar o popping no stash remove as alterações no stash e as reaplica na cópia de trabalho.

Como outra opção, você pode aplicar mais uma vez as alterações à cópia de trabalho e manter no stash com o git stash apply:

$ git stash apply
On branch master
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

É um recurso útil caso você queira aplicar as mesmas alterações de stashing a mais da ramificação.

Agora que você aprendeu o básico de stashing, existe uma ressalva com o git stash que você precisa estar ciente: por padrão, o Git não vai fazer o stash de alterações feitas a arquivos ignorados ou não rastreados.

Fazer stash em arquivos ignorados ou não rastreados

Por padrão, executar o git stash vai fazer o stash de:

  • alterações que foram adicionadas ao seu índice (alterações preparadas)
  • alterações feitas a arquivos que estão no momento rastreados pelo Git (alterações despreparadas)

No entanto, o stashing não vai ser realizado em:

  • novos arquivos na cópia de trabalho que ainda não foram preparados
  • arquivos que foram ignorados

Ou seja, se a gente adiciona um terceiro arquivo ao exemplo acima, mas não o prepara (por exemplo, sem executar o git add), o git stash não vai executar o stashing nele.

$ script.js

$ git status
On branch master
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Untracked files:

    script.js

$ git stash
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage

$ git status
On branch master
Untracked files:

    script.js

Adicionar a opção -u (ou --include-untracked) vai dizer ao git stash para também fazer o stashing dos arquivos não rastreados:

$ git status
On branch master
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Untracked files:

    script.js

$ git stash -u
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage

$ git status
On branch master
nothing to commit, working tree clean

Você também pode incluir alterações para arquivos ignorados, passando a opção -a (ou --all) ao executar o git stash.

Git Stash opções

Gerenciar múltiplos stashes

Você não está limitado a um único stash. Você pode executar o git stash mais da vez para criar múltiplos stashes e, então, usar o git stash list para fazer uma visualização. Por padrão, os stashes são identificados apenas como "WIP" — work in progress (trabalho em progresso) — no topo da ramificação e commit dos quais você criou o stash. Depois de certo tempo, pode ser difícil lembrar o conteúdo de cada stash:

$ git stash list
stash@{0}: WIP on master: 5002d47 our new homepage
stash@{1}: WIP on master: 5002d47 our new homepage
stash@{2}: WIP on master: 5002d47 our new homepage

Para contextualizar melhor, é uma boa prática anotar uma descrição para seus stashes, usando o git stash save "mensagem":

$ git stash save "add style to our site"
Saved working directory and index state On master: add style to our site
HEAD is now at 5002d47 our new homepage

$ git stash list
stash@{0}: On master: add style to our site
stash@{1}: WIP on master: 5002d47 our new homepage
stash@{2}: WIP on master: 5002d47 our new homepage

Por padrão, git stash pop vai reaplicar o stash criado mais há pouco tempo: stash@{0}

Você pode escolher qual stash aplicar mais uma vez, passando seu identificador como o último argumento, por exemplo:

$ git stash pop stash@{2}

Visualizar comparações de stash

Você pode visualizar um resumo do stash com o git stash show:

$ git stash show
 index.html | 1 +
 style.css | 3 +++
 2 files changed, 4 insertions(+)

Ou passar a opção -p (ou --patch) para visualizar a comparação completa do stash:

$ git stash show -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+  text-decoration: blink;
+}
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>

Stashes parciais

Também é possível escolher fazer o stashing no único arquivo, uma coleção de arquivos, ou mudanças individuais de dentro de arquivos. Se você passar a opção -p (ou --patch) ao git stash, ele vai percorrer cada "fragmento" alterado na cópia de trabalho e perguntar se você quer fazer o stashing:

$ git stash -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+  text-decoration: blink;
+}
Stash this hunk [y,n,q,a,d,/,e,?]? y
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>
Stash this hunk [y,n,q,a,d,/,e,?]? n
Git Stash -p

Você pode digitar ? para obter uma lista completa de comandos de fragmento. Os mais úteis são:

Comando Descrição
/ pesquisar um fragmento por regex
? ajuda
n não fazer stashing neste fragmento
q sair (o stashing vai ser feito em quaisquer fragmentos que já foram selecionados)
s dividir este fragmento em fragmentos menores
y fazer stashing neste fragmento

Não existe nenhum comando "abortar" explícito, no entanto, digitar CTRL-C(SIGINT) vai abortar o processo de stashing.

Criar uma ramificação do stash

Se as alterações na ramificação divergirem das alterações no stash, você vai poder entrar em conflito ao fazer o popping ou aplicar o stash. Outra opção é usar o git stash branch para criar uma nova ramificação para aplicar alterações com stashing:

$ git stash branch add-stylesheet stash@{1}
Switched to a new branch 'add-stylesheet'
On branch add-stylesheet
Changes to be committed:

    new file:   style.css

Changes not staged for commit:

    modified:   index.html

Dropped refs/stash@{1} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

Isto verifica uma nova ramificação com base no commit do qual você criou o stash e depois mostra as alterações com stashing nesta ramificação.

Limpar seu stash

Caso você decida que não precisa mais do stash em particular, você pode fazer a exclusão com o git stash drop:

$ git stash drop stash@{1}
Dropped stash@{1} (17e2697fd8251df6163117cb3d58c1f62a5e7cdb)

Ou você pode excluir todos os seus stashes com:

$ git stash clear

Como o git stash funciona

Se o seu intuito era apenas o de aprender como usar o git stash, você pode parar de ler aqui. No entanto, caso esteja curioso em saber como o Git (e o git stash) funciona de fato, continue lendo!

Os stashes são codificados no repositório como objetos com commit. A ref especial em .git/refs/stash aponta para seu stash mais recente criado e stashes criados antes são referenciados pelo reflog da ref do stash. É por este motivo que você referencia os stashes com stash@{n}: você está na verdade referenciando o número de entrada do reflog para a ref do stash. Como um stash é apenas um commit, você pode examinar com o git log:

$ git log --oneline --graph stash@{0}
*-.   953ddde WIP on master: 5002d47 our new homepage
|\ \ 
| | * 24b35a1 untracked files on master: 5002d47 our new homepage
| * 7023dd4 index on master: 5002d47 our new homepage
|/ 
* 5002d47 our new homepage

Dependendo em que você fez stash, uma única operação de git stash vai criar duas ou três novos commits. Os commits no diagrama acima são:

  • stash@{0}, um novo commit para armazenar os arquivos rastreados que estavam na cópia de trabalho quando você executou o git stash
  • o primeiro pai do stash@{0}, o commit preexistente que estava no HEAD quando você executou o git stash
  • o segundo pai do stash@{0}, um novo commit representando o índice quando você executou o git stash
  • o terceiro pai do stash@{0}, um novo commit representando arquivos não rastreados que estavam na cópia de trabalho quando você executou o git stash. Este terceiro pai só é criado se:
    • a cópia de trabalho de fato continha arquivos não rastreados; e
    • você especificou a opção --include-untracked ou --all ao chamar o git stash.

Como o git stash codifica a árvore de trabalho e índice como commits:

  • Antes de fazer o stashing, sua árvore de trabalho pode conter alterações a arquivos rastreados, arquivos não rastreados e arquivos ignorados. Algumas destas alterações podem também estar preparadas no índice.

    Antes de fazer stash
  • Chamar o git stash vai codificar quaisquer alterações a arquivos rastreados como dois novos commits no DAG: uma para arquivos despreparados e outra para alterações preparadas no índice. A ref especial refs/stash é atualizada para direcionar a elas.

    Git stash
  • O uso da opção --include-untracked também vai codificar quaisquer alterações para arquivos não rastreados como um commit adicional.

    Git stash --include-untracked
  • O uso da opção --all inclui as alterações a quaisquer arquivos ignorados em conjunto com as alterações a arquivos não rastreados no mesmo commit.

    Git Stash --all

Ao executar o git stash pop, as alterações dos commits acima são usadas para atualizar a cópia de trabalho e índice, bem como o reflog do stash é embaralhado para remover o commit mostrado. Observe que os commits mostrados não são excluídos no mesmo instante, mas se tornam candidatos para futura coleta de lixo.

Pronto(a) para aprender Git?

Tente este tutorial interativo.

Comece agora mesmo