Git warning: Pulling without specifying how to reconcile divergent branches is discouraged

Git quer que escolhamos como ele deve lidar com a situação em que nosso branch remoto (por exemplo origin/develop) está fora de sincronia com nosso branch local ( develop).

A partir da versão 2.27.0 do Git a execução do comando git pull exibirá a seguinte mensagem, a menos que a configuração do Git inclua certas configurações.

warning: Pulling without specifying how to reconcile divergent branches is
discouraged. You can squelch this message by running one of the following
commands sometime before your next pull:

  git config pull.rebase false  # merge (the default strategy)
  git config pull.rebase true   # rebase
  git config pull.ff only       # fast-forward only

You can replace "git config" with "git config --global" to set a default
preference for all repositories. You can also pass --rebase, --no-rebase,
or --ff-only on the command line to override the configured default per
invocation.

Explicação curta

Git quer que escolhamos como ele deve lidar com a situação em que nosso branch remoto (por exemplo origin/develop) está fora de sincronia com nosso branch local (develop). Muitas pessoas (inclusive eu) acham que a maneira padrão com que o Git lidava com essa situação era ótima, entretanto, mudar o comportamento padrão é uma melhora significativa. O Git facilitou a modificação do comportamento e adicionou esta tela para lembrá-lo de que você pode querer alterar o padrão.

Correção resumida

O short fix é, queremos mudar o comportamento padrão e podemos fazer isso executando o seguinte na linha de comando.

  git config --global pull.ff only

Isso adicionará uma linha ao arquivo de configuração global do Git para usar a “melhor” abordagem ao usar git pull.

Isso adicionará uma linha ao seu arquivo de configuração Git global para usar a “melhor” abordagem ao usar git pull.

O problema que estamos resolvendo

Ao trabalhar com o Git, você tem sua branch local em seu computador (por exemplo develop) e sua branch remota (por exemplo origin/develop). Seu branch remoto normalmente vive em algum lugar como o GitHub GitHub. Você gostaria de ter os mesmos commits em seu branch local e em seu branch remoto.

develop    origin/develop

cem32k     cem32k
b4d2o1     b4d2o1
abc123     abc123

Outra pessoa adiciona um commit

Quando outra pessoa usa git push para adicionar seu commit em origin/develop (por exemplo zyx911), ficamos fora de sincronia.

develop    origin/develop

           zyx911
cem32k     cem32k
b4d2o1     b4d2o1
abc123     abc123

A boa notícia é que podemos colocar as coisas de volta em sincronia executando git pull. Nesse caso, é óbvio para o Git que, adicionando zyx911 aos nossos commits, estaremos em sincronia. Isso é chamado de fast-forward merge.

O comando que adicionamos acima ( git config --global pull.ff only) define isso como o único tipo de mesclagem que o Git deve fazer, a menos que digamos explicitamente o contrário.

Ambos Adicionam commits

Imagine a situação onde alguém adiciona um commit ao branch remoto (por exemplo, zyx911 é adicionado origin/develop) e ao mesmo tempo adicionamos um commit ao nosso branch local (por exemplo, adicionamos dg34mpa develop).

develop    origin/develop

dg34mp     zyx911
cem32k     cem32k
b4d2o1     b4d2o1
abc123     abc123

Agora, quando executamos git pull o Git diz: "Uau, espere! Não posso adicionar o commit zyx911 ao nosso branch local porque há um commit extra em nosso branch local que não existe no branch remoto!"

Existem três maneiras de lidar com a situação

Criar um Merge Commit

Este é o comportamento padrão histórico. Git cria um novo commit (por exemplo 3649fc) que é pai de ambos dg34mp e zyx911. Merge commits são uma ferramenta extremamente útil no Git, no entanto, eles também trazem complexidade, e é por isso que a maioria concorda que o Git não deve criar um merge commit sem que o usuário o solicite explicitamente.

Além disso, como estamos mesclando estes para diferentes commits, este é um momento comum para ter conflitos de mesclagem.

    develop       origin/develop

    3649fc
dg34mp  zyx911    zyx911
    cem32k        cem32k
    b4d2o1        b4d2o1
    abc123        abc123

Rebase nos nossos commits locais

Rebasing é uma ideia importante do Git que merece uma postagem inteira, mas em linhas gerais:

Rebasing pega nosso commit local ( dg34mp) e remove-o temporariamente de nosso branch local, o que o torna fácil um fast-forward merge.

develop    origin/develop

zyx911     zyx911
cem32k     cem32k
b4d2o1     b4d2o1
abc123     abc123

então nosso commit ( dg34mp) é adicionado de volta ao nosso branch local

develop         origin/develop

40931 (dg34mp)
zyx911          zyx911
cem32k          cem32k
b4d2o1          b4d2o1
abc123          abc123

entretanto, como o hash do commit ( dg34mp ) é baseado não apenas em nossas mudanças, mas em todas as mudanças antes dele, o hash do commit muda (aqui para 40931). Este também é um momento em que os conflitos de mesclagem são comuns.

Não faça nada por padrão

Já que criar um conflito de mesclagem e rebasing têm suas próprias complexidades, não queremos que o Git faça isso por padrão. É por isso que definimos o fast-forward only com git config --global pull.ff. Contanto que estejamos apenas fazendo pull de novos commits, git pull funciona bem, mas se as coisas saírem de sincronia receberemos a mensagem

fatal: Not possible to fast-forward, aborting.

Então podemos dizer explicitamente ao Git para criar um commit de merge

git pull --merge

ou fazer rebase das nossas mudanças

git pull --rebase

Configuração Global do Git

Quando o executamos, git config --global pull.ff ele adiciona o seguinte

[pull]
        ff = only

à nossa configuração global do Git, normalmente encontrada em ~/.gitconfig.

Comentários