Como uso o vimdiff para resolver um conflito de mesclagem do git?


159

Acabei de fundir um ramo no meu mestre no git e consegui Automatic merge failed; fix conflicts and then commit the result.Agora corri git mergetoole vimdiff foi aberto com a imagem abaixo. Não sei como usar o vimdiff. O que cada painel aqui significa e como devo proceder para corrigir o conflito de mesclagem?

insira a descrição da imagem aqui


3
Veja esta página . Se é isso que você quer dizer com "correto", o estado atual do seu código está no canto superior esquerdo.
romainl

@romainl Ainda estou confuso depois de ler isso, quais são os atalhos e como escolho qual arquivo usar como ramo principal?
Indivíduo fresco Yo


Veja também: this
skelliam

Respostas:


142

Todos os quatro buffers fornecem uma visão diferente do mesmo arquivo. O buffer superior esquerdo (LOCAL) é a aparência do arquivo na ramificação de destino (na qual você está mesclando). O buffer superior direito (REMOTE) é a aparência do arquivo na ramificação de origem (de onde você está mesclando). O buffer do meio (BASE) é o ancestral comum dos dois (para que você possa comparar como as versões esquerda e direita divergem umas das outras).

Eu posso estar enganado no seguinte ponto. Eu acho que a fonte do conflito de mesclagem é que os dois arquivos mudaram a mesma parte do arquivo desde o BASE; LOCAL alterou as aspas de duplo para único e REMOTE fez a mesma alteração, mas também alterou o valor de segundo plano de uma cor para um URL. (Eu acho que a mesclagem não é inteligente o suficiente para perceber que todas as alterações em LOCAL também estão presentes no REMOTE; ele apenas sabe que LOCAL fez alterações desde BASE nos mesmos locais que o REMOTE).

De qualquer forma, o buffer inferior contém o arquivo que você pode editar - aquele localizado no seu diretório de trabalho. Você pode fazer as alterações que desejar; vimestá mostrando como ela difere de cada uma das vistas superiores, que são as áreas que a mesclagem automática não conseguiu lidar. Puxe as alterações de LOCAL se não desejar as alterações REMOTE. Puxe as alterações de REMOTE, se você preferir as alterações LOCAL. Puxe da BASE se achar que REMOTE e LOCAL estão errados. Faça algo completamente diferente se tiver uma ideia melhor! No final, as alterações feitas aqui são as que realmente serão confirmadas.


4
Pergunta rápida como faço para salvar no vim?
Indivíduo fresco Yo

6
:xou :w( :xsai também) mais 'return'.
31813 Jonathan Leffler

4
Anders: existem outras ferramentas de mesclagem que você pode usar se não estiver familiarizado com o uso vim.
chepner

3
@AndersKitson, como você está no Mac OS X, o FileMerge é perfeito, gratuito e vem com o XCode.
Romainl

8
Por que o voto negativo? Se houver algo de fato incorreto, corrija-o ou, pelo menos, aponte-o.
chepner

91

A resposta do @ chepner é ótima, eu gostaria de adicionar alguns detalhes sobre a parte "como devo proceder para corrigir o conflito de mesclagem". Se você examinar como realmente usar o vimdiff nesse caso, ele será mostrado abaixo.


Primeiro, para abordar a opção "abortar tudo" - se você não quiser usar "vimdiff" e quiser abortar a mesclagem: pressione Esc, digite :qa!e pressione Enter. (consulte também Como faço para sair do editor Vim? ). O Git perguntará se a mesclagem foi concluída, responda com n.


