Git pull resulta em mensagens estranhas "Merge branch" no log de commit

110

Estou trabalhando com outro desenvolvedor em um projeto e estamos usando o Github como nosso repositório remoto. Estou em um Mac usando git 1.7.7.3, ele está no Windows usando git 1.7.6.

É isso que está acontecendo

  1. Um de nós (vamos chamá-lo de desenvolvedor A, mas não importa qual) envia um conjunto de commits para o GitHub.
  2. O outro (desenvolvedor B) faz alguns commits locais.
  3. B faz a git pull.
  4. B faz a git push.
  5. Olhando para o log de histórico de commits , vejo Merge branch 'master' de github.com:foo/bar

O log de commits fica cheio de mensagens "Merge branch" ao longo do tempo e também mostra o desenvolvedor B como as alterações de commit que o desenvolvedor A fez. A única maneira que encontramos de evitar esse problema foi fazer um git pull --rebasena etapa 3, mas não sei quais efeitos colaterais o rebaseing apresentará. Esta é minha primeira vez trabalhando em um repositório git multi-desenvolvedor, então isso é apenas um comportamento normal? Alguma ideia de como resolver esse problema?

mshafrir
fonte
2
Você pode ver o registro sem git log --no-merges
mesclar

Respostas:

88

O commit que você está vendo está perfeitamente bem. Um pullé executado com eficácia git fetche, git mergegeralmente, ocorre uma fusão quando você executa git pull.

A alternativa de usar rebase em vez de mesclar é possível, mas geralmente você deve evitá-la. Rebasing permite que você mantenha um histórico linear, mas também remove qualquer informação sobre a ramificação que ocorreu originalmente. Isso também fará com que o histórico do branch atual seja reescrito, recriando todos os commits que não estão contidos no branch de destino (no seu caso, o remoto). Como os commits recriados são commits diferentes , isso pode causar muita confusão ao desenvolver junto com outros, especialmente quando as pessoas já deram check-out de partes desses commits antes de serem reescritos (por exemplo, com branches de recursos). Portanto, como regra geral, você nunca deve reescrever nenhum commit que já foi enviado.

Os commits que você vê existem para combinar dois (ou mais) branches. É perfeitamente normal ter um commit que não faz nada mais do que mesclar vários branches. Na verdade, fica muito claro quando você tem um commit de mesclagem que combina ramos ao olhar para o histórico. Em comparação com o rebase, a mesclagem também permite que você veja efetivamente o histórico original conforme foi desenvolvido, incluindo as ramificações reais que coexistiram.

Então, encurtando a história: Sim, ter commits de mesclagem é perfeitamente normal e você não deve se preocupar com eles.

cutucar
fonte
2
Muito boa resposta. Eu mesmo tentei o estilo rebase, já que era recomendado em algumas diretrizes de contribuição de projetos de código aberto, e isso me causou problemas. Um novo membro da equipe também teve o mesmo. Acho que a opção de rebase não é para equipes que trabalham juntas o dia todo, mas é correta para projetos que têm contribuidores principais e outros que apenas enviam patches. Esses devem buscar o repositório principal e refazer as alterações antes de emitir uma solicitação de pull.
Meligy
2
@sTodorov Se não houver novas alterações, a parte de busca do pull não fará nada, mas a mesclagem ainda está sendo executada. Portanto, se o seu branch local atual não estiver atualizado, ele irá mesclar as novas alterações em seu branch. E se ele não puder fazer uma fusão de avanço rápido (se você tiver commits divergentes), ele criará um commit de fusão.
cutucar
28
Essa resposta faz parecer que usar o rebase como o OP descreveu é perigoso, mas não é. Rebase no passo 3 não reescreve toda a história. Apenas os commits locais que não foram enviados são reescritos ao serem reaplicados no topo do novo HEAD (o último commit enviado para aquele branch). Isso evita os commits de mesclagem externos e não tem outros efeitos colaterais.
bob esponja,
1
@bobesponja Todos os commits que não estão no branch remoto puxado são reescritos. Isso pode incluir commits publicados de outros branches, por exemplo, branches de recursos, que outros já podem ter acessado antes. Como tal, sim, rebase sem pensar sobre o que você rebase é um tanto perigoso.
cutucar
1
@bobesponja Sim, se você estiver publicando seu branch de recurso antecipadamente (porque outros trabalham nele, ou simplesmente como backup), você não deve rebaseá-lo porque outros já podem tê-lo obtido. Rebasing então - como você mesmo diz - vai contra as diretrizes de rebasing que afirmei em minha resposta. No entanto, se você não publicar seus commits, então o rebasing é bom se você quiser e não se importar com o histórico linear. Mas depende de como você trabalha, então a resposta geral é evitá-lo, a menos que seja realmente seguro. Btw. Revisei minha resposta, então, se o problema for resolvido, agradeceria se você removesse seu voto negativo.
cutucar
48

Essa resposta foi revisada, pois meu entendimento, diagramas e conclusões estavam incorretos.


git pullcausa commits de mesclagem porque git está mesclando. Isso pode ser alterado configurando seus branches para usar rebase em vez de merge. Usar rebase em vez de mesclar em um pull fornece um histórico mais linear para o repositório compartilhado. Por outro lado, os commits de mesclagem mostram os esforços de desenvolvimento paralelo no branch.

Por exemplo, duas pessoas estão trabalhando na mesma filial. A filial começa como:

...->C1

