Como posso renomear um stash git?

203

Eu tenho um esconderijo com um nome incorreto. Gostaria de corrigir o nome para que seja preciso.

Como posso renomear um stash?

mikemaccana
fonte
5
pop-lo e salvá-lo novamente com um nome diferente?
Bartlomiej Lewandowski
5
Estocar e ocultar novamente nem sempre é uma opção, pois o stash pode ser baseado em um estado desatualizado e resultar em conflitos durante o popping. (O estado desatualizado nem sequer tem de existir em qualquer lugar na história mais.)
Tom

Respostas:

259

Vamos supor que sua lista stash seja assim:

$ git stash list
stash@{0}: WIP on master: Add some very important feature 
stash@{1}: WIP on master: Fix some silly bug

Primeiro, você deve remover a entrada stash que deseja renomear:

$ git stash drop stash@{1}
Dropped stash@{1} (af8fdeee49a03d1b4609f294635e7f0d622e03db)

Agora basta adicioná-lo novamente com nova mensagem usando sha of commit retornado após o drop:

$ git stash store -m "Very descriptive message" af8fdeee49a03d1b4609f294635e7f0d622e03db

E é isso:

$ git stash list
stash@{0}: Very descriptive message
stash@{1}: WIP on master: Add some very important feature

Esta solução requer o git 1.8.4 ou posterior e, sim, também funciona com o diretório de trabalho sujo.

qzb
fonte
3
git show stash@{0}ainda mostra as informações antigas posteriormente. Como consertar isso? (Por favor, note que o esconderijo, em seguida, recebe um SHA diferente.)
Tino
4
É melhor começar com o hash git showe começar git stash store. Então, com git stash listvocê verá o velho e o novo esconderijo. Finalmente, você pode limpar o esconderijo antigo git stash drop.
Hogi 5/07
6
o git stash drop não perderá as alterações?
Shravya Boggarapu
4
@ShravyaBoggarapu, não, o git não remove o commit até que git gcseja executado. Depois de stash dropencontrar facilmente esse commit normalmente inacessível usando o git fsck | grep commitcomando
Qzb 21/07
2
@ ÐerÆndi simplesmente aplicar e salvar é uma opção fácil, mas não funciona quando as alterações não podem ser reaplicadas devido a conflitos. Enquanto isso, soltar e armazenar obras em qualquer circunstância. Testei minha solução mais uma vez - ela funciona muito bem na versão mais recente do git (2.17.0).
Qzb 17/04
62

A menos que você faça isso manualmente ou contribua com uma melhoria no Git, você pode usar um alias:

git config --global alias.stash-rename '!_() { rev=$(git rev-parse $1) && git stash drop $1 || exit 1 ; git diff-index --quiet HEAD; s=$?; [ $s != 0 ] && git stash save "tmp stash from stash-rename"; git stash apply $rev && shift && git stash save "$@" && [ $s != 0 ] && git stash pop stash@{1}; }; _'

Uso: " git stash-rename <stash> [save options] [<message>]"

Com [save options]qualquer opção de git stash save:[-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked] [-a|--all]

Exemplo:

$ git stash list
stash@{0}: On master: Pep8 format
stash@{1}: On master: co other than master with local changes
stash@{2}: On master: tests with deployAtEnd

# Let's say I want to rename the stash@{2} adding an issue reference:
$ git stash-rename stash@{2} NXP-13971-deployAtEnd

$ git stash list
stash@{0}: On master: NXP-13971-deployAtEnd
stash@{1}: On master: Pep8 format
stash@{2}: On master: co other than master with local changes

Isso funcionará mesmo se você tiver alterações locais sem etapas :)

EDIT 2016/02/22

Script simplificado, créditos para qzb , https://stackoverflow.com/a/35549615/515973

git config --global alias.stash-rename '!_() { rev=$(git rev-parse $1) && git stash drop $1 || exit 1 ; git stash store -m "$2" $rev; }; _'

Uso: " git stash-rename <stash> [<message>]"

Julien Carsique
fonte
1
Impressionante! Ainda mais legal se você pudesse fazergit stash-rename 'tests with deployAtEnd' 'NXP-13971-deployAtEnd'
mikemaccana
3
então a resposta é 1) cópia de trabalho limpa, 2) aplique o stash que você deseja renomear, 3) remova-o da lista de stash, 4) crie um novo stash com a mensagem correta.
Gcb
2
Para esclarecer, você está renomeando o último stash e, após essa ação, ele se torna o stash superior?
Onebree
2
Excluo o stash para renomear, salve as alterações atuais, se houver, recrie o stash excluído com o nome desejado, reaplique as alterações atuais, se houver.
Julien Carsique
3
Esta versão verifica se os dois argumentos estão lá, para que não solte seu último esconderijo acidentalmente. Também requer apenas o número do stash, não toda a stash@{0}referência. gist.github.com/jdforsythe/f248bf6c72fc020225cc3e315a32e922 git config --global alias.stash-rename '!_() { if [ -z \"$1\" ] || [ -z \"$2\" ]; then echo \"git stash-rename 0 NewName\" && echo \"\" && git stash list && exit 1; else stash=\"stash@{$1}\"; rev=$(git rev-parse \"${stash}\"); git stash drop \"${stash}\" || exit 1; git stash store -m \"$2\" \"$rev\" || exit 1; git stash list; fi }; _'
jdforsythe
6