Se você deseja usar o vimdiff, aqui estão alguns atalhos úteis. Isso pressupõe que você conhece os conceitos básicos do Vim (navegação e inserção / modo normal):

  • navegue até o buffer inferior (resultado da mesclagem): Ctrl-W j
  • navegue para o próximo diff com j/ k; ou, melhor, use ] ce [ cpara navegar para a diferença seguinte e anterior, respectivamente
  • use z oenquanto estiver dobrado para abri-lo, se você quiser ver mais contexto
  • para cada diff, conforme a resposta do @ chepner, você pode obter o código de uma versão local, remota ou base, ou editá-lo e refazê-lo como achar melhor
    • para obtê-lo da versão local, use :diffget LO
    • do controle remoto: :diffget RE
    • da base: :diffget BA
    • ou, se você quiser editar o código sozinho, obtenha uma versão do local / remoto / base primeiro e, em seguida, vá para o modo de inserção e edite o restante
  • Depois de feito, salve o resultado da mesclagem e feche todas as janelas :wqa
  • normalmente, o git detecta que a mesclagem foi feita e cria o commit da mesclagem

Não parece possível adicionar blocos de conflito locais e remotos sem colar cola ou atalhos personalizados: /vi/10534/is-there-a-way-to-take-both- when-using-vim-as-merge-tool, que é uma pena, pois add add é um tipo de conflito tão comum.

Para impedir que o vimdiff peça para você pressionar enter toda vez que for iniciado, adicione ao seu .vimrc:

set shortmess=Ot

conforme mencionado em: /vi/771/how-can-i-suppress-the-press-enter-prompt-when-opening-files-in-diff-mode

Você pode pesquisar na Internet por outros atalhos do vimdiff. Eu encontrei este útil: https://gist.github.com/hyamamoto/7783966


10
Isso deve ser votado x1000 vezes e aceito como uma resposta melhor.
Andrey Portnoy

para pular rapidamente para o próximo conflito, basta procurar por ===. faça "/ ===" e digite
Apit John Ismail

Consulte esta postagem ( stackoverflow.com/questions/51520705/… ) se mais de uma correspondência encontrada usando :diffget.
Jason

7

A melhor ferramenta de fusão para substituir o vimdiff

Isso é meio que explícito, mas foi para isso que acabei convergindo como um vimmer depois de tentar vimdiff.

Para resolver um conflito de mesclagem, o que quase sempre preciso é ver:

  • CONTROLO REMOTO
  • LOCAL
  • duas diferenças:
    • diff BASE REMOTE
    • diff BASE LOCAL

para tentar juntar os dois.

Enquanto o vimdiff mostra BASE, LOCAL e REMOTE na tela:

    +--------------------------------+
    | LOCAL  |     BASE     | REMOTE |
    +--------------------------------+
    |             MERGED             |
    +--------------------------------+

Eu não sei como fazê-lo mostrar claramente essas duas diferenças que eu preciso, além de olhar direito, esquerdo, direito e esquerdo várias vezes.

Além disso, LOCAL e REMOTE já são visíveis nos marcadores de conflito de mesclagem do git, então não ganho muito com uma ferramenta que os mostra novamente.

Portanto, criei meu próprio "difftool" minúsculo que realmente mostra os diffs que estavam faltando:

~ / bin / cirosantilli-mergetool

#!/usr/bin/env bash
BASE="$1"
LOCAL="$2"
REMOTE="$3"
diff --color -u "$BASE" "$LOCAL"
diff --color -u "$BASE" "$REMOTE"
exit 1

GitHub upstream .

E instale-o com:

git config --global mergetool.cirosantilli-mergetool.cmd 'cirosantilli-mergetool $BASE $LOCAL $REMOTE'
git config --global mergetool.cirosantilli-mergetool.trustExitCode true
# If you want this to become your default mergetool.
#git config --global merge.tool 'cirosantilli-mergetool'

Agora, quando você faz:

git mergetool -t cirosantilli-mergetool

mostra as duas diferenças que eu quero no terminal, por exemplo, algo junto:

--- ./src/dev/arm/RealView_BASE_15560.py        2019-12-27 13:46:41.967021591 +0000
+++ ./src/dev/arm/RealView_LOCAL_15560.py       2019-12-27 13:46:41.979021479 +0000
@@ -994,7 +994,7 @@                                                              

     def setupBootLoader(self, cur_sys, loc):
         if not cur_sys.boot_loader:                           
-            cur_sys.boot_loader = [ loc('boot_emm.arm64'), loc('boot_emm.arm') ]
+            cur_sys.boot_loader = [ loc('boot.arm64'), loc('boot.arm') ]
         cur_sys.atags_addr = 0x8000000                  
         cur_sys.load_offset = 0x80000000                    

@@ -1054,7 +1054,7 @@                                           
             ]                                                     

     def setupBootLoader(self, cur_sys, loc):
