Jak używać vimdiff do rozwiązywania konfliktów git merge?

159

Właśnie połączyłem gałąź z moim masterem w git i otrzymałem. Automatic merge failed; fix conflicts and then commit the result.Teraz uruchomiłem git mergetooli vimdiff otworzył się z poniższym obrazkiem. Nie wiem, jak używać vimdiff. Co oznacza każdy panel w tym miejscu i jak powinienem rozwiązać konflikt scalania?

wprowadź opis obrazu tutaj

Cool Guy Yo
źródło
3
Zobacz tę stronę . Jeśli to właśnie masz na myśli mówiąc „poprawny”, aktualny stan twojego kodu znajduje się w lewym górnym rogu.
romainl
@romainl Po przeczytaniu tego nadal jestem zdezorientowany. Jakie są skróty i jak wybrać plik, który ma być główną gałęzią?
Cool Guy Yo
2
@Danny http://www.rosipov.com/blog/use-vimdiff-as-git-mergetool/ jest dobry.
ᴠɪɴᴄᴇɴᴛ
Zobacz także: to
skelliam

Odpowiedzi:

142

Wszystkie cztery bufory zapewniają inny widok tego samego pliku. Bufor po lewej stronie u góry (LOCAL) to wygląd pliku w gałęzi docelowej (w którą scalasz). Bufor w prawym górnym rogu (REMOTE) to wygląd pliku w gałęzi źródłowej (skąd scalasz). Bufor środkowy (BASE) jest wspólnym przodkiem obu (dzięki czemu można porównać, w jaki sposób wersje lewa i prawa różnią się od siebie).

Mogę się mylić w następującym punkcie. Myślę, że źródłem konfliktu podczas łączenia jest to, że oba pliki zmieniły tę samą część pliku od czasu BASE; LOCAL zmienił cudzysłowy z podwójnych na pojedyncze, a REMOTE dokonał tej samej zmiany, ale także zmienił wartość tła z koloru na adres URL. (Myślę, że scalanie nie jest wystarczająco inteligentne, aby zauważyć, że wszystkie zmiany LOCAL są również obecne w REMOTE; po prostu wie, że LOCAL wprowadził zmiany od czasu BASE w tych samych miejscach, co REMOTE).

W każdym razie dolny bufor zawiera plik, który możesz edytować - ten, który znajduje się w katalogu roboczym. Możesz wprowadzić dowolne zmiany; vimpokazuje, czym różni się on od każdego z górnych widoków, czyli obszarów, których automatyczne scalanie nie mogło sobie poradzić. Pobierz zmiany z LOCAL, jeśli nie chcesz, aby zmiany REMOTE. Pobierz zmiany z REMOTE, jeśli wolisz je od zmian LOKALNYCH. Wyciągnij z BASE, jeśli uważasz, że zarówno ZDALNE, jak i LOKALNE są błędne. Zrób coś zupełnie innego, jeśli masz lepszy pomysł! Ostatecznie zmiany, które tu wprowadzisz, są faktycznie wprowadzane.

Chepner
źródło
4
Szybkie pytanie, jak zapisać w vimie?
Cool Guy Yo,
6
:xlub :w( :xteż wychodzi) plus „powrót”.
Jonathan Leffler,
4
Anders: istnieją inne narzędzia do scalania, których możesz użyć, jeśli nie wiesz, jak ich używać vim.
chepner
3
@AndersKitson, ponieważ korzystasz z Mac OS X, FileMerge jest doskonały, darmowy i zawiera XCode.
romainl
8
Dlaczego głos przeciw? Jeśli coś jest nie tak ze stanem faktycznym, napraw to lub przynajmniej wskaż.
chepner
91

Odpowiedź @ chepner jest świetna, chciałbym dodać kilka szczegółów na temat części pytania „jak mam postępować, aby naprawić konflikt scalania”. Jeśli przyjrzysz się, jak właściwie używać vimdiff w tym przypadku, znajdziesz to poniżej.


Po pierwsze, aby zająć się opcją "przerwij wszystko" - jeśli nie chcesz używać "vimdiff" i chcesz przerwać scalanie: naciśnij Esc, a następnie wpisz :qa!i naciśnij Enter. (zobacz też Jak wyjść z edytora Vima? ). Git zapyta, czy scalanie zostało zakończone, odpowiedz n.


