Por que o git pull executa uma mesclagem, em vez de uma rebase, por padrão?

71

Considere a seguinte situação:

  • Você tem um clone de um repositório git
  • Você tem algumas confirmações locais (confirmações que ainda não foram enviadas a lugar algum)
  • O repositório remoto possui novas confirmações que você ainda não reconciliou

Então, algo como isto:

Confirmações não imersas

Se você executar git pullcom as configurações padrão, obterá algo como isto:

mesclar commit

Isso ocorre porque o git executou uma mesclagem.

Existe uma alternativa, no entanto. Você pode dizer ao pull para fazer uma nova rebase:

git pull --rebase

e você obterá isso:

rebased

Na minha opinião, a versão rebased tem inúmeras vantagens, principalmente centradas em manter o seu código e o histórico limpos, então estou um pouco impressionado com o fato de o git fazer a mesclagem por padrão. Sim, os hashes dos commits locais serão alterados, mas isso parece um preço pequeno a pagar pelo histórico mais simples que você recebe em troca.

De maneira alguma, estou sugerindo que, de alguma forma, isso é um padrão ruim ou errado. Estou tendo problemas para pensar nos motivos pelos quais a mesclagem pode ser preferida para o padrão. Temos alguma ideia de por que foi escolhido? Existem benefícios que o tornam mais adequado por padrão?

A principal motivação para essa pergunta é que minha empresa está tentando estabelecer alguns padrões de linha de base (espero, mais parecidos com diretrizes) sobre como organizamos e gerenciamos nossos repositórios para facilitar aos desenvolvedores a abordagem de um repositório com o qual não haviam trabalhado antes. Estou interessado em defender que normalmente devemos refazer esse tipo de situação (e provavelmente por recomendar que os desenvolvedores definam sua configuração global para refazer o rebote por padrão), mas se eu fosse contrário a isso, certamente perguntaria por que o rebase não é ' o padrão, se é tão bom. Então, eu estou querendo saber se há algo que estou faltando.

Foi sugerido que esta pergunta é uma duplicata de Por que tantos sites preferem "git rebase" ao "git merge"? ; no entanto, essa pergunta é um pouco o inverso desta. Ele discute os méritos de rebase sobre mesclagem, enquanto essa pergunta pergunta sobre os benefícios da mesclagem sobre rebase. As respostas refletem isso, concentrando-se nos problemas de mesclagem e nos benefícios da rebase.

jpmc26
fonte
6
Possível duplicata de Por que tantos sites preferem "git rebase" ao "git merge"?
Gbjbaanb 11/01
O outro problema é que, se você acidentalmente se comprometer com o mestre, faça um pull que se mesclou, os dois mestres podem estar fora de sincronia, mesmo que a mesclagem pareça normal. É por isso que meu alias de pull inclui --ff-only.
Ixrec
se o sourcetree alterar a visualização do gráfico para exibir rebase / mesclagem diferente, você mudará para mesclagem?
Ewan
11
O @Ewan SourceTree não deve mudar sua visualização gráfica. Representa com precisão o gráfico.
Jpmc26
4
Para eleitores enganados, observe que o conteúdo da resposta que eu aceitei definitivamente não está presente na pergunta que você está reivindicando como duplicada.
jpmc26

Respostas:

56

É difícil saber ao certo por que a mesclagem é o padrão sem ouvir a pessoa que tomou essa decisão.

Aqui está uma teoria ...

O Git não pode presumir que não há problema em - refazer cada puxão. Ouça como isso soa. "Rebase cada puxão." Soa errado se você usar solicitações pull ou similares. Você se recuperaria de uma solicitação pull?

Em uma equipe que não está apenas usando o Git para controle centralizado de fontes ...

  • Você pode puxar a montante e a jusante. Algumas pessoas fazem muito esforço de downstream, de colaboradores, etc.

  • Você pode trabalhar em recursos em estreita colaboração com outros desenvolvedores, retirando deles ou de um ramo de tópico compartilhado e, ainda assim, ocasionalmente atualizado do upstream. Se você sempre se refaz, acaba alterando o histórico compartilhado, sem mencionar divertidos ciclos de conflito.

O Git foi projetado para uma equipe grande e altamente distribuída, na qual todo mundo não puxa nem empurra para um único repositório central. Portanto, o padrão faz sentido.

  • Os desenvolvedores que não sabem quando está tudo bem com a rebase serão mesclados por padrão.
  • Os desenvolvedores podem se refazer quando quiserem.
  • Os colaboradores que fazem muitos puxões e têm muitos puxões obtêm o padrão que melhor lhes convém.