-        cur_sys.boot_loader = [ loc('boot_emm_v2.arm64') ]
+        cur_sys.boot_loader = [ loc('boot_v2.arm64') ]
         super(VExpress_GEM5_V2_Base,self).setupBootLoader(
                 cur_sys, loc)                             

--- ./src/dev/arm/RealView_BASE_15560.py        2019-12-27 13:46:41.967021591 +0000
+++ ./src/dev/arm/RealView_REMOTE_15560.py      2019-12-27 13:46:41.991021366 +0000
@@ -610,10 +610,10 @@           
     def attachIO(self, *args, **kwargs):              
         self._attach_io(self._off_chip_devices(), *args, **kwargs)

-    def setupBootLoader(self, cur_sys, loc):
-        cur_sys.boot_loader = loc('boot.arm') 
-        cur_sys.atags_addr = 0x100                           
-        cur_sys.load_offset = 0       
+    def setupBootLoader(self, cur_sys, boot_loader, atags_addr, load_offset):
+        cur_sys.boot_loader = boot_loader      
+        cur_sys.atags_addr = atags_addr     
+        cur_sys.load_offset = load_offset

Então você pode ver aqui as duas diferenças despejadas no terminal:

  • RealView_BASE_15560.py vs RealView_LOCAL_15560.py
  • RealView_BASE_15560.py vs RealView_REMOTE_15560.py

Se os diffs forem grandes, procurarei apenas com meus superpoderes do tmux .

Sim, você perde alguns atalhos fornecidos pelo vimdiff, mas, em geral, a solução de conflitos requer uma colagem cuidadosa de cópias de ambas as versões, o que eu posso fazer dentro de uma sessão normal do vim com os marcadores de conflito git.

Observando e diferenciando arquivos enquanto vimdiffestá em execução

Antes de me sentar e automatizar minha configuração perfeita cirosantilli-mergetool, era isso que eu estava fazendo para obter as duas diferenças necessárias.

Enquanto git mergetoolestiver em execução vimdiff, se houver um conflito em um arquivo chamado, por exemplo main.py, o git gera arquivos para cada uma das versões, denominadas como:

main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

no mesmo diretório em main.pyque 1367está o PID do git mergetool e, portanto, um número inteiro "aleatório", como mencionado em: Em um conflito de mesclagem do git, quais são os arquivos BACKUP, BASE, LOCAL e REMOTE que são gerados?

Então, para ver as diferenças que eu quero, primeiro encontro os arquivos gerados git statuse, em seguida, abro novos terminais e faço um vimdiff entre os pares de arquivos que me interessam:

vim -d main_BASE_1367.py main_LOCAL_1367.py
vim -d main_BASE_1367.py main_REMOTE_1367.py

Juntamente com git mergetool, essas informações ajudam MUITO a descobrir o que está acontecendo rapidamente!

Além disso, mesmo enquanto o mergetool estiver em execução, você pode simplesmente abrir o arquivo:

vim main.py

diretamente e edite-o lá se achar que será mais fácil com uma janela maior do editor.

Ir diretamente para mesclar conflitos

Enquanto ]cpula para o próximo ponto diferencial dentro do vimdiff, nem sempre há um conflito de mesclagem lá.

Para ajudar com isso, eu tenho no meu ~/.vimrc:

# Git Merge conflict
nnoremap <leader>gm /\v^\<\<\<\<\<\<\< \|\=\=\=\=\=\=\=$\|\>\>\>\>\>\>\> /<cr>

que encontra os conflitos diretamente.

git imerge

Talvez a melhor opção seja desistir do uso do vimdiff e confiar no vim + git imerge regular, mencionado em: Como descobrir qual commit do Git causa conflitos? já que a curva de aprendizado de vimdiff é irritante e não executa as funções que mais precisamos.


1
Votado. Acho que mencionei isso há 9 anos em stackoverflow.com/a/3052118/6309 . (ver a última parte da resposta)
VonC

@VonC sim, acho que você ganhou este! XD
Ciro Santilli respondeu
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.