É muito simples. Primeiro, desfaça o último estoque com:

git stash pop

Depois disso, você pode salvar o stash com um nome personalizado desta maneira:

git stash save "your explanatory name"

Espero que seja útil para você. :)

Sandra
fonte
O stash renomeado pode não ser o mais recente.
Mikemaccana 28/03/19
Polegares para cima, pois isso é mais direto (SOMENTE) para o stash mais recente.
Kaihua
3

Eu não acho que é possível fazer isso. Houve uma proposta para renomear stash, mas ainda não foi implementada.

Minha ideia geral é:

  1. Implemente um novo git reflog updatecomando que atualize a mensagem associada a uma entrada de reflog específica. Para fazer isso, uma nova update_reflog_ent()função (em reflog.c ) alteraria a mensagem associada à entrada de reflog específica para atualização. Uma update_reflog()função usaria for_each_reflog_ent()com update_reflog_entpara realmente fazer a alteração.

  2. Um git stash renamecomando precisaria apenas chamar git reflog updatecom a referência apropriada e a nova mensagem.

Ou você pode, é claro, abrir o esconderijo e fazer uma git stash save [message]

A1ternat1ve
fonte
3

Para o benefício do leitor, aqui está uma extensão da resposta atualmente aceita e correta .

Se você não apenas deseja corrigir a mensagem stash e também deseja corrigir a mensagem de confirmação da stash, de forma que

git stash list

e

git log --oneline -1 stash

ambos concordam com o que é mostrado, você precisa de um pouco mais. Pode haver uma maneira melhor de fazer isso, mas espero que essa receita aqui seja fácil de entender.

Para poder fazer isso, git commit --amendvocê precisa estar na ponta de uma ramificação. Portanto, a solução é:

git checkout -b scratch stash@{1}
git stash drop stash@{1}
git commit --amend -m "$MESSAGE"
git stash store -m "$MESSAGE" HEAD
git checkout master
git branch -D scratch

Explicado:

  • Crie um novo ramo "scratch" (ainda não existente) a partir do "stash in question" e mude para ele
  • Retire o esconderijo antigo. Isso é seguro, pois ainda temos isso no ramo.
  • Use git commit --amendpara substituir a mensagem de confirmação, alterando o SHA do "stash in question"
  • Armazene o estoque, com base na resposta do qzb
  • Voltar (que assume que você veio de "mestre") e limpeza

Desvantagens:

  • Isso alterna ramificações temporariamente. Portanto, esta receita só pode ser aplicada quando git status --porcelainestiver limpa (leia-se: não gera nada)

  • Ele renumera os stashes, para que o stash alterado se torne stash@{0}

  • Você precisa inserir $MESSAGEduas vezes ou usar alguma variável de ambiente (no exemplo MESSAGE:)

  • Você precisa encontrar um nome de filial não utilizado

Existem maneiras de fazer isso sem alternar ramificações, mas isso está além do escopo desta resposta.

Exemplo

git init scratch
cd scratch
for a in A B C D; do date >$a; git add $a; git commit -m $a; done
for a in X Y; do echo $a > Z; git stash save --all; done
git log --oneline --graph --decorate --all; git stash list

Resultado

*-.   e0e281b (refs/stash) WIP on master: 8bdcc32 D
|\ \  
| | * 4d62f52 untracked files on master: 8bdcc32 D
| * 096f158 index on master: 8bdcc32 D
|/  
* 8bdcc32 (HEAD, master) D
* c84c659 C
* 49bb2da B
* b1852c6 A
stash@{0}: WIP on master: 8bdcc32 D
stash@{1}: WIP on master: 8bdcc32 D

Agora, sem alterar o commit (observe: o SHA a seguir será diferente ao seu lado):

git stash drop stash@{1}
git stash store -m ...changed... 2fbf9007dfdfb95ae269a19e13b8b9ca3e24181c
git log --oneline --graph --decorate --all; git stash list

Resultado

*-.   2fbf900 (refs/stash) WIP on master: 8bdcc32 D
|\ \  
| | * 246dc5c untracked files on master: 8bdcc32 D
| * 80c5ea0 index on master: 8bdcc32 D
|/  
* 8bdcc32 (HEAD, master) D
* c84c659 C
* 49bb2da B
* b1852c6 A
stash@{0}: ...changed...
stash@{1}: WIP on master: 8bdcc32 D

