Quando devo usar o git pull --rebase?

806

Conheço algumas pessoas que usam git pull --rebasepor padrão e outras que insistem em nunca usá-lo. Acredito entender a diferença entre mesclar e rebasear, mas estou tentando colocar isso no contexto de git pull. Trata-se de não querer ver muitas mensagens de confirmação de mesclagem ou existem outros problemas?

Jason Baker
fonte
1
Fonte para pessoas que aconselham contra o git pull --rebase? Rebase ou git rebase são atividades separadas do git pull --rebase!
Przemo_li 17/04/19

Respostas:

584

Você deve usar git pull --rebasequando

  • suas alterações não merecem uma ramificação separada

De fato - por que não então? É mais claro e não impõe um agrupamento lógico em seus commits.


Ok, acho que precisa de alguns esclarecimentos. No Git, como você provavelmente sabe, você é incentivado a ramificar e mesclar. Sua ramificação local, na qual você puxa alterações, e ramificação remota são, na verdade, ramificações diferentes, e git pullé sobre como mesclá-las. É razoável, já que você pressiona com muita frequência e geralmente acumula várias alterações antes que elas constituam um recurso completo.

No entanto, às vezes - por qualquer motivo - você acha que seria realmente melhor se esses dois - remotos e locais - fossem um ramo. Como no SVN. É aqui que git pull --rebaseentra em jogo. Você não mescla mais - na verdade, confirma em cima da ramificação remota . É disso que se trata.

Se é perigoso ou não, é se você está tratando a filial local e remota como algo inseparável. Às vezes, é razoável (quando suas alterações são pequenas ou se você está no início de um desenvolvimento robusto, quando mudanças importantes são trazidas por pequenas confirmações). Às vezes não é (quando você normalmente cria outro ramo, mas você fica com preguiça de fazer isso). Mas essa é uma pergunta diferente.

P Shved
fonte
17
Eu acho que é útil quando você trabalha no mesmo ramo, mas pode mudar sua estação de trabalho. Tendo a comprometer e enviar minhas alterações de uma estação de trabalho, retiro novamente a outra e continuo trabalhando no mesmo ramo.
Pablo Pazos
11
É uma prática recomendada o fato de configurar o Git para se refazer automaticamente após puxar com git config --global pull.rebase preserve (preserve preserve, além de habilitar a refazer a refração, para tentar preservar mesclagens se você tiver feito localmente).
Colin D Bennett
2
Eu discordo que você deve usar pull --rebase apenas ao trabalhar em um ramo. Você deve usá-lo o tempo todo, a menos que seja impossível por causa de alguma outra circunstância.
Tomáš Fejfar
@P Shved ... "No entanto, às vezes - por qualquer motivo - você acha que seria realmente melhor se esses dois - remotos e locais - fossem um único ramo" ... isso pode ser feito? que no ambiente local, posso ter minha ramificação e um espelho de ramificação remota como origem / mestre. Você pode fornecer informações aqui?
Mandroid
736

Eu gostaria de fornecer uma perspectiva diferente sobre o que "git pull --rebase" realmente significa, porque às vezes parece se perder.

Se você já usou o Subversion (ou CVS), pode estar acostumado ao comportamento de "svn update". Se você tiver alterações a confirmar e a confirmação falhar porque as alterações foram feitas a montante, você "svn update". O Subversion prossegue mesclando alterações upstream com as suas, resultando potencialmente em conflitos.

O que o Subversion acabou de fazer foi essencialmente "pull --rebase". O ato de reformular suas alterações locais para que ele seja relativo à versão mais recente é a parte "rebasing" dela. Se você fez "svn diff" antes da falha na tentativa de confirmação e comparou o diff resultante com a saída de "svn diff" posteriormente, a diferença entre os dois diffs é o que a operação de rebasagem fez.

A principal diferença entre o Git e o Subversion, neste caso, é que no Subversion, "suas" alterações existem apenas como alterações não confirmadas na sua cópia de trabalho, enquanto no Git você tem confirmações reais localmente. Em outras palavras, no Git você bifurcou a história; sua história e a história a montante divergiram, mas você tem um ancestral em comum.

Na minha opinião, no caso normal de ter sua filial local simplesmente refletindo a filial upstream e desenvolvendo-a continuamente, a coisa certa a fazer é sempre "--rebase", porque é isso que você realmente está semanticamente fazendo . Você e outras pessoas estão cortando a história linear pretendida de um ramo. O fato de alguém ter empurrado um pouco antes da tentativa de empurrar é irrelevante e parece contraproducente para cada acidente de tempo resultar em mesclagens na história.

