git rebase, mantendo o controle de ‘local’ e ‘remoto’

Ao fazer um rebase git, muitas vezes tenho dificuldade em descobrir o que está acontecendo com o ‘local’ e ‘remoto’ ao resolver conflitos. Às vezes tenho a impressão de que eles trocam de lado de um commit para o seguinte.

Isso é provavelmente (definitivamente) porque eu ainda não entendi direito.

Quando rebasing, quem é ‘local’ e quem é ‘remoto’?

(Eu uso o P4Merge para resolver conflitos)

TL; DR;

Para resumir (como as observações de Benubird ), quando:

 git checkout A git rebase B # rebase A on top of B 
  • local é B (rebase para ),
  • remote é A

E:

 git checkout A git merge B # merge B into A 
  • local é A (mesclar),
  • remote é B

Um rebase alterna o ours (o ramo atual antes de o rebase iniciar) e o theirs (o ramo no topo do qual você deseja fazer o rebase).


kutschkem ressalta que, em um contexto de fusilagem de GUI :

  • referências locais os commits parcialmente refeitos : ” ours ” (a ramificação upstream)
  • remote refere-se às alterações recebidas : ” theirs ” – o ramo atual antes do rebase.

Veja ilustrações na última parte desta resposta.


Inversão quando rebase

A confusão pode estar relacionada à inversão da ours e da theirs durante um rebase .
(extratos relevantes)

git rebase man page :

Observe que uma mesclagem de rebase funciona repetindo cada confirmação da ramificação de trabalho na parte superior da ramificação .

Por causa disso, quando um conflito de mesclagem acontece:

  • o lado reportado como ‘ ours ‘ é a série tão rebased, começando com ,
  • e ‘ theirs ‘ é o ramo de trabalho. Em outras palavras, os lados são trocados.

Inversão ilustrada

Em uma fusão

 x--x--x--x--x(*) < - current branch B ('*'=HEAD) \ \ \--y--y--y <- other branch to merge 

, nós não mudamos a ramificação atual 'B', então o que temos ainda é o que estávamos trabalhando (e nos fundimos a partir de outra ramificação)

 x--x--x--x--x---------o(*) MERGE, still on branch B \ ^ / \ ours / \ / --y--y--y--/ ^ their 

Em um rebase:

Mas em um rebase , nós mudamos de lado porque a primeira coisa que um rebase faz é checar o branch upstream! (para repetir os commits atuais em cima)

 x--x--x--x--x(*) < - current branch B \ \ \--y--y--y <- upstream branch 

Um git rebase upstream primeiro mudará HEAD of B para o branch upstream do upstream (daí a mudança de 'ours' e 'theirs' em comparação com o ramo de trabalho anterior "atual").

 x--x--x--x--x < - former "current" branch, new "theirs" \ \ \--y--y--y(*) <- upstream branch with B reset on it, new "ours", to replay x's on it 

e, em seguida, o rebase fará o replay de 'their' commits no novo branch 'our' B:

 x--x..x..x..x < - old "theirs" commits, now "ghosts", available through reflogs \ \ \--y--y--y--x'--x'--x'(*) <- branch B with HEAD updated ("ours") ^ | upstream branch 

Nota: a noção "upstream" é o conjunto referencial de dados (um repo todo ou, como aqui, uma ramificação, que pode ser uma ramificação local ) a partir da qual os dados são lidos ou para os quais novos dados são adicionados / criados.


' local ' e ' remote ' vs. ' mine ' e ' theirs '

Pandawood adiciona nos comentários :

Para mim, a questão ainda permanece, que é "local" e quem é "remoto" (desde que os termos "nosso" e "deles" não são usados ​​quando rebasing no git, referindo-se a eles apenas parece fazer uma resposta mais confusa) .

GUI git mergetool

kutschkem adiciona, e com razão:

Ao resolver conflitos, o git dirá algo como:

 local: modified file and remote: modified file. 

