Come posso usare vimdiff per risolvere un conflitto git merge?


159

Ho appena unito un ramo nel mio master in git e ho ottenuto Automatic merge failed; fix conflicts and then commit the result.Ora ho corso git mergetoole vimdiff si è aperto con l'immagine qui sotto. Non so come usare vimdiff. Che cosa significa ogni pannello qui e come devo procedere per correggere il conflitto di unione?

inserisci qui la descrizione dell'immagine


3
Vedere questa pagina . Se questo è ciò che intendi per "corretto", lo stato corrente del tuo codice è in alto a sinistra.
Romainl,

@romainl Sono ancora confuso dopo averlo letto, quali sono le scorciatoie e come posso scegliere quale file utilizzare come ramo principale?
Cool Guy Yo,


Vedi anche: questo
skelliam

Risposte:


142

Tutti e quattro i buffer forniscono una vista diversa dello stesso file. Il buffer in alto a sinistra (LOCAL) è l'aspetto del file nel ramo di destinazione (in che cosa si sta unendo). Il buffer in alto a destra (REMOTE) è l'aspetto del file nel ramo di origine (da cui si sta unendo). Il buffer centrale (BASE) è l'antenato comune dei due (quindi è possibile confrontare il modo in cui le versioni sinistra e destra si sono discostate l'una dall'altra).