Se você realmente sente a necessidade de algo ser um ramo por qualquer motivo, essa é uma preocupação diferente na minha opinião. Mas, a menos que você tenha um desejo específico e ativo de representar suas alterações na forma de mesclagem, o comportamento padrão deve, na minha opinião, ser "git pull --rebase".

Por favor, considere outras pessoas que precisam observar e entender a história do seu projeto. Deseja que o histórico esteja repleto de centenas de fusões por todo o lado ou apenas algumas poucas fusões que representam fusões reais de esforços de desenvolvimento divergentes intencionais?

codificar
fonte
18
@ MarceloCantos Para ser claro, não estou dizendo que o git (a ferramenta) deve usar o rebase como padrão. Isso seria perigoso, já que uma recuperação rebate essencialmente a história. Estou dizendo que, em termos de fluxo de trabalho, quando você não pretende ramificar e está apenas hackeando algum ramo em que outras pessoas também estão trabalhando, "git pull --rebase" deve ser o comportamento padrão do usuário.
scode
1
Você está dizendo que não deveria git config --global branch.autosetupmerge always?
Marcelo Cantos
9
@MarceloCantos Não, eu não;) Pessoalmente, eu deixaria a configuração automática como padrão de true (se eu estiver mesclando a quarta e a quarta entre ramos diferentes do local <-> remoto, eu gostaria que fosse explícito). Estou apenas dizendo que, como humano, sempre uso o "git pull --rebase" como parte do meu fluxo de trabalho normal "grab latest in master branch", porque nunca quero criar um commit de mesclagem, a menos que esteja explicitamente ramificando.
scode
9
+1 @ código. Depois de muitas horas dolorosas de lidar com a pergunta rebase / mesclagem, finalmente , aqui está uma resposta que o esclarece.
AgileYogi 16/10/12
10
Essa resposta é apenas uma tentativa de adaptar os usuários de sistemas de controle de versão não distribuídos ao Git, em vez de dar a eles a chance de entender adequadamente os benefícios de ter ramificações apropriadas.
Alexey Zimarev
211

Talvez a melhor maneira de explicar isso seja com um exemplo:

  1. Alice cria a ramificação de tópicos A e trabalha nela
  2. Bob cria um ramo de tópico não relacionado B e trabalha nele
  3. Alice faz git checkout master && git pull. O mestre já está atualizado.
  4. Bob faz git checkout master && git pull. O mestre já está atualizado.
  5. Alice faz git merge topic-branch-A
  6. Bob faz git merge topic-branch-B
  7. Bob faz git push origin masterantes de Alice
  8. Alice aceita git push origin master, o que é rejeitado porque não é uma mesclagem de avanço rápido.
  9. Alice examina o log de origem / mestre e vê que o commit não está relacionado ao dela.
  10. Alice faz git pull --rebase origin master
  11. O commit de mesclagem de Alice é desenrolado, o commit de Bob é puxado e o commit de Alice é aplicado após o commit de Bob.
  12. Alice faz isso git push origin master, e todo mundo fica feliz por não precisar ler um commit inútil de mesclagem quando olhar para os logs no futuro.

Observe que o ramo específico que está sendo mesclado é irrelevante para o exemplo. O mestre neste exemplo poderia ser tão facilmente um ramo de lançamento ou um ramo de desenvolvimento. O ponto principal é que Alice e Bob estão mesclando simultaneamente suas ramificações locais em uma ramificação remota compartilhada.

Cody Poll
fonte
2
Agradável. Costumo ser explícito e git co master && git pull; git checkout topic-branch-A; git rebase master; git checkout master; git merge topic-branch-A; git push origin masterrepetir se o esforço de alguém para dominar aconteceu antes do meu. Embora eu possa ver as vantagens sucintas em sua receita.
HankCa
Boa explicação @Cody Poll
Rajanikanta Pradhan
148

Eu acho que você deve usar git pull --rebaseao colaborar com outras pessoas no mesmo ramo. Você está no seu trabalho → confirmar → trabalhar → ciclo de confirmação, e quando você decide enviar seu trabalho, seu envio é rejeitado, porque houve um trabalho paralelo no mesmo ramo. Neste ponto, eu sempre faço a pull --rebase. Não uso squash (para nivelar confirmações), mas me refiz para evitar as confirmações de mesclagem extras.

À medida que seu conhecimento sobre o Git aumenta, você se vê muito mais histórico do que com qualquer outro sistema de controle de versão que eu usei. Se você tem uma tonelada de pequenas confirmações de mesclagem, é fácil perder o foco da imagem maior que está acontecendo em sua história.

Na verdade, essa é a única vez que refizo (*) e o restante do meu fluxo de trabalho é baseado em mesclagem. Mas, enquanto seus confirmadores mais frequentes fizerem isso, a história parecerá muito melhor no final.

