Git stash
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.
- Git stash
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 main
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 main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch main
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 main
nothing to commit, working tree clean
$ git stash pop
On branch main
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 main
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 main
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 main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch main
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 main
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 main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch main
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
.
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 main: 5002d47 our new homepage
stash@{1}: WIP on main: 5002d47 our new homepage
stash@{2}: WIP on main: 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 main: add style to our site
HEAD is now at 5002d47 our new homepage
$ git stash list
stash@{0}: On main: add style to our site
stash@{1}: WIP on main: 5002d47 our new homepage
stash@{2}: WIP on main: 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
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 main: 5002d47 our new homepage
|\ \
| | * 24b35a1 untracked files on main: 5002d47 our new homepage
| * 7023dd4 index on main: 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 ogit stash
- o primeiro pai do
stash@{0}
, o commit preexistente que estava no HEAD quando você executou ogit stash
- o segundo pai do
stash@{0}
, um novo commit representando o índice quando você executou ogit 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 ogit 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 ogit 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.
-
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 especialrefs/stash
é atualizada para direcionar a elas. -
O uso da opção
--include-untracked
também vai codificar quaisquer alterações para arquivos não rastreados como um commit adicional. -
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.
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.