Armazenando apenas alterações não organizadas no Git


229

Eu gostaria de fazer o seguinte fluxo de trabalho:

  1. Adicione alterações ao palco.
  2. Esconda todas as outras alterações que não foram testadas.
  3. Faça algumas coisas com as coisas em fase (por exemplo, compilar, executar testes etc.)
  4. Aplique o esconderijo.

Existe uma maneira de executar a etapa 2?

Exemplo

 echo "123" > foo
 git add foo # Assumes this is a git directory
 echo "456" >> foo
 git stash
 cat foo # Should yield 123

Por que não confirmar suas alterações depois de prepará-las?
Shizzmo 4/10/11

3
IIRC --keepindex faz exatamente isso
veja

4
Porque se, digamos, a compilação falhar, não quero confirmar isso. Sei que posso excluir a confirmação, mas gostaria de fazer isso sem confirmação, se possível.
Unapiedra

Sehe, obrigado. Eu posso confirmar isso funciona. Puxa, olhei o manual em linux.die.net/man/1/git-stash, que está desatualizado. man git stashé muito melhor.
Unapiedra

é --keep-index, fwiw.
jaf0

Respostas:


288

git stash savetem uma opção --keep-indexque faz exatamente o que você precisa.

Então corra git stash save --keep-index.


9
Verdade. Eu continuo usando savecom git stash. Talvez seja o programador em mim insistindo em honrar a simetria com apply / pop. :)
vhallac

104
Nota: isso ainda esconde todas as suas alterações; a única diferença em relação ao regular git stash saveé que ele também deixa as alterações já realizadas na sua cópia de trabalho. No fluxo de trabalho acima, isso funcionaria bem, pois você está aplicando o stash em cima de uma cópia local que já possui metade das alterações do stash (que o git é inteligente o suficiente para ignorar). Mas se você editar o código antes de aplicar novamente o stash, poderá ver conflitos de mesclagem ao aplicar. Para sua informação.
Peterflynn 04/03

2
@ytpete Isso já me incomodou tantas vezes. Eu realmente gostaria que houvesse uma maneira de o git esconder apenas as coisas que você não está guardando ... Eu costumo cometer coisas e depois fazer um esconderijo completo, sabendo que posso git commit --ammendse houver problemas no que eu cometi.
Rjmunro

1
--amend(em vez de --ammend)
Rhubbarb

19
Esta solução não funciona para mim devido aos problemas descritos por peterflynn. Não é uma boa resposta para a pergunta, pois ainda esconde as alterações realizadas. Alguém tem uma solução melhor?
user643011

43

Isso pode ser feito em 3 etapas: salve as alterações faseadas, esconda todo o resto, restaure o índice com as mudanças faseadas. O que é basicamente:

git commit -m 'Save index'
git stash push -u -m 'Unstaged changes and untracked files'
git reset --soft HEAD^

Isso fará exatamente o que você deseja.


3
Nota: -utambém esconde arquivos não rastreados.
ma11hew28

Essa abordagem duplica essencialmente o que git stash save --keep-indexfaz com muito mais trabalho. Não vejo nenhuma vantagem.
Inigo

1
@vas Não, a abordagem não duplica isso. Veja o comentário de peterflynn na resposta aceita.
Alexander Klauer

28
git stash save --keep-index

Além disso, Re:

Por que não confirmar suas alterações depois de prepará-las? - Canela

R: Como você deve sempre verificar o código testado :) Isso significa que você precisa executar os testes apenas com as alterações que está prestes a confirmar

Tudo isso além do fato de que, claro, como um programador experiente, você tem o desejo inato de teste e análise apenas aquelas mudanças - única parte brincadeira


14

Com git version 2.7.4você pode fazer:

git stash save --patch

O gitirá pedir-lhe para adicionar ou não as alterações no esconderijo.
E você então responde youn

Você pode restaurar o diretório de trabalho, sempre fazendo isso:

git stash pop

ou, se você deseja manter as alterações salvas no stash:

git stash apply

Isso é incrível. É um pouco trabalhoso, mas pelo menos você pode pular e adicionar arquivos inteiros.
Dustin Oprea

5

Estendendo respostas anteriores, às vezes tenho um conjunto complexo de alterações em etapas, mas desejo confirmar uma alteração separada primeiro. Por exemplo, eu posso ter detectado um bug ou código incorreto que gostaria de corrigir antes das alterações em etapas. Um caminho possível a seguir é o seguinte:

primeiro esconda tudo, mas deixe as alterações em etapas intactas

$ git stash save --keep-index [--include-untracked]

agora esconda as mudanças faseadas separadamente também

$ git stash save

faça alterações para correção; e teste; comprometa-os:

$ git add [--interactive] [--patch]

$ git commit -m "conserta ..."

agora restaure as alterações preparadas anteriormente:

$ git stash pop

resolva quaisquer conflitos e observe que, se houver conflitos, o git terá aplicado, mas não eliminado, a entrada principal do stash.

