Wie verwende ich vimdiff, um einen Git-Merge-Konflikt zu lösen?


159

Ich habe gerade einen Zweig mit meinem Master in Git zusammengeführt und Automatic merge failed; fix conflicts and then commit the result.jetzt habe ich git mergetoolgerannt und vimdiff mit dem Bild unten geöffnet. Ich weiß nicht, wie man Vimdiff benutzt. Was bedeutet jedes Panel hier und wie soll ich vorgehen, um den Zusammenführungskonflikt zu beheben?

Geben Sie hier die Bildbeschreibung ein


3
Siehe diese Seite . Wenn Sie das mit "richtig" meinen, befindet sich der aktuelle Status Ihres Codes oben links.
Romainl

@romainl Ich bin immer noch verwirrt, nachdem ich das gelesen habe. Was sind die Verknüpfungen und wie wähle ich die Datei aus, die als Hauptzweig verwendet werden soll?
Cooler Kerl Yo


Siehe auch: this
skelliam

Antworten:


142

Alle vier Puffer bieten eine unterschiedliche Ansicht derselben Datei. Der obere linke Puffer (LOCAL) gibt an, wie die Datei in Ihrem Zielzweig aussah (in was Sie zusammenführen). Der obere rechte Puffer (REMOTE) gibt an, wie die Datei in Ihrem Quellzweig aussah (von wo aus Sie zusammenführen). Der mittlere Puffer (BASE) ist der gemeinsame Vorfahr der beiden (Sie können also vergleichen, wie die linke und die rechte Version voneinander abweichen).

Ich kann mich in folgendem Punkt irren. Ich denke, die Ursache des Zusammenführungskonflikts ist, dass beide Dateien seit BASE denselben Teil der Datei geändert haben. LOCAL hat die Anführungszeichen von doppelt in einfach geändert, und REMOTE hat dieselbe Änderung vorgenommen, aber auch den Hintergrundwert von einer Farbe in eine URL geändert. (Ich denke, die Zusammenführung ist nicht klug genug, um festzustellen, dass alle Änderungen an LOCAL auch in REMOTE vorhanden sind. Es ist nur bekannt, dass LOCAL seit BASE an denselben Stellen wie REMOTE Änderungen vorgenommen hat.)

In jedem Fall enthält der untere Puffer die Datei, die Sie tatsächlich bearbeiten können - die Datei, die sich in Ihrem Arbeitsverzeichnis befindet. Sie können beliebige Änderungen vornehmen. vimzeigt Ihnen, wie es sich von den einzelnen Draufsichten unterscheidet. Dies sind die Bereiche, die bei der automatischen Zusammenführung nicht behandelt werden konnten. Ziehen Sie Änderungen aus LOCAL, wenn Sie die REMOTE-Änderungen nicht möchten. Ziehen Sie Änderungen aus FERN, wenn Sie diese den LOKALEN Änderungen vorziehen. Ziehen Sie von BASE ab, wenn Sie der Meinung sind, dass sowohl REMOTE als auch LOCAL falsch sind. Mach etwas ganz anderes, wenn du eine bessere Idee hast! Letztendlich sind die Änderungen, die Sie hier vornehmen, diejenigen, die tatsächlich festgeschrieben werden.


4
Kurze Frage, wie ich in vim speichere?
Cooler Kerl Yo

6
:xoder :w(auch :xExits) plus 'return'.
Jonathan Leffler

4
Anders: Es gibt andere Zusammenführungswerkzeuge, die Sie verwenden können, wenn Sie nicht mit der Verwendung vertraut sind vim.
Chepner

3
@AndersKitson, da Sie unter Mac OS X arbeiten, ist FileMerge perfekt, kostenlos und wird mit XCode geliefert.
Romainl

8
Warum das Downvote? Wenn etwas sachlich nicht stimmt, beheben Sie es bitte oder weisen Sie zumindest darauf hin.
Chepner

91