Tenho certeza de que a questão visa a definição de local e remoto neste ponto. Nesse ponto, parece-me pela minha experiência que:

  • referências locais os commits parcialmente refeitos : " ours " (a ramificação upstream)
  • remote refere-se às alterações recebidas : " theirs " - o ramo atual antes do rebase.

git mergetool fato menciona 'local' e 'remoto' :

 Merging: f.txt Normal merge conflict for 'f.txt': {local}: modified file {remote}: modified file Hit return to start merge resolution tool (kdiff3): 

Por exemplo, o KDiff3 exibiria a resolução de mesclagem da seguinte forma :

kdiff3

E o meld também mostraria isso :

Meld diff

O mesmo para o VimDiff , que exibe :

Invoque o Vimdiff como um mergetool com o git mergetool -t gvimdiff. Versões recentes do Git invocam o Vimdiff com o seguinte layout de janela:

 +--------------------------------+ | LOCAL | BASE | REMOTE | +--------------------------------+ | MERGED | +--------------------------------+ 
  • LOCAL :
    Um arquivo temporário contendo o conteúdo do arquivo no ramo atual.
  • BASE :
    Um arquivo temporário contendo a base comum para a mesclagem.
  • REMOTE :
    Um arquivo temporário contendo o conteúdo do arquivo a ser mesclado.
  • MERGED :
    O arquivo que contém os marcadores de conflito.

O Git executou o máximo possível de resolução automática de conflitos e o estado desse arquivo é uma combinação de LOCAL e REMOTE com marcadores de conflito em torno de qualquer coisa que o Git não pudesse resolver sozinho.
O mergetool deve escrever o resultado da resolução para este arquivo.

A linha de fundo

rebase git

  • LOCAL = a base que você está rebaixando
  • REMOTO = os commits que você está subindo no topo

git merge

  • LOCAL = o ramo original em que você está se fundindo
  • REMOTE = o outro ramo cujo commit você está mesclando

Em outras palavras, LOCAL é sempre o original, e REMOTE é sempre o cara cujos commits não estavam lá antes, porque eles estão sendo mesclados ou rebased no topo

Prove isso!

Certamente. Não tome minha palavra para isso! Aqui está uma experiência fácil que você pode fazer para ver por si mesmo.

Primeiro, certifique-se de ter o gitto mergetool configurado corretamente. (Se não o fizesse, provavelmente você não estaria lendo essa questão de qualquer maneira). Em seguida, encontre um diretório para trabalhar.

Configure seu repository:

 md LocalRemoteTest cd LocalRemoteTest 

Crie um commit inicial (com um arquivo vazio):

 git init notepad file.txt (use the text editor of your choice) (save the file as an empty file) git add -A git commit -m "Initial commit." 

Crie um commit em um branch que não é master:

 git checkout -b notmaster notepad file.txt (add the text: notmaster) (save and exit) git commit -a -m "Add notmaster text." 

Crie um commit no branch master:

 git checkout master notepad file.txt (add the text: master) (save and exit) git commit -a -m "Add master text." gitk --all 

Neste ponto, seu repository deve ficar assim:

Repositório com uma consolidação de base e duas ramificações de um único commit

Agora, para o teste de rebase:

 git checkout notmaster git rebase master (you'll get a conflict message) git mergetool LOCAL: master REMOTE: notmaster 

Agora o teste de mesclagem. Feche seu mergetool sem salvar nenhuma alteração e, em seguida, cancele o rebase:

 git rebase --abort 

Então:

 git checkout master git merge notmaster git mergetool LOCAL: master REMOTE: notmaster git reset --hard (cancels the merge) 

Seus resultados devem ser os mesmos que aparecem no topo.

Eu não entendi exatamente o problema, mas acho que o diagrama a seguir resolve seu problema. (Rebase: Repositório Remoto —> Área de Trabalho)

http://assets.osteele.com/images/2008/git-transport.png

Fonte: Meu stream de trabalho do Git