A primeira pessoa termina o trabalho e segue para o galho:

...->C1->C2

A segunda pessoa termina o trabalho e quer empurrar, mas não pode porque precisa atualizar. O repositório local para a segunda pessoa se parece com:

...->C1->C3

Se o pull estiver configurado para mesclar, o repositório da segunda pessoa será semelhante a.

...->C1->C3->M1
      \      /
       ->C2->

Onde M1 é um commit de mesclagem. Este novo histórico de branch será enviado ao repositório. Se, em vez disso, o pull for definido para realocar o repositório local terá a seguinte aparência:

...->C1->C2->C3

Não há commit de mesclagem. A história se tornou mais linear.

Ambas as opções refletem a história do ramo. git permite que você escolha o histórico de sua preferência.

De fato, existem lugares onde o rebase pode causar um problema com branches remotos. Este não é um desses casos. Preferimos usar rebase, pois simplifica um histórico de branch já complicado e também mostra uma versão do histórico em relação ao repositório compartilhado.

Você pode definir branch.autosetuprebase = sempre para que o git estabeleça automaticamente seus branches remotos como rebase em vez de master.

git config --global branch.autosetuprebase always

Essa configuração faz com que o git crie automaticamente uma definição de configuração para cada branch remoto:

branch.<branchname>.rebase=true

Você mesmo pode definir isso para suas filiais remotas que já estão configuradas.

git config branch.<branchname>.rebase true

Gostaria de agradecer a @LaurensHolst por questionar e buscar minhas declarações anteriores. Eu certamente aprendi mais sobre como o git funciona com pull e merge commits.

Para obter mais informações sobre commits de mesclagem, você pode ler Contribuindo para um projeto no ProGit-Book . A seção Private Small Team mostra os commits de mesclagem.

Bill Door
fonte
7
“Usar rebase em vez de mesclar em um pull fornece o histórico correto para o repositório compartilhado. O uso de mesclagem fornece um histórico falso. ” - Qual é o fundamento lógico por trás dessa afirmação bastante ousada? Não há como um histórico com mesclagens ser 'falso histórico'. É uma descrição precisa da ordem em que as coisas aconteceram. O que você está fazendo ao rebasear é, na verdade, alterar a história, para criar uma versão um pouco mais linear dela. Você sacrifica a precisão pela estética. Talvez algo que você prefira fazer, mas de forma alguma mais verdadeiro.
Laurens Holst
2
Usar rebase em vez de mesclar não sacrifica a precisão pela estética. Usamos --no-ff para mesclagens, portanto a estética não é um requisito. A precisão é um desejo. Rebase fornece essa precisão.
Bill Door
2
Como a história rebaseificada é mais precisa? Você não esclarece isso, e não vejo como seria.
Laurens Holst
1
A história é um reflexo da época em que os commits ocorreram no repo compartilhado . Um dia 1, o repo compartilhado viu o commit C2. No dia 2, o repo compartilhado vê o commit C3. Se C3 viesse antes de C2, o reflexo do tempo não estaria correto. C3 não veio antes de C2. Tudo que o rebase faz é reorganizar os commits no repositório local para refletir adequadamente o histórico mostrado pelo repositório compartilhado.
Bill Door
6
Suas perguntas me levaram a revisar meu entendimento sobre os commits de mesclagem. Meu diagrama está incorreto. Estou revisando a discussão. Minhas conclusões também estão incorretas. O histórico de rebase e mesclagem está igualmente correto. Você pode fazer sua própria escolha.
Bill Door
11

Você pode fazer:

git pull --rebase

No entanto, isso sempre colocará suas alterações em cima das de seus colaboradores. Mas você não receberá nenhuma mensagem de mesclagem poluente.

gostoso
fonte
9

Na verdade, há uma resposta muito mais simples para isso. Apenas faça com que o desenvolvedor B faça um pull ANTES de fazer seu commit. Isso impedirá os commits de mesclagem, já que eles são causados ​​pelo histórico que você criou em seu repositório local a partir de seu commit local tentando mesclar com o histórico dos commits no repo remoto. Se você receber uma mensagem dizendo algo parecido com 'as alterações serão sobrescritas' ao fazer um pull, significa apenas que vocês tocaram no mesmo arquivo, então faça:

git stash
git pull
git stash pop

então você pode resolver quaisquer conflitos de mesclagem, se houver.

Lucas
fonte
Mais irritantes e ansiosos são exatamente conflitos de fusão. Prefiro evitar
Verde
1
@Green Se você está preocupado com conflitos de mesclagem, mesmo o git pull não é diferente.
Zoso
Exceto aquela vez em que você esquece stashantes de você pull. Ugh git exige que eu esteja no topo do meu jogo o tempo todo.
linuxNoob
Precisa git pull --rebaseintegrar as mudanças remotas antes das locais, de qualquer maneira.
vonbrand
7

Fazer um git pull irá inserir as mensagens "Merge branch", é exatamente o que faz. Ao fazer um git pull, você fundiu o branch remoto em seu branch local.

Quando você faz um git pull e há conflitos, o log do git mostrará as atualizações dos arquivos em conflito como provenientes do usuário que resolveu os conflitos. Presumo que seja porque a pessoa que corrige o conflito compromete novamente o arquivo.

Pelo que eu sei, é assim que o git funciona, e não há uma maneira de contornar isso.

Rebasing vai acabar com o histórico do git, então você não será capaz de ver quando as fusões ocorreram.

kclair
fonte