Branch Git divergiu após rebase

112

Eu rebasei um branch local que já foi enviado.

Git está avisando que meu branch e remoto divergiram e que:

"e ter 109 e 73 commits diferentes cada, respectivamente"

O push do meu branch resolverá isso - ou seja, isso é esperado após um rebase?

Marty Wallace
fonte
Eu tenho o mesmo problema. Podemos dizer que "a maneira certa de fazer" é realocar o branch local e só então enviar?
Mher Didaryan

Respostas:

154

Quando você rebase um branch, você tem que reescrever os commits para qualquer commit que esteja acima dos commits no branch no qual você está rebase. Isso ocorre porque uma das propriedades de um commit é seu pai (ou pais). Quando você rebase, você está mudando o pai do commit local mais antigo em seu branch - e assim mudando os hashes de commit de todos os seus commits locais, uma vez que esta mudança borbulha pelos commits transitivamente.

Uma vez que você já fez push do branch, você deveria ter fundido no branch de origem, ao invés de rebasing contra ele. É possível "forçar o push" em seu novo branch (usando a -fbandeira), mas um push normal não funcionará, porque a integridade do histórico de branches será perturbada. Se você está colaborando com outras pessoas neste ramo, empurrar à força é uma má ideia, pois fará com que outros colaboradores fiquem muito confusos quando sua história de repente não coincidir.

TL; DR - Se você não estiver colaborando, empurre o branch usando push -f. Se estiver, redefina a ramificação para o estado anterior e mescle na ramificação de origem.

Jason LeBrun
fonte
1
"Já que você já fez push do branch, deveria ter mesclado no branch de origem" - por que isso?
hammett
1
@HamiltonVerissimo A primeira frase de Jason: "Quando você rebase um branch, você tem que reescrever os commits para qualquer commit que esteja acima dos commits no branch no qual você está rebase." Mesmo que as mudanças capturadas nos commits "acima" tenham o mesmo conteúdo lógico, elas estão sendo aplicadas a uma base diferente e, portanto, são commits diferentes com hashes diferentes. Se outros desenvolvedores estiverem trabalhando a partir do branch pré-rebaseado, fazer um git push -f seria extremamente perturbador para o fluxo de trabalho. Portanto, como este branch foi transferido para uma fonte pública, ele deveria ter fundido.
awolf
4
você também pode usar push --force-with-lease se não tiver certeza se alguém já enviou algo.
Console de
1
@ jason-lebrun Não é a desvantagem de mesclar as alterações do upstream que você pode sobrescrever seu próprio trabalho sem aviso? Os conflitos de mesclagem são detectados da mesma forma que no rebasing? Por exemplo, se eu remover uma seção de um arquivo em meu branch porque ela não é mais necessária, mas outra pessoa fez uma alteração trivial na mesma seção no upstream, como remover alguns espaços em branco ou alguma ação global localizar / substituir, não mesclar isso no topo do meu branch substituir minha exclusão com sua versão modificada trivialmente?
Chris Bloom
1
Mesclar o outro branch com o seu não é uma má ideia? Por exemplo, mesclar master em um branch de recurso - isso não criará um novo commit para isso? Isso não resultará em um commit extra, uma vez que este branch de recurso se mesclar para master mais tarde?
Ross
55

Todos os seus commits mudaram de id, então o desvio não é verdadeiramente uma divergência.

Para resolver seu problema, você deve sobrescrever seu branch remoto:

git push -f origin experiment

http://git-scm.com/book/ch3-6.html

Explicação:

Veja como nesta imagem C3 não é colocado como C3 após o rebase, mas como C3 '. Isso ocorre porque não é exatamente C3, mas tem todas as alterações de código.

Rebase

Nesta outra imagem, você tem uma ideia do que um rebase é visto quando um controle remoto está envolvido, e por que há um desvio.

diverge e git push

Em qualquer caso, depois de fazer o push forçado, ele dirá que fez uma (atualização forçada), você deve estar bem nesse ponto.

Verifique o link no topo e procure por "git push --force". Você verá uma explicação mais detalhada.

mimoralea
fonte
3
Sim. Acho que isso resolve o problema. Porém, force push pode não funcionar quando você está trabalhando em uma equipe, quando seu push pode substituir qualquer trabalho recente enviado por outros. Estou certo?
Hari Krishna Ganji
Pode não ter os efeitos desejados. Certifique-se de mesclar suas alterações 'fast forward' antes de fazer o rebase.
mimoralea
1

Tive sucesso com a divergência de rebase para um push ao fazer o seguinte:

git checkout mybranch
git pull
git push origin mybranch

A atração resolveu a divergência.

ANTES de puxar

Your branch and 'origin/mybranch' have diverged,
and have 2 and 1 different commit(s) each, respectively.

PULL output

Mesclagem feita por recursiva. mypath / myfile.py | 12 +++++++++++ - 1 arquivo alterado, 11 inserções (+), 1 exclusões (-)

APÓS puxar

Seu branch está à frente de 'origin / mybranch' por 3 commits.

APÓS EMPURRAR

mybranch está 3 à frente do branch e ainda tem uma mensagem de mesclagem de solicitação de pull aberta adicionada ao histórico de commits Merge branch mybranch de remoto em mybranch

Estou assumindo que isso é provavelmente o que o impulso de força faz, e não verifiquei.

Como os outros disseram, evite um rebase se você já tiver uma solicitação pull aberta. Estou fornecendo este exemplo como algo que funcionou para mim.

zerocog
fonte
1

Isso pode ser corrigido sem um force push, rebaseando o branch de destino em seu branch local atual, mudando para seu branch de destino e, em seguida, rebaseando seu branch local no alvo. Isso não diverge, pois os commits que podem estar faltando são adicionados e não precisam mais ser criados. Exemplo para uma explicação mais fácil:

  1. ramo principal é desenvolver
  2. Você verifica um novo branch feature / doing_stuff
  3. Um membro da equipe empurra um novo compromisso para desenvolver

Se você NÃO atualizou seu branch de desenvolvimento, então um "git checkout developers" && "git rebase feature / doing_stuff" funcionará corretamente, já que nenhum commit foi adicionado desde o seu checkout. No entanto, se você fez check-out do desenvolvimento e baixou o novo commit, então você verá essa divergência se tentar rebase devido a um novo commit ser visto. Uma solução fácil sem empurrar com força (geralmente não é uma boa ideia em um ambiente de equipe) é:

  1. git checkout feature / doing_stuff
  2. git rebase desenvolva
  3. git checkout development
  4. git rebase feature / doing_stuff

O rebase da etapa 2 traz o commit ausente para o feature / doing_stuff, portanto, quando a etapa 4 chega, ele está atualizado e não precisa criar um novo commit para a mudança.

Esta é uma solução que eu sei que funciona porque acabei de encontrar isso e executei as etapas acima para desenvolver o push com sucesso sem forçar. Eu trabalho em uma equipe de mais de 50 desenvolvedores, então é proibido forçar o envio de qualquer coisa que não seja meus próprios branches de teste, então eu tive que encontrar uma solução.

Chris
fonte