Potrei sbagliarmi sul punto seguente. Penso che la fonte del conflitto di unione sia che entrambi i file hanno cambiato la stessa parte del file da BASE; LOCAL ha modificato le virgolette da doppie a singole e REMOTE ha apportato la stessa modifica, ma ha anche modificato il valore di sfondo da un colore a un URL. (Penso che l'unione non sia abbastanza intelligente da notare che tutte le modifiche a LOCAL sono presenti anche in REMOTE; sa solo che LOCAL ha apportato modifiche da BASE negli stessi posti di REMOTE).

In ogni caso, il buffer inferiore contiene il file che puoi effettivamente modificare, quello che si trova nella tua directory di lavoro. Puoi apportare le modifiche che desideri; vimti sta mostrando come differisce da ciascuna delle viste principali, che sono le aree che l'unione automatica non è riuscita a gestire. Estrarre le modifiche da LOCAL se non si desidera le modifiche REMOTE. Estrai le modifiche da REMOTO se preferisci quelle alle modifiche LOCALI. Estrarre da BASE se si ritiene che sia REMOTE sia LOCAL siano errati. Fai qualcosa di completamente diverso se hai un'idea migliore! Alla fine, le modifiche apportate qui sono quelle che verranno effettivamente impegnate.


4
Domanda veloce come posso salvare in vim?
Cool Guy Yo,

6
:xo :w( :xesce anche) più 'return'.
Jonathan Leffler,

4
Anders: ci sono altri strumenti di unione che puoi usare se non hai familiarità con l'uso vim.
Chepner,

3
@AndersKitson, poiché sei su Mac OS X, FileMerge è perfetto, gratuito e viene fornito con XCode.
Romainl,

8
Perché il downvote? Se c'è qualcosa di effettivamente errato, correggilo o almeno segnalalo.
Chepner,

91

La risposta di @ chepner è ottima, vorrei aggiungere alcuni dettagli su "come devo procedere per risolvere il conflitto di unione" della domanda. Se osservi come utilizzare effettivamente Vimdiff in questo caso, va sotto.


Innanzitutto, per affrontare l'opzione "annulla tutto" - se non si desidera utilizzare "vimdiff" e si desidera interrompere l'unione: premere Esc, quindi digitare :qa!e premere Enter. (vedi anche Come uscire dall'editor Vim? ). Git ti chiederà se l'unione è stata completata, rispondi con n.


Se vuoi usare vimdiff, ecco alcune scorciatoie utili. Ciò presuppone che tu conosca le basi di Vim (navigazione e inserimento / modalità normale):

  • vai al buffer inferiore (unisci risultato): Ctrl-W j
  • vai al prossimo diff con j/ k; o, meglio, usare ] ce [ cper passare rispettivamente alla differenza successiva e precedente
  • utilizzare z oin piega per aprirlo, se si desidera vedere più contesto
  • per ogni diff, secondo la risposta di @ chepner, puoi ottenere il codice da una versione locale, remota o di base, oppure modificarlo e ripetere come meglio credi
    • per ottenerlo dalla versione locale, utilizzare :diffget LO
    • dal telecomando: :diffget RE
    • dalla base: :diffget BA
    • oppure, se si desidera modificare il codice da soli, ottenere prima una versione da local / remote / base, quindi passare alla modalità di inserimento e modificare il resto
  • una volta fatto, salva il risultato dell'unione ed esci da tutte le finestre :wqa
  • normalmente, git rileva che l'unione è stata fatta e crea il commit di unione

Non sembra essere possibile aggiungere blocchi di conflitti sia locali che remoti senza incollare copie o collegamenti personalizzati: /vi/10534/is-there-a-way-to-take-both- quando-usando-vim-come-merge-tool che è un peccato dato che aggiungere aggiungere è un tipo di conflitto così comune.

Per evitare che vimdiff ti chieda di premere invio ogni volta che si avvia, aggiungi a .vimrc:

set shortmess=Ot

come menzionato in: /vi/771/how-can-i-suppress-the-press-enter-prompt-when-opening-files-in-diff-mode

Puoi cercare in Internet altre scorciatoie di Vimdiff. Ho trovato questo utile: https://gist.github.com/hyamamoto/7783966


10
Questo dovrebbe essere aggiornato x1000 volte e accettato come una risposta migliore.
Andrey Portnoy,

per passare rapidamente al prossimo conflitto, basta cercare ===. fai "/ ===" e inserisci
Apit John Ismail,

Vedi questo post ( stackoverflow.com/questions/51520705/… ) se è stata trovata più di una corrispondenza utilizzando :diffget.
Jason il

7

La fusione definitiva per sostituire vimdiff

Questo è un po 'ironico, ma è quello che ho finito per convergere come un vimmer dopo aver provato Vimdiff.

Per risolvere un conflitto di unione, ciò di cui ho quasi sempre bisogno è vedere:

  • A DISTANZA
  • LOCALE
  • due differenze:
    • diff BASE REMOTE
    • diff BASE LOCALE

per poi provare a metterli insieme.

Mentre vimdiff mostra BASE, LOCAL e REMOTE sullo schermo:

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

Non so come fare per mostrare chiaramente quei due diff che mi servono, inoltre, guardando a destra a sinistra a sinistra un sacco di volte.

Inoltre, LOCAL e REMOTE sono già visibili nei marker di conflitto di git merge, quindi non guadagno molto da uno strumento che li mostra di nuovo.

Pertanto, ho invece creato il mio piccolo "difftool" che in realtà mostra le differenze che mi mancavano:

~ / 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 a monte .

E installalo con:

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'

Ora, quando lo fai:

git mergetool -t cirosantilli-mergetool

mostra le due differenze che desidero sul terminale, ad esempio qualcosa:

--- ./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

Quindi puoi vedere qui i due diff scaricati nel terminale:

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

Se i diff sono grandi, cercherò solo con i miei superpoteri tmux .

Sì, perdi alcune scorciatoie fornite da vimdiff, ma in generale la risoluzione dei conflitti richiede un'attenta copia delle copie da entrambe le versioni, cosa che posso fare bene in una normale sessione di vim con i marker di conflitto git.

Osservare e diffondere file mentre vimdiffè in esecuzione

Prima di sedermi e automatizzare la mia configurazione perfetta cirosantilli-mergetool, questo è quello che stavo facendo per ottenere le due differenze di cui avevo bisogno.

Durante l' git mergetoolesecuzione vimdiff, in caso di conflitto in un file denominato, ad esempio main.py, git genera file per ciascuna delle versioni, denominate come:

main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

nella stessa directory di main.pydove si 1367trova il PID di git mergetool e quindi un numero intero "casuale", come menzionato in: In un conflitto di git merge, quali sono i file BACKUP, BASE, LOCAL e REMOTE che vengono generati?

Quindi, per vedere le differenze che voglio, prima trovo i file generati git status, quindi apro nuovi terminali e faccio un vimdiff tra le coppie di file che mi interessano:

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

Insieme a git mergetool, queste informazioni aiutano MOLTO a capire cosa sta succedendo rapidamente!

Inoltre, anche mentre mergetool è in esecuzione, puoi semplicemente aprire il file:

vim main.py

direttamente e modificalo lì se ritieni che sarà più facile con una finestra dell'editor più grande.

Salta direttamente per unire i conflitti

Mentre ]csalta al successivo punto diff all'interno di vimdiff, non c'è sempre un conflitto di unione lì.

Per aiutare con questo, ho nel mio ~/.vimrc:

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

che trova direttamente i conflitti.

git imerge

Forse l'opzione migliore è semplicemente rinunciare a usare vimdiff e fare affidamento su vim + git imerge che è stato menzionato in: Come posso sapere quale Git si commette causa conflitti? poiché la curva di apprendimento di vimdiff è fastidiosa e non svolge le funzioni di cui abbiamo più bisogno.


1
Upvoted. Penso di averlo menzionato 9 anni fa in stackoverflow.com/a/3052118/6309 . (vedi l'ultima parte della risposta)
VonC

@VonC sì, penso che tu abbia vinto questo! XD
Ciro Santilli 14 冠状 病 六四 事件 法轮功
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.