O “git pull” pode esconder e exibir automaticamente as alterações pendentes?


122

Eu sei como resolver isso:

user@host$ git pull
Updating 9386059..6e3ffde
error: Your local changes to the following files would be overwritten by merge:
    foo.bar
Please, commit your changes or stash them before you can merge.
Aborting

Mas não tem como deixar git pullfazer stashe popdançar para mim?

Se este comando tiver um nome diferente, está tudo bem.

Criar um alias de shell para git stash; git pull; git stash popé uma solução, mas procuro uma solução melhor.


que tal um alias git ?
Яois

20
Executar git stash; git pull; git stash popprogramaticamente é perigoso, porque se não houver nada para armazenar, não git stashhaverá operação , mas git stash popexibirá o último esconderijo (se houver), que quase certamente não é o que você deseja. O usuário torek tem uma ótima postagem sobre isso no Stack Overflow, mas não consigo encontrar ...
jub0bs


1
@guettli Eu não estava insinuando que sua pergunta é uma duplicata, estava apenas respondendo ao comentário do Jubobs.
VonC

2
Como um passo adiante, a operação deve ter sucesso apenas se o stash puder ser aplicado de forma limpa após o puxão. Se houver conflitos, toda a operação falhará atomicamente para que a árvore não seja alterada. Isso é o que eu gostaria de fazer: puxar para baixo as alterações com meus locais mesclados ou falhar com um erro e me deixar decidir manualmente o que fazer a seguir. Esse tipo de 'transação' git é possível?
Ed Avis

Respostas:


185

Para Git 2.6+ (lançado em 28 de setembro de 2015)

o git config configuração que seria de interesse é:

rebase.autoStash

(com Git 2.27, Q2 2020, agora você também tem merge.autostash, veja abaixo)

Quando definido como verdadeiro, cria automaticamente um stash temporário antes do início da operação e o aplica após o término da operação.
Isso significa que você pode executar o rebase em uma árvore de trabalho suja.

No entanto, use com cuidado: o aplicativo stash final após um rebase bem-sucedido pode resultar em conflitos não triviais. O padrão é falso.

combine isso com:

pull.rebase

Quando verdadeiro, rebase branches sobre o branch obtido, ao invés de mesclar o branch padrão do remoto padrão quando "git pull" é executado.

git config pull.rebase true
git config rebase.autoStash true

Isso seria o suficiente para um simples git pulltrabalhar mesmo em uma árvore suja.
Nenhum alias necessário nesse caso.


Consulte commit 53c76dc (04 de julho de 2015) de Kevin Daudt ( Ikke) .
(Incorporado por Junio ​​C Hamano - gitster- no commit e69b408 , 17 de agosto de 2015)

pull: permitir árvore suja quando rebase.autostashhabilitado

rebase aprendeu a esconder mudanças quando encontra uma árvore de trabalho sujo, mas git pull --rebasenão o faz.

Somente verifique se a árvore de trabalho está suja quando rebase.autostashnão está habilitada.


Nota: se você quiser puxar sem autostash (mesmo que rebase.autoStash trueesteja definido), você tem desde o git 2.9 (junho de 2016):

 pull --rebase --no-autostash

Consulte commit 450dd1d , commit 1662297 , commit 44a59ff , commit 5c82bcd , commit 6ddc97c , commit eff960b , commit efa195d (02 abr 2016) e commit f66398e , commit c48d73b (21 mar 2016) por Mehul Jain ( mehul2029) .
(Incorporado por Junio ​​C Hamano - gitster- no commit 7c137bb , 13 de abril de 2016)

O compromisso f66398e em particular inclui:

pull --rebase: adicionar --[no-]autostashbandeira

Se a rebase.autoStashvariável de configuração for definida, não há como substituí-la por " git pull --rebase" na linha de comando.

Ensina " git pull --rebase" o --[no-]autostashsinalizador de linha de comando que substitui o valor atual de rebase.autoStash, se definido. Como " git rebase" entende a --[no-]autostashopção, é apenas uma questão de passar a opção para " git rebase" subjacente quando " git pull --rebase" for chamado.


Aviso: antes do Git 2.14 (terceiro trimestre de 2017), " git pull --rebase --autostash" não armazenava automaticamente quando o histórico local avançava rapidamente para o upstream.

Veja o commit f15e7cf (01 de junho de 2017) de Tyler Brazier ( tylerbrazier) .
(Incorporado por Junio ​​C Hamano - gitster- no commit 35898ea , 05 de junho de 2017)

pull: ff --rebase --autostashfunciona em repositório sujo

Quando git pull --rebase --autostashem um repositório sujo resultou em um avanço rápido, nada estava sendo autostashed e o pull falhou.
Isso ocorreu devido a um atalho para evitar a execução de rebase quando podemos avançar, mas o autostash é ignorado nesse caminho de código.