Die Antwort von @ chepner ist großartig. Ich möchte einige Details zum Teil "Wie soll ich vorgehen, um den Zusammenführungskonflikt zu beheben?" der Frage hinzufügen. Wenn Sie sich ansehen, wie Sie vimdiff in diesem Fall tatsächlich verwenden, finden Sie weiter unten Informationen.


Um zunächst die Option "Alles abbrechen" anzusprechen - wenn Sie "vimdiff" nicht verwenden und die Zusammenführung abbrechen möchten: Drücken Sie Esc, geben Sie ein :qa!und drücken Sie Enter. (Siehe auch Wie beende ich den Vim-Editor? ) Git wird Sie fragen, ob die Zusammenführung abgeschlossen ist. Antworten Sie mit n.


Wenn Sie vimdiff verwenden möchten, finden Sie hier einige nützliche Verknüpfungen. Dies setzt voraus, dass Sie die Grundlagen von Vim kennen (Navigation und Einfügen / Normalmodus):

  • Navigieren Sie zum unteren Puffer (Ergebnis zusammenführen): Ctrl-W j
  • Navigieren Sie mit j/ zum nächsten Diff k. oder besser, verwenden Sie ] cund [ c, um zum nächsten bzw. vorherigen Diff zu navigieren
  • Verwenden Sie diese z oOption, um sie zu öffnen, wenn Sie mehr Kontext sehen möchten
  • Für jedes Diff können Sie gemäß der Antwort von @ chepner entweder den Code von einer lokalen, Remote- oder Basisversion abrufen oder ihn bearbeiten und nach Belieben wiederholen
    • Verwenden Sie, um es von der lokalen Version zu erhalten :diffget LO
    • von der Fernbedienung: :diffget RE
    • von der Basis: :diffget BA
    • Wenn Sie den Code selbst bearbeiten möchten, rufen Sie zuerst eine Version von local / remote / base ab, wechseln Sie dann in den Einfügemodus und bearbeiten Sie den Rest
  • Speichern Sie anschließend das Zusammenführungsergebnis und beenden Sie alle Fenster :wqa
  • Normalerweise erkennt git, dass die Zusammenführung durchgeführt wurde, und erstellt das Zusammenführungs-Commit

Es scheint nicht möglich zu sein, sowohl lokale als auch Remote-Konflikt-Hunks ohne Einfügen von Kopien oder benutzerdefinierte Verknüpfungen hinzuzufügen: /vi/10534/is-there-a-way-to-take-both- Wenn Sie vim-as-merge-tool verwenden , ist das eine Schande, da add add ein so häufiger Konflikttyp ist.

Um zu verhindern, dass vimdiff Sie bei jedem Start auffordert, die Eingabetaste zu drücken, fügen Sie Folgendes hinzu .vimrc:

set shortmess=Ot

wie erwähnt unter: /vi/771/how-can-i-suppress-the-press-enter-prompt-when-opening-files-in-diff-mode

Sie können im Internet nach anderen vimdiff-Verknüpfungen suchen. Ich fand dieses nützlich: https://gist.github.com/hyamamoto/7783966


10
Dies sollte x1000-mal hochgestuft und als bessere Antwort akzeptiert werden.
Andrey Portnoy

Um schnell zum nächsten Konflikt zu gelangen, suchen Sie einfach nach ===. mach "/ ===" und gib ein
Apit John Ismail

Siehe diesen Beitrag ( stackoverflow.com/questions/51520705/… ), wenn mehr als eine Übereinstimmung mit gefunden wurde :diffget.
Jason

7

Das ultimative Mergetool, um vimdiff zu ersetzen

Das ist eine Art Augenzwinkern, aber es ist das, worauf ich mich nach dem Versuch von vimdiff als Vimmer konzentriert habe.

Um einen Zusammenführungskonflikt zu lösen, muss ich fast immer Folgendes sehen:

  • FERNBEDIENUNG
  • LOKAL
  • zwei Unterschiede:
    • diff BASE REMOTE
    • diff BASE LOCAL

um dann zu versuchen, beide zusammenzufügen.

Während vimdiff BASE, LOCAL und REMOTE auf dem Bildschirm anzeigt:

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

Ich weiß nicht, wie ich die beiden Unterschiede, die ich außerdem brauche, deutlich machen kann, indem ich ein paar Mal nach rechts, links, rechts und links schaue.

Außerdem sind LOCAL und REMOTE bereits in den Konfliktmarkierungen für Git-Merge sichtbar, sodass ich nicht so viel von einem Tool profitiere, das sie erneut anzeigt.

Deshalb habe ich stattdessen mein eigenes kleines "Difftool" erstellt, das tatsächlich die Unterschiede zeigt, die mir fehlten:

~ / 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 stromaufwärts .

Und installieren Sie es mit:

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'

Wenn Sie dies tun:

git mergetool -t cirosantilli-mergetool

Es zeigt die beiden Unterschiede, die ich auf dem Terminal haben möchte, z. B. etwas entlang:

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

Sie können hier also die beiden im Terminal abgelegten Diffs sehen:

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

Wenn die Unterschiede groß sind, suche ich einfach nach meinen tmux-Superkräften .

Ja, Sie verlieren zwar einige von vimdiff bereitgestellte Verknüpfungen, aber im Allgemeinen erfordert das Lösen von Konflikten ein sorgfältiges Kopieren und Einfügen aus beiden Versionen, was ich in einer normalen vim-Sitzung mit den Git-Konfliktmarkierungen problemlos tun kann.

Beobachten und Verteilen von Dateien während der vimdiffAusführung

Bevor ich mich cirosantilli-mergetoolhinsetzte und mein perfektes Setup mit automatisierte , tat ich Folgendes, um die beiden Unterschiede zu erreichen, die ich brauchte.

Wenn während der git mergetoolAusführung vimdiffein Konflikt mit einer Datei mit dem Namen z. B. main.pyauftritt, generiert git Dateien für jede der folgenden Versionen:

main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

im selben Verzeichnis wie main.pywo 1367ist die PID von git mergetool und daher eine "zufällige" Ganzzahl, wie unter: Welche BACKUP-, BASE-, LOCAL- und REMOTE-Dateien werden in einem Git-Merge-Konflikt generiert?

Um die gewünschten Unterschiede zu sehen, finde ich zuerst die generierten Dateien mit git status, öffne dann neue Terminals und mache einen Vimdiff zwischen den Dateipaaren, die mir wichtig sind:

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

Zusammen mit git mergetoolhelfen diese Informationen VIEL, schnell herauszufinden, was los ist!

Auch wenn mergetool ausgeführt wird, können Sie die Datei einfach öffnen:

vim main.py

direkt und bearbeiten Sie es dort, wenn Sie der Meinung sind, dass es mit einem größeren Editorfenster einfacher wird.

Springe direkt, um Konflikte zusammenzuführen

Während ]cin vimdiff zum nächsten Diff-Punkt gesprungen wird, gibt es dort nicht immer einen Zusammenführungskonflikt.

Um dies zu unterstützen, habe ich in meinem ~/.vimrc:

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

das findet die Konflikte direkt.

git imerge

Vielleicht ist die beste Option, einfach auf die Verwendung von vimdiff zu verzichten und sich auf reguläres vim + git imerge zu verlassen, das unter folgendem erwähnt wurde: Wie kann ich herausfinden, welche Git-Commits Konflikte verursachen? da die Lernkurve von vimdiff ärgerlich ist und nicht die Funktionen erfüllt, die wir am meisten benötigen.


1
Upvoted. Ich glaube, ich habe das vor 9 Jahren in stackoverflow.com/a/3052118/6309 erwähnt . (siehe den letzten Teil der Antwort)
VonC

@VonC ja, ich denke du hast diesen gewonnen! XD
Ciro Santilli 法轮功 冠状 病 六四.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.