git stash arquiva (ou faz o stash) 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 o commit.

Fazer stash no trabalho

O comando git stash pega as alterações sem commit (tanto as preparadas quanto as não preparadas), as salva 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

Isso é ú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ãovai 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 "message":

$ 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. Em vez disso, você pode 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 dois 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.

    Before stashing
  • 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 para aprender sobre o Git?

Experimente este tutorial interativo.

Comece agora mesmo