Para evidências de intenção, aqui está um link para um e-mail bem conhecido de Linus Torvalds com suas opiniões sobre quando eles não devem ser refeitos. Dri-devel git pull email

Se você seguir o tópico inteiro, poderá ver que um desenvolvedor está puxando de outro desenvolvedor e Linus está puxando de ambos. Ele deixa sua opinião bem clara. Como ele provavelmente decidiu os padrões do Git, isso pode explicar o porquê.

Agora, muitas pessoas usam o Git de maneira centralizada, onde todos em uma equipe pequena recorrem apenas a um repositório central upstream e passam para o mesmo controle remoto. Esse cenário evita algumas das situações em que uma rebase não é boa, mas geralmente não as elimina.

Sugestão: não faça uma política de alteração do padrão. Sempre que você juntar o Git a um grande grupo de desenvolvedores, alguns deles não entenderão o Git tão profundamente (inclusive eu). Eles irão para o Google, SO, obterão conselhos sobre livros de culinária e depois se perguntarão por que algumas coisas não funcionam, por exemplo, por que git checkout --ours <path>a versão incorreta do arquivo? Você sempre pode revisar seu ambiente local, criar aliases etc. para se adequar ao seu gosto.

Josh
fonte
5
+1 por não alterar o padrão - em vez de lançar seu próprio fluxo de trabalho git, é provavelmente melhor escolher um que exista (por exemplo, qualquer um dos documentados por Atlassian atlassian.com/git/tutorials/comparing-workflows/… )
Rob Church
11
Obrigado pela resposta. A informação sobre puxar a jusante era o que estava faltando. Além disso, curiosamente, o link que você deu incentiva exatamente o que eu gostaria de alcançar: "As pessoas podem (e provavelmente deveriam) refazer suas árvores privadas (seu próprio trabalho)".
Jpmc26
2
@jpmc Ótimo. De fato. Reestruturar árvores privadas pode manter muita distração fora da história compartilhada. Eu faço. É importante esclarecer quando não fazer isso.
joshp
"alguns desenvolvedores não entenderão o Git tão profundamente". Rebase NÃO é um recurso super sofisticado ("profundo", etc.) do Git. Você realmente considera isso difícil de entender? Eu acho que isso deve ser um gatilho para chamar dev incompetente.
Victor Yarema
15

Se você ler a página de manual do git para rebase, ele diz :

Reprovar (ou qualquer outra forma de reescrita) uma ramificação na qual outros se basearam é uma péssima idéia: qualquer pessoa a jusante é forçada a corrigir manualmente seu histórico. Esta seção explica como fazer a correção do ponto de vista do downstream. A solução real, no entanto, seria evitar rebasear o upstream em primeiro lugar.

Eu acho que isso diz o suficiente como uma razão para não usar rebase, e muito menos fazê-lo automaticamente a cada puxão. Algumas pessoas consideram a rebase prejudicial . Talvez nunca devesse ter sido colocado no git, pois tudo o que parece fazer é embelezar a história, algo que não deveria ser necessário em nenhum SCM cuja única tarefa essencial é preservar a história.

Quando você diz "manter ... a história limpa", pensa que está errado. Pode parecer melhor, mas para uma ferramenta projetada para manter o histórico de revisões, é muito mais limpo manter todas as confirmações para que você possa ver o que aconteceu. Limpar a história depois é como polir a pátina, fazendo com que uma antiguidade rica pareça uma reprodução brilhante :-)