Como você pode ver, stash@{0}ainda é mostrado como 2fbf900 (refs/stash) WIP on master: 8bdcc32 Dem git log. Se você observar atentamente, verá que vários commits alteraram o SHA. Isso ocorre devido à maneira como os stashes são manipulados (os pais são incluídos no SHA e os stashes têm seus stashes como pais).

Conserte isso:

git checkout -b scratch stash
git stash drop
git commit --amend -m ...changed...
git stash store -m ...changed... HEAD
git checkout master
git branch -D scratch
git log --oneline --graph --decorate --all; git stash list

Resultado

*-.   4d55186 (refs/stash) ...changed...
|\ \  
| | * 246dc5c untracked files on master: 8bdcc32 D
| * 80c5ea0 index on master: 8bdcc32 D
|/  
* 8bdcc32 (HEAD, master) D
* c84c659 C
* 49bb2da B
* b1852c6 A
stash@{0}: ...changed...
stash@{1}: WIP on master: 8bdcc32 D

Como você também pode ver, o refs/stashSHA também mudou.

Tino
fonte
Vale mencionar: isso destrói o índice que foi salvo com o stash original, substituindo-o por um novo índice que corresponda ao commit pai do stash original. Se alguém não planeja usar o índice salvo original (ou já correspondeu ao pai do stash original), isso não é um problema.
torek 01/06/19
1

Aqui está uma versão modificada do alias de Julien que permite lidar adequadamente com o On <branch>prefixo geralmente anexado aos nomes escondidos:

git config --global alias.stash-rename '!_() { newmsg="$1" && stash=${2:-"stash@{0}"} && newbranch="$3" && sha=$(git rev-parse "$stash") && olddesc="$(git stash list --format=%gs -1 "$stash")" && newdesc="$(if [[ "$newbranch" = "." ]]; then echo "$newmsg"; else if [[ -n "$newbranch" ]]; then echo "On $newbranch: $newmsg"; else if [[ "$olddesc" =~ ":" ]]; then echo "$(echo "$olddesc" | cut -f1 -d":"): $newmsg"; else echo "$newmsg"; fi; fi; fi)" && git stash drop "$stash" > /dev/null || exit 1; git stash store -m "$newdesc" "$sha" && git stash list; }; _'

Sintaxe:

git stash-rename <new-name> [<stash> [<new-branch-name> | .]]

Exemplo de uso:

repo[master] % touch tmp && git add tmp && git stash save first
Saved working directory and index state On master: first
HEAD is now at bd62064 Initial commit
repo[master] % touch tmp && git add tmp && git stash save second
Saved working directory and index state On master: second
HEAD is now at bd62064 Initial commit
repo[master] % git stash list
stash@{0}: On master: second
stash@{1}: On master: first
repo[master] % git stash-rename renamed
stash@{0}: On master: renamed
stash@{1}: On master: first
repo[master] % git stash-rename also-renamed stash@{1}
stash@{0}: On master: also-renamed
stash@{1}: On master: renamed
repo[master] % git stash-rename branch-changed stash@{0} new-branch
stash@{0}: On new-branch: branch-changed
stash@{1}: On master: renamed
repo[master] % git stash-rename branch-name-persists
stash@{0}: On new-branch: branch-name-persists
stash@{1}: On master: renamed
repo[master] % git stash-rename no-branch stash@{0} .
stash@{0}: no-branch
stash@{1}: On master: renamed
repo[master] % git stash-rename renamed
stash@{0}: renamed
stash@{1}: On master: renamed
repo[master] % git stash-rename readd-branch stash@{0} develop
stash@{0}: On develop: readd-branch
stash@{1}: On master: renamed

A maior parte do comando é para analisar os argumentos e descobrir o que deve ser feito com o nome da ramificação. As gitferramentas utilizadas são as seguintes:

  • git rev-parse <stash> para encontrar o SHA do esconderijo.
  • git stash list --format=%gs -1 <stash>para encontrar o assunto de reflog do esconderijo. Observe que isso é diferente da mensagem de confirmação do stash, que não é alterada por este comando. O assunto do reflog é o que aparece git stash list, e você pode alterar o assunto do reflog sem alterar os hashes dos commits associados aos stashes. No entanto, você sempre pode encontrar a mensagem de confirmação original, portanto, não use git stash-renamepara remover informações confidenciais!
  • git stash drop <stash>para largar a antiga referência ao stash (mas ainda temos o SHA, para que não seja perdido).
  • git stash store -m <new-message> <sha>para salvar uma nova referência ao stash com as mesmas informações de confirmação, mas com um assunto de reflog diferente .
  • git stash listpara listar os stashes após a conclusão da operação. Observe que novos stashes são sempre enviados para o início da lista. Seria necessário re-empurrar todos os stashes antes do stash de interesse para restaurar sua posição original.
Radon Rosborough
fonte
0

Maneira mais simples: pop seu stash com git stash pop e salve-o novamente com git stash save your-name

yoel neuman
fonte
O stash renomeado pode não ser o mais recente.
Mikemaccana 28/03/19