(*) Enquanto ministrava um curso Git, um aluno me prendeu por isso, pois também defendia o rebasamento de ramos de recursos em determinadas circunstâncias. E ele havia lido esta resposta;) Esse rebote também é possível, mas sempre deve estar de acordo com um sistema pré-combinado / acordado e, como tal, não deve "sempre" ser aplicado. E naquela época eu normalmente também não pull --rebase, o que é a questão;)

krosenvold
fonte
2
certamente um pode escrever um script para ocultar os commits mesclagem do log
Hasen
3
Fusões podem conter diffs também, o que significa que não é inteiramente trivial
krosenvold
9
@hasen j Sim, mas o conteúdo dessas fusões podem importa
krosenvold
Esta resposta é vaga e opinativa em comparação com a resposta escolhida: o que você quer dizer com "mesmo ramo" exatamente? Existem alguns pontos positivos, que não estão na resposta escolhida.
Iwein
1
A imprecisão em torno de "ramificação" é bastante intencional, pois existem muitas maneiras de usar refs; "linha de trabalho" é apenas uma opção.
precisa saber é o seguinte
49

Eu não acho que haja uma razão para não usar pull --rebase- eu adicionei código ao Git especificamente para permitir que meu git pullcomando sempre se rebase contra confirmações upstream.

Ao analisar a história, nunca é interessante saber quando o cara / garota que trabalha no recurso parou para sincronizar. Pode ser útil para o cara / moça enquanto ele estiver fazendo isso, mas reflogé para isso. É só adicionar ruído para todos os outros.

Dustin
fonte
2
"Ao analisar a história, nunca é interessante saber quando o cara que trabalhava no recurso parou para sincronizar". / mas isso não significa que essas confirmações intermediárias provavelmente são compilações interrompidas?
eglasius
10
Sim, e eles também não são um "estado inteiro". É por isso que não os queremos. Eu quero saber o que ele queria, não como ele chegou lá.
Dustin
4
Se pull --rebasesempre deve ser usado, por que não o pullfaz por padrão?
Straya #
2
Receio que você precise formar sua própria opinião. Tenho várias coisas .gitconfigpara fazer com que algumas das opções façam a coisa certa. Eu acho que o git rebase faz a coisa errada por padrão, assim como o git tag, etc ... Se você discorda, não precisa justificar sua opinião.
Dustin
8
Isso parece um bom conselho se você sair do "upstream", digamos master, e se o ramo no qual você entrar ainda não for público (ainda). Se você puxa, por outro lado, de um ramo de recurso para o masterlocal é mais o contrário: nunca há um motivo para usá-lo --rebase, certo? Essa pode ser a razão pela qual não é padrão. Descobri que Rebases é como as mudanças devem passar do topo da hierarquia para baixo e mesclas são como elas fluem de volta para cima. derekgourlay.com/blog/git-when-to-merge-vs-when-to-rebase
jolvi
38

Apenas lembra-te:

  • pull = buscar + mesclar
  • pull --rebase = busca + rebase

Portanto, escolha a maneira como você deseja lidar com seu ramo.

É melhor você saber a diferença entre mesclar e refazer :)

leohxj
fonte
9

Eu acho que tudo se resume a uma preferência pessoal.

Deseja ocultar seus erros bobos antes de fazer alterações? Se assim git pull --rebasefor , é perfeito. Ele permite que você comprima mais tarde seus commits para alguns (ou um) commit. Se você tiver mesclagens no seu histórico (sem push), não é tão fácil fazer um git rebaseposterior.

Eu, pessoalmente, não me importo de publicar todos os meus erros bobos, por isso tenho a tendência de mesclar em vez de me refazer.

hasen
fonte
8
Nota para quem está visualizando esta pergunta: esta resposta é completamente irrelevante para a pergunta "quando devo usar o git pull --rebase?"
therealklanni
3
@therealklanni Eu editei a resposta para ficar mais claro como é relevante para a pergunta (espero sem destruir a intenção).
Paŭlo Ebermann 30/01
Compartilhar um registro de trabalho sujo e não estruturado não é um esforço honesto, é apenas preguiça. Você está desperdiçando o tempo das pessoas, fazendo-as persegui-lo através da sua toca de desenvolvimento e depuração; dê a eles o resultado, não as divagações.
krystah
8

git pull --rebasepode ocultar uma reescrita do histórico de um colaborador git push --force. Eu recomendo usar git pull --rebase apenas se você souber que esqueceu de enviar seus commit antes que alguém faça o mesmo.

Se você não cometeu nada, mas seu espaço de trabalho não está limpo, pouco git stashantes de fazê-lo git pull. Dessa forma, você não reescreverá silenciosamente seu histórico (o que pode excluir silenciosamente parte do seu trabalho).

Habax
fonte