(... Em seguida, confirme as alterações em etapas, restaure o estoque de todas as outras alterações e continue ...)


4

Para adicionar os arquivos não marcados (não adicionados à confirmação) ao stash, execute o seguinte comando:

git stash -k

Em seguida, você pode confirmar os arquivos temporários. Depois disso, você pode recuperar os últimos arquivos escondidos usando o comando:

git stash pop

4

Armazenar apenas a árvore de trabalho (alterações sem etapas) no Git é mais difícil do que deveria ser. A resposta aceita oculta as alterações não organizadas, mas também oculta as alterações organizadas (e as deixa organizadas também), o que raramente é o que você deseja.

Esse alias funciona bem:

stash-working = "!f() { \
  git commit --quiet -m \"temp for stash-working\" && \
  git stash push \"$@\" && \
  git reset --quiet --soft HEAD~1; }; f"

Ele confirma temporariamente as alterações em etapas, cria uma ocultação das alterações restantes (e permite que argumentos adicionais como --include-untrackede --messagesejam passados ​​como argumentos de alias) e redefine a confirmação temporária para recuperar as alterações em etapas.

É semelhante à resposta de @Simon Knapp , mas com algumas pequenas diferenças - ele usa --quietas ações temporárias executadas e aceita qualquer número de parâmetros para o stash push, em vez de codificar o código -me adiciona --softà final redefinir para que o índice permaneça como iniciado.

Para o problema oposto de esconder apenas as mudanças faseadas (alias stash-index), veja esta resposta .


2

Outra dica, relacionada à pergunta:

Quando você efetivamente esconde suas alterações não organizadas usando

$ git stash save --keep-index

convém enviar uma mensagem para o stash, para que, quando você fizer um git stash list, seja mais óbvio o que você escondeu antes, especialmente se você seguir essa operação de stash por mais salvamentos. Por exemplo

$ git stash save --keep-index "alterações ainda não preparadas"

(embora na verdade contenha todas as alterações, conforme observado em outras respostas).

Por exemplo, o acima pode ser seguido imediatamente por:

$ git stash save "mudanças faseadas para o recurso X"

Cuidado, porém, que você não pode usar

$ git stash apply "stash @ {1}" ### ✘ não faz exatamente o que você deseja

para restaurar apenas as alterações não faseadas.


2

O Git não possui um comando que oculte apenas as alterações não-estágios.

O Git, no entanto, permite especificar quais arquivos você deseja ocultar.

git stash push --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

Se você deseja ocultar apenas alterações específicas nesses arquivos, adicione a --patchopção

git stash push --patch --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

A --include-untrackedopção permite que você esconda arquivos não rastreados.

git stash push --include-untracked --message 'Untracked files' -- app/controllers/widgets_controller.rb test/controllers/widgets_controller_test.rb

Execute git help stash(ou man git-stash) para obter mais informações.

Nota: Se as suas alterações não organizadas são bastante desoganizadas, a resposta de @ alesguzik é provavelmente mais fácil.


0

A forma moderna desse comando é git stash push [--] [<pathspec>...], desde o Git 2.16+ ( git stash saveestá obsoleto )

Você pode combinar isso com um formulário curinga, por exemplo:

git stash push --all --keep-index ':(glob)**/*.testextension' 

Mas isso não funciona bem com o Git para Windows, até o Git 2.22 (Q2 2019), veja a edição 2037 , considerando git stashque foi reimplementado em C (em vez de um shell script)

Veja commit 7db9302 (11 Mar 2019) por Thomas Gummerer ( tgummerer) .
Consulte commit 1366c78 , commit 7b556aa ( 07/03/2019 ) por Johannes Schindelin ( dscho) .
(Incorporado por Junio ​​C Hamano - gitster- in commit 0ba1ba4 , 22 de abr de 2019)

built-in stash: manipule :(glob)pathspecs novamente

Ao passar uma lista de pathspecs para, digamos, git addprecisamos ter cuidado ao usar a forma original, não a forma analisada dos pathspecs.

Isso faz a diferença, por exemplo, ao chamar

git stash -- ':(glob)**/*.txt'

onde a forma original inclui o :(glob)prefixo, enquanto a forma analisada não.

No entanto, no built-in git stash, passamos o formulário analisado (ou seja, incorreto) egit add falharíamos com a mensagem de erro:

fatal: pathspec '**/*.txt' did not match any files

no estágio em que git stashas alterações são removidas da árvore de trabalho, mesmo que refs/stashtenham sido atualizadas com êxito.


0

Eu uso um alias, que aceita uma string para ser usada como uma mensagem na entrada stash.

mystash = "!f() { git commit -m hold && git stash push -m \"$1\" && git reset HEAD^; }; f"

Qual:

  • confirma tudo no índice,
  • esconde o que é alterado na árvore de trabalho (poderia, é claro, adicionar -uou -a),
  • redefine o último commit de volta para a tentativa de trabalho (pode ser usado --softpara mantê-lo no índice).
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.