Jeśli chcesz używać vimdiff, oto kilka przydatnych skrótów. Zakłada się, że znasz podstawy Vima (nawigacja i tryb wstawiania / normalny):

  • przejdź do dolnego bufora (wynik scalania): Ctrl-W j
  • przejdź do następnego porównania za pomocą j/ k; lub lepiej, użyj ] ci, [ caby przejść odpowiednio do następnej i poprzedniej różnicy
  • użyj, z ogdy jesteś na zginaniu, aby go otworzyć, jeśli chcesz zobaczyć więcej kontekstu
  • dla każdej różnicy, zgodnie z odpowiedzią @ chepner, możesz pobrać kod z wersji lokalnej, zdalnej lub podstawowej lub edytować go i powtórzyć według własnego uznania
    • aby pobrać go z wersji lokalnej, użyj :diffget LO
    • z pilota: :diffget RE
    • od bazy: :diffget BA
    • lub jeśli chcesz samodzielnie edytować kod, najpierw pobierz wersję z lokalnego / zdalnego / podstawowego, a następnie przejdź do trybu wstawiania i edytuj resztę
  • po zakończeniu zapisz wynik scalania i zamknij wszystkie okna :wqa
  • normalnie git wykrywa, że ​​scalenie zostało wykonane i tworzy zatwierdzenie scalania

Wydaje się, że nie można dodać lokalnych i zdalnych fragmentów konfliktów bez wklejania kopii lub niestandardowych skrótów: /vi/10534/is-there-a-way-to-take-both- when-using-vim-as-merge-tool, a szkoda, ponieważ add add jest tak powszechnym typem konfliktu.

Aby vimdiff nie prosił Cię o naciśnięcie klawisza Enter przy każdym uruchomieniu, dodaj do .vimrc:

set shortmess=Ot

jak wspomniano na: /vi/771/how-can-i-suppress-the-press-enter-prompt-when-opening-files-in-diff-mode

Możesz przeszukać Internet pod kątem innych skrótów vimdiff. Uważam, że ten jest przydatny: https://gist.github.com/hyamamoto/7783966

Timur
źródło
10
Powinno to zostać przegłosowane x1000 razy i zaakceptowane jako lepsza odpowiedź.
Andrey Portnoy,
aby szybko przejść do następnego konfliktu, po prostu wyszukaj ===. wykonaj "/ ===" i wejdź
Apit John Ismail
Zobacz ten post ( stackoverflow.com/questions/51520705/ ... ), jeśli znaleziono więcej niż jedno dopasowanie przy użyciu :diffget.
Jason
7

Najlepsze narzędzie do łączenia, które zastępuje vimdiff

To trochę żartobliwy żart, ale właśnie do tego doszedłem jako vimmer po wypróbowaniu vimdiff.

Aby rozwiązać konflikt scalania, prawie zawsze potrzebuję zobaczyć:

  • ZDALNY
  • LOKALNY
  • dwie różnice:
    • diff BASE REMOTE
    • diff BASE LOCAL

a następnie spróbować połączyć je razem.

Podczas gdy vimdiff pokazuje BASE, LOCAL i REMOTE na ekranie:

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

Nie wiem, jak sprawić, by wyraźnie pokazywał te dwa różnice, których potrzebuję poza tym, patrząc kilka razy w prawo, lewo, prawo, lewo.

Co więcej, LOKALNE i ZDALNE są już widoczne w znacznikach konfliktów git merge, więc nie zyskuję zbyt wiele na narzędziu, które je ponownie pokazuje.

Dlatego zamiast tego stworzyłem własne małe "difftool", które faktycznie pokazuje różnice, których mi brakowało:

~ / bin / cirosantilli-connectetool

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

GitHub upstream .

I zainstaluj go za pomocą:

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'

Teraz, kiedy to zrobisz:

git mergetool -t cirosantilli-mergetool

pokazuje dwa różnice, które chcę na terminalu, np. coś razem:

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

Możesz więc zobaczyć tutaj dwa różnice wrzucone do terminala:

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

Jeśli różnice są duże, po prostu wyszukam moje supermoce tmux .

Tak, tracisz pewne skróty, które zapewnia vimdiff, ale ogólnie rozwiązywanie konfliktów wymaga starannego kopiowania wklejania z obu wersji, co mogę zrobić dobrze w normalnej sesji vim z markerami konfliktów git.

Obserwowanie i porównywanie plików podczas vimdiffdziałania

Zanim usiadłem i zautomatyzowałem moją idealną konfigurację cirosantilli-mergetool, właśnie to robiłem, aby uzyskać dwa różnice, których potrzebowałem.

Podczas git mergetooldziałania vimdiff, jeśli wystąpi konflikt w pliku o nazwie, powiedzmy main.py, git generuje pliki dla każdej z wersji, nazwane jako:

main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

w tym samym katalogu, w main.pyktórym 1367znajduje się identyfikator PID git connectetool, a zatem „losowa” liczba całkowita, jak wspomniano w: W przypadku konfliktu git merge, jakie są generowane pliki BACKUP, BASE, LOCAL i REMOTE?

Aby zobaczyć różnice, które chcę, najpierw znajduję wygenerowane pliki git status, a następnie otwieram nowe terminale i robię vimdiff między parami plików, na których mi zależy:

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

Razem z git mergetooltymi informacjami pomaga WIELU szybko dowiedzieć się, co się dzieje!

Ponadto, nawet gdy uruchomiony jest program Mergetool, możesz po prostu otworzyć plik:

vim main.py

bezpośrednio i edytuj go tam, jeśli uważasz, że będzie to łatwiejsze z większym oknem edytora.

Przejdź bezpośrednio, aby scalić konflikty

Podczas ]cprzeskakiwania do następnego punktu diff wewnątrz vimdiff, nie zawsze występuje tam konflikt scalania.

Aby w tym pomóc, mam w swoim ~/.vimrc:

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

która bezpośrednio wyszukuje konflikty.

git imerge

Może najlepszą opcją jest po prostu zrezygnowanie z używania vimdiff i poleganie na zwykłym vim + git imerge, o którym wspomniano w: Jak mogę się dowiedzieć, które zmiany Git powodują konflikty? ponieważ krzywa uczenia się vimdiff jest denerwująca i nie wykonuje funkcji, których potrzebujemy najbardziej.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
1
Głosowano za. Myślę, że wspomniałem o tym 9 lat temu na stackoverflow.com/a/3052118/6309 . (patrz ostatnia część odpowiedzi)
VonC
@VonC tak, myślę, że wygrałeś ten! XD
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功