gbjbaanb
fonte
3
@Ewan IMHO "não funciona, mas parece bonito" é algo que deve ser reservado exclusivamente para a indústria da moda, não para a TI. O IMHO git deve removê-lo, pois obviamente incentiva muitas pessoas a pensar que o estilo é mais importante que a substância.
gbjbaanb 11/01
12
Eu contestaria sua sugestão de que manter a história limpa é inútil. Não é. Um histórico de repositório é destinado ao consumo humano e, como tal, há muito valor em torná-lo legível. No meu caso de uso específico, pretendemos até que os gerentes de projeto que não sejam desenvolvedores possam ler o histórico. Um histórico limpo só pode ajudar com isso, e pode ajudar um novo desenvolvedor que nunca viu a base de código e precisa se aprofundar e corrigir um bug para entender o que aconteceu em uma área específica do código.
jpmc26
3
O código existe antes de mais nada para ser executado por uma máquina (possivelmente após ser compilado). Aplicando sua filosofia acima, concluiríamos que a legibilidade do código não importa, porque nenhuma legibilidade resolverá a dificuldade de entender o código. Eu nunca sugeri que algo fosse esmagado. Estou apenas dizendo que é difícil seguir um gráfico complexo que diverge em vários caminhos, portanto vale a pena investir um pouco para manter sua história razoavelmente limpa. Observe também que um histórico linear é mais propício para alavancar ferramentas git como culpar e dividir.
Jpmc26
6
Os documentos não dizem "não rebase". Ele diz: "não rebase as mudanças que estão a montante de outras pessoas ". Há um mundo de diferença entre os dois. O próprio Linus aconselha algumas reformulações para organizar a história, como pode ser visto no link da resposta aceita. E como uma ferramenta saberia quais confirmações são irrelevantes (especialmente se as ferramentas tiverem dificuldade em analisar uma história não linear!), E como você saberia com qual confirmação você deseja diferenciar (especialmente sem ser capaz de vasculhar a história!)? Você está tomando uma palavra de cautela sobre uma situação específica a um extremo dogmático.
Jpmc26
4
Você definitivamente não deseja "manter o histórico de revisões" se isso incluir todos os commit que um desenvolvedor já fez. Seguindo essa lógica, também devemos registrar a versão original do código toda vez que a tecla backspace for pressionada. Todo commit deve ser uma mudança mínima e completa que ainda mantenha todo o projeto em estado estável. Se o seu commit original mais tarde for encontrado com bugs, é muito melhor refazer / editar / alterar o commit do que criar outro. No entanto, consulte também mail-archive.com/[email protected]/msg39091.html
Mikko Rantalainen
12

Você está correto, supondo que você tenha apenas um repositório local / alterado. No entanto, considere a existência de um segundo PC local, por exemplo.

Depois que sua cópia local / modificada for enviada para outro lugar, o rebaseamento estragará essas cópias. Claro, você pode forçar o empurrão, mas isso rapidamente se torna complicado. O que acontece se um ou mais deles tiver outro commit completamente novo?

Como você pode ver, é muito situacional, mas a estratégia básica parece (para mim) muito mais prática em casos não especiais / de colaboração.


Uma segunda diferença: a estratégia de mesclagem manterá uma estrutura clara e consistente com o tempo. Após os rebotes, é muito provável que os commit mais antigos sigam mudanças mais recentes, dificultando a compreensão de todo o histórico e seu fluxo.

Mario
fonte
11
"Depois das rebotes, é muito provável que as confirmações mais antigas sigam as alterações mais recentes" - isso acontece também com as mesclagens, e é por isso que você (talvez) precisa do gráfico bonito para entender isso. O horário em que uma confirmação foi feita pode demorar muito antes da mesclagem que a trouxe para essa ramificação.
21716 Steve Joplin
6

O grande motivo provavelmente é que o comportamento padrão deve "apenas funcionar" em repositórios públicos. Renascer a história que outras pessoas já fundiram vai causar-lhes problemas. Sei que você está falando sobre seu repositório particular, mas, de um modo geral, o git não sabe nem se importa com o que é público ou privado; portanto, o padrão escolhido será o padrão para ambos.

Eu uso git pull --rebasebastante em meu repositório particular, mas mesmo lá há uma desvantagem em potencial: a história do meu HEADnão reflete mais a árvore enquanto eu realmente trabalhava nela.

Portanto, para um grande exemplo, suponha que eu sempre execute testes e garanta que eles sejam aprovados antes de realizar uma confirmação. Isso tem menos relevância depois que eu faço um git pull --rebase, porque não é mais verdade que a árvore em cada um dos meus commits passou nos testes. Enquanto as alterações não interfere de forma alguma, e o código eu puxo foi testado, então, presumivelmente, ele iria passar os testes, mas nós não sabemos porque eu nunca tentei. Se a integração contínua for uma parte importante do seu fluxo de trabalho, qualquer tipo de rebase em um repositório que está sendo CI é problemático.

Eu realmente não me importo com isso, mas isso incomoda algumas pessoas: elas preferem que sua história no git reflita o código em que realmente trabalharam (ou talvez no momento em que a publicam, uma versão simplificada da verdade após algum uso) de "correção").

Não sei se esse problema em particular é o motivo pelo qual Linus optou por mesclar, em vez de se refazer por padrão. Pode haver outras desvantagens que não encontrei. Mas, como ele não tem vergonha de expressar sua opinião em código, tenho certeza de que tudo se resume ao que ele considera um fluxo de trabalho adequado para pessoas que não querem pensar muito sobre isso (e especialmente as que trabalham em público em vez disso). do que um repo privado). Evitar linhas paralelas no gráfico bonito, em favor de uma linha reta limpa que não represente o desenvolvimento paralelo como aconteceu, provavelmente não é sua principal prioridade, mesmo que seja sua :-)

Steve Jessop
fonte