Atualização: Mariusz Pawelski faz nos comentários uma pergunta interessante:

Então, todo mundo está escrevendo sobre autostashquando você faz rebase (ou pull --rebase).

Mas ninguém está falando sobre autostashing quando você faz pull normal com mesclagens .
Portanto, não existe uma mudança automática para isso? Ou estou perdendo alguma coisa? Eu prefiro fazer, git pull --rebasemas o OP perguntou sobre git pull " padrão "

Responda:

O tópico original que discute esse recurso de autostash, foi implementado originalmente para git pull(mesclar) e git pull --rebase.

Mas ... Junio ​​C Hamano (mantenedor do Git) observou que:

Se pull-mergefosse algo que induziria o "aborrecimento" que desencadeou este tópico, por definição, a mudança local se sobrepõe à mesclagem, e esse "stash pop" interno tocará os caminhos tocados pela mesclagem e provavelmente não resultará em "Eliminado "mas deixamos outros conflitos a serem resolvidos.

Suspeito que a pull.autostashconfiguração não seja uma boa adição, pois incentiva um fluxo de trabalho ruim e doloroso.
Em casos simples, pode não doer, mas quando as mudanças locais são complexas, seria mais difícil do que não ter, e a configuração rouba o incentivo para escolher.

A equação é um pouco diferente para "pull-rebase", já que "rebase" insiste que você comece a partir de uma árvore de trabalho limpa, então o aborrecimento de "baixar e parar" parece maior. Tenho a suspeita de que afrouxar isso pode ser uma solução mais produtiva para o problema real.

Portanto, em relação a um pull-merge clássico, é melhor:

incentive o usuário a pensar sobre a natureza do WIP que ele tem na árvore de trabalho antes de executar " git pull" .
É uma besta muito complexa que pode interferir no que os outros estão fazendo, ou é uma mudança trivial que ele pode esconder e devolvê-la?

Se for o primeiro, ele ficará muito melhor fazendo " checkout -b", continue trabalhando até que a mudança local fique um pouco melhor e "se comprometa", antes de puxar para o branch original.

Se for o último, é melhor ele fazer:

  • " git pull",
  • depois de encontrar conflitos, execute
    • git stash,
    • git merge FETCH_HEAD e
    • git stash pop

Dito isso, com o Git 2.27 (Q2 2020), " git pull" aprendeu a avisar quando nenhuma pull.rebaseconfiguração existe, e nem --[no-]rebasenem --ff-onlyé fornecido (o que resultaria em uma fusão).

Consulte o commit d18c950 (10 de março de 2020) de Alex Henrie ( alexhenrie) .
(Fundido por Junio ​​C Hamano - gitster- no commit 1c56d6f , 27 de março de 2020)

pull: avisa se o usuário não disse se deseja realocar ou mesclar

Assinado por: Alex Henrie

Freqüentemente, os usuários novatos do Git esquecem de dizer " pull --rebase" e acabam com uma mesclagem desnecessária do upstream.

O que eles geralmente desejam é " pull --rebase" nos casos mais simples, ou " pull --ff-only" atualizar a cópia das ramificações de integração principais e realocar seu trabalho separadamente.
A pull.rebasevariável de configuração existe para ajudá-los nos casos mais simples, mas não existe nenhum mecanismo para alertar esses usuários sobre isso.

Emita uma mensagem de aviso quando nenhuma --[no-]rebaseopção da linha de comando e nenhuma pull.rebasevariável de configuração for fornecida.
Isso vai incomodar aqueles que nunca querem " pull --rebase", que não tiveram que fazer nada de especial, mas o custo do transtorno é pago apenas uma vez por usuário, o que deve ser um custo razoável para ajudar um número de novos usuários.


Com o Git 2.27 (Q2 2020), " git merge" aprende a --autostashopção " " e a nova merge.autostashconfiguração.

Veja cometer d9f15d3 , cometer f8a1785 , cometer a03b555 , cometer 804fe31 , cometer 12b6e13 , cometer 0dd562e , cometer 0816f1d , cometer 9bb3dea , cometer 4d4bc15 , cometer b309a97 , cometer f213f06 , cometer 86ed00a , cometer facca7f , cometer be1bb60 , cometer efcf6cf , cometer c20de8b , cometer bfa50c2 , commit 3442c3d , commit 5b2f6d9 (07 de abril de 2020), commit 65c425a(04 de abril de 2020), e cometer fd6852c , cometer 805d9ea (21 de março de 2020) por Denton Liu ( Denton-L) .
(Incorporado por Junio ​​C Hamano - gitster- no commit bf10200 , 29 de abril de 2020)

pull: passe --autostash para mesclar

Assinado por: Denton Liu

Antes, --autostashsó trabalhava com git pull --rebase.

No entanto, no último patch, merge aprendeu --autostashtambém, então não há razão para termos mais essa restrição.
Ensine pull para passar --autostashpara mesclar, assim como fez para rebase.

E:

rebase: use apply_autostash()do sequencer.c

Assinado por: Denton Liu

A apply_autostash()função em builtin/rebase.cé semelhante o suficiente à apply_autostash()função emsequencer.c sentido de que são quase intercambiáveis, exceto pelo tipo de argumento que aceitam. Torne a sequencer.cversão externa e use-a no rebase.

A versão rebase foi introduzida em 6defce2b02 ("rebase embutido: --autostashopção de suporte ", 2018-09-04, Git v2.20.0-rc0 - mesclagem listada no lote # 8 ) como parte da conversão de shell para C.
Ele optou por duplicar a função porque, na época, havia outro projeto em andamento convertendo o rebase interativo de shell para C também e eles não queriam entrar em conflito com eles refatorando a sequencer.cversão do apply_autostash().
Uma vez que ambos os esforços são feitos há muito tempo, podemos combiná-los livremente agora.


Em 2.4.2, isso ainda não foi implementado. Talvez algum dia. rebase.autoStashaplica-se apenas ao usar rebase. pull.rebaseaplica-se apenas ao usar pull.
Randal Schwartz

"Isso seria o suficiente para um simples git pull funcionar mesmo em uma árvore suja." Como Randal comentou, isso ainda não é verdade. O pull.c do mestre atual ainda escolhe die_on_unclean_work_tree.
Pradhan de

1
@Pradhan eu concordo. A implementação acabou de entrar no controle esta manhã e deve estar pronta para o git 2.6. Eu editei a resposta para deixar isso claro.
VonC de

Eu confirmei que autostash está funcionando com git 2.5.5.
Joshua Hoblitt

1
Então, todo mundo está escrevendo sobre autostash quando você faz rebase(ou pull --rebase). Mas ninguém está falando sobre autostashing quando você faz o normal pullcom mesclagens. Portanto, não existe uma mudança automática para isso? Ou estou perdendo alguma coisa? Eu prefiro fazer, git pull --rebasemas OP perguntou sobre "padrão"git pull
Mariusz Pawelski

41

Para economizar alguns segundos para os exploradores que se aproximam, aqui está um resumo (graças a @VonC):

git pull --rebase --autostash

6
A questão é: depois de um git config pull.rebase truee git config rebase.autoStash true, tudo o que você precisa é git pull. Apenas git pull. Nenhuma outra opção necessária.
VonC

3
Parece que você precisa de pelo menos Git 2.9 para a --autostashopção. O -c rebase.autoStash=truefunciona em Git 2.6 em diante.
ntc2

15

Como o comentário acima afirmou, definir os dois valores de configuração não funciona atualmente git pull, já que a configuração de autostash se aplica apenas a rebases reais. Esses comandos git fazem o que você deseja:

git fetch
git rebase --autostash FETCH_HEAD

Ou defina-o como um alias:

git config alias.pullr '!git fetch; git rebase --autostash FETCH_HEAD'

Então faça:

git pullr

É claro que esse alias pode ser renomeado conforme desejado.


7

Com Git 2.6+, você pode usar o seguinte:

alias gup='git -c rebase.autoStash=true pull --rebase'

Isso --rebasefaz com que git-pull use em rebasevez de merge, então configurações / opções como--ff-only não se aplicam.

Estou usando um alias para puxar --ff-onlypor padrão ( git pull --ff-only) e posso usar gup(de cima) no caso de uma mesclagem rápida não ser possível ou se houver alterações ocultas.


Qual é a principal diferença entre git pull --ff-onlyegit pull pull --rebase --autostash
alper

0

Como você já mencionou, esta é a maneira de se fazer. Você pode usá-lo como um alias para economizar digitação e usar atalhos ou pode usá-lo em uma única linha (pode ser um apelido também)

git stash && git pull --rebase && git stash pop

Ele fará a mesma coisa que você fez, mas em uma única linha (&&) e se você definir como alias, será ainda mais curto.

As linhas a seguir exibirão as mudanças de entrada / saída antes de você puxar / empurrar

git log ^master origin/master
git log master ^origin/master

8
Essa abordagem não é segura: se não houver nada para armazenar, o primeiro comando não fará nada e, em seguida stash pop, removerá algumas coisas aleatórias de antes.
John Zwinck

Só para ser mais claro: mesmo se git stashnão faz nada stash-lo ainda "retornos" não errorcode para que o && ainda vai continuar com git pulle git stash pope pop um estoque anterior. Então é melhor não usar isso a menos que você tenha certeza de que vai esconder alguma coisa!
MoonLite
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.