ฉันจะใช้ vimdiff เพื่อแก้ไขข้อขัดแย้ง git merge ได้อย่างไร


159

ฉันเพิ่งรวมสาขากับเจ้านายของฉันและฉันได้Automatic merge failed; fix conflicts and then commit the result.ตอนนี้ฉันวิ่งgit mergetoolและ vimdiff เปิดด้วยภาพด้านล่าง ฉันไม่รู้วิธีใช้ vimdiff แต่ละแผงที่นี่หมายถึงอะไรและฉันควรดำเนินการอย่างไรเพื่อแก้ไขข้อขัดแย้งในการผสาน

ป้อนคำอธิบายรูปภาพที่นี่


3
ดูหน้านี้ หากนั่นคือสิ่งที่คุณหมายถึงโดย "ถูกต้อง" สถานะปัจจุบันของรหัสของคุณอยู่ที่ด้านบนซ้าย
romainl

@ ฉีดฉันยังคงสับสนหลังจากอ่านสิ่งนั้นทางลัดคืออะไรและฉันจะเลือกไฟล์ที่จะใช้เป็นสาขาหลักได้อย่างไร
ผู้ชายที่ยอดเยี่ยม Yo


ดูเพิ่มเติมที่นี่
skelliam

คำตอบ:


142

บัฟเฟอร์ทั้งสี่ให้มุมมองที่แตกต่างกันของไฟล์เดียวกัน บัฟเฟอร์ซ้ายบน (LOCAL) เป็นวิธีที่ไฟล์ดูในสาขาเป้าหมายของคุณ (สิ่งที่คุณรวมเข้าด้วยกัน) บัฟเฟอร์ด้านขวาบน (REMOTE) คือวิธีที่ไฟล์ค้นหาในสาขาต้นทางของคุณ (ซึ่งคุณกำลังผสานจาก) middle buffer (BASE) เป็นบรรพบุรุษร่วมกันของทั้งสอง (เพื่อให้คุณสามารถเปรียบเทียบว่ารุ่นซ้ายและขวาแยกจากกันอย่างไร)

ฉันอาจเข้าใจผิดในประเด็นต่อไปนี้ ฉันคิดว่าแหล่งที่มาของความขัดแย้งผสานคือไฟล์ทั้งสองมีการเปลี่ยนแปลงส่วนเดียวกันของไฟล์ตั้งแต่ BASE; LOCAL เปลี่ยนราคาจาก double เป็น single และ REMOTE ทำการเปลี่ยนแปลงเดียวกัน แต่เปลี่ยนค่าพื้นหลังจากสีเป็น URL (ฉันคิดว่าการผสานไม่ฉลาดพอที่จะสังเกตเห็นว่าการเปลี่ยนแปลงทั้งหมดของ LOCAL นั้นมีอยู่ใน REMOTE เช่นกัน แต่เพิ่งรู้ว่า LOCAL ได้ทำการเปลี่ยนแปลงตั้งแต่ฐานในสถานที่เดียวกับที่ REMOTE มี)

ไม่ว่าในกรณีใดบัฟเฟอร์ด้านล่างมีไฟล์ที่คุณสามารถแก้ไขได้จริงซึ่งเป็นไฟล์ที่อยู่ในไดเรกทอรีทำงานของคุณ คุณสามารถทำการเปลี่ยนแปลงใด ๆ ที่คุณต้องการ; vimกำลังแสดงให้คุณเห็นถึงความแตกต่างจากมุมมองด้านบนแต่ละอันซึ่งเป็นพื้นที่ที่การผสานอัตโนมัติไม่สามารถจัดการได้ ดึงการเปลี่ยนแปลงจาก LOCAL หากคุณไม่ต้องการให้การเปลี่ยนแปลงระยะไกล ดึงการเปลี่ยนแปลงจาก REMOTE หากคุณต้องการการเปลี่ยนแปลงแบบ LOCAL ดึงออกจากฐานถ้าคุณคิดว่าทั้งระยะไกลและในพื้นที่ผิด ทำสิ่งที่แตกต่างอย่างสิ้นเชิงถ้าคุณมีความคิดที่ดีกว่า! ในท้ายที่สุดการเปลี่ยนแปลงที่คุณทำที่นี่เป็นสิ่งที่จะเกิดขึ้นจริง


4
คำถามด่วนฉันจะบันทึกเป็นกลุ่มได้อย่างไร
ผู้ชายเย็น Yo

6
:xหรือ:w( :xออกด้วย) บวกกับ 'return'
Jonathan Leffler

4
Anders: มีเครื่องมือผสานอื่น ๆ vimที่คุณสามารถใช้หากคุณไม่คุ้นเคยกับวิธีการใช้งาน
chepner

3
@AndersKitson เนื่องจากคุณอยู่ใน Mac OS X FileMerge นั้นสมบูรณ์แบบฟรีและมาพร้อมกับ XCode
romainl

8
ทำไมต้องลงคะแนน? หากมีสิ่งที่ไม่ถูกต้องตามข้อเท็จจริงโปรดแก้ไขหรืออย่างน้อยก็ชี้ให้เห็น
chepner

91

@ คำตอบของ chepner ดีมากฉันต้องการเพิ่มรายละเอียดบางส่วนเกี่ยวกับ "ฉันจะดำเนินการแก้ไขข้อขัดแย้งผสาน" ได้อย่างไร หากคุณดูว่าจะใช้ vimdiff อย่างไรในกรณีนี้มันจะอยู่ด้านล่าง


ครั้งแรกเพื่อที่อยู่ "ยกเลิกทุกอย่างที่" ตัวเลือก - ถ้าคุณไม่ต้องการที่จะใช้ "vimdiff" และต้องการที่จะยกเลิกการผสาน: กดEscแล้วพิมพ์และการตี:qa! Enter(ดูเพิ่มเติมฉันจะออกจากโปรแกรมแก้ไข Vim ได้อย่างไร ) Git nจะถามคุณว่าการผสานเสร็จสมบูรณ์ตอบกลับด้วย


หากคุณต้องการใช้ vimdiff ต่อไปนี้เป็นทางลัดที่มีประโยชน์ สิ่งนี้จะถือว่าคุณรู้พื้นฐานของ Vim (การนำทางและโหมดแทรก / ปกติ):

  • นำทางไปยังบัฟเฟอร์ด้านล่าง (ผลการรวม): Ctrl-W j
  • นำทางไปยัง diff ถัดไปด้วยj/ k; หรือดีกว่าใช้] cและ[ cเพื่อไปยังส่วนต่างถัดไปและก่อนหน้าตามลำดับ
  • ใช้เวลาz oสักครู่เพื่อเปิดหากคุณต้องการดูบริบทเพิ่มเติม
  • สำหรับแต่ละ diff ตามคำตอบของ @ chepner คุณสามารถรับรหัสจากเวอร์ชันโลคัลรีโมตหรือฐานหรือแก้ไขและทำซ้ำตามที่เห็นสมควร
    • เพื่อรับจากเวอร์ชันในเครื่องให้ใช้ :diffget LO
    • จากระยะไกล: :diffget RE
    • จากฐาน: :diffget BA
    • หรือหากคุณต้องการแก้ไขรหัสด้วยตัวเองให้รับรุ่นจาก local / remote / base ก่อนจากนั้นไปที่โหมดแทรกและแก้ไขส่วนที่เหลือ
  • เสร็จแล้วบันทึกผลการรวมและออกจากหน้าต่างทั้งหมด :wqa
  • โดยปกติคอมไพล์ตรวจพบว่ามีการรวมและสร้างการคอมมิชชัน

ดูเหมือนว่าจะไม่สามารถเพิ่มทั้งความขัดแย้งในพื้นที่และระยะไกลโดยไม่ต้องคัดลอกการวางหรือทางลัดที่กำหนดเอง: /vi/10534/is-there-a-way-to-take-both- เมื่อใช้ vim-as-merge-toolซึ่งเป็นความอัปยศเนื่องจากการเพิ่มการเพิ่มนั้นเป็นประเภทความขัดแย้งทั่วไป

เพื่อป้องกันไม่ให้ vimdiff ขอให้คุณกด Enter ทุกครั้งที่เริ่มต้นให้เพิ่มใน.vimrc:

set shortmess=Ot

ตามที่กล่าวไว้ที่: /vi/771/how-can-i-suppress-the-press-enter-prompt-when-opening-files-in-diff-mode

คุณสามารถค้นหาทางลัด vimdiff ทางอินเทอร์เน็ตได้ ฉันพบสิ่งนี้มีประโยชน์: https://gist.github.com/hyamamoto/7783966


10
นี่ควรได้รับการอัปเกรดสูงกว่า 1,000 ครั้งและยอมรับว่าเป็นคำตอบที่ดีกว่า
Andrey Portnoy

หากต้องการข้ามไปยังความขัดแย้งครั้งต่อไปเพียงแค่ค้นหา === ทำ "/ ===" แล้วป้อน
Apit John Ismail

ดูโพสต์นี้ ( stackoverflow.com/questions/51520705/… ) หากพบการแข่งขันมากกว่าหนึ่ง:diffgetรายการ
เจสัน

7

mergetool ที่ดีที่สุดเพื่อแทนที่ vimdiff

นี่เป็นลิ้นแบบแก้ม แต่มันก็เป็นสิ่งที่ฉันจบลงด้วยการมารวมตัวกันเป็นกลุ่มหลังจากลอง vimdiff

เมื่อต้องการแก้ไขข้อขัดแย้งในการผสานสิ่งที่ฉันต้องได้รับคือ:

  • REMOTE
  • ท้องถิ่น
  • สอง diffs:
    • diff BASE REMOTE
    • diff BASE LOCAL

เพื่อลองใส่ทั้งคู่เข้าด้วยกัน

ในขณะที่ vimdiff แสดง BASE, LOCAL และ REMOTE ในหน้าจอ:

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

ฉันไม่รู้ว่าจะทำให้มันแสดงให้เห็นอย่างชัดเจนถึงสองสิ่งที่ฉันต้องการได้อย่างไรโดยดูจากซ้ายขวาไปทางซ้ายหลายครั้ง

นอกจากนี้ LOCAL และ REMOTE จะปรากฏอยู่ในเครื่องหมายความขัดแย้งผสานแล้วดังนั้นฉันจึงไม่ได้รับมากจากเครื่องมือที่แสดงให้เห็นอีกครั้ง

ดังนั้นฉันจึงสร้าง "difftool" ตัวเล็ก ๆ ของฉันที่แสดงให้เห็นถึงความแตกต่างที่ฉันหายไป:

~ / 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 ต้นน้ำ

และติดตั้งด้วย:

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'

ตอนนี้เมื่อคุณ:

git mergetool -t cirosantilli-mergetool

มันแสดงให้เห็นถึงความแตกต่างสองอย่างที่ฉันต้องการบนเครื่องเทอร์มินัลเช่นบางอย่างพร้อม:

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

ดังนั้นคุณสามารถดูที่นี่ทั้งสองแตกต่างทิ้งลงในสถานี:

  • RealView_BASE_15560.py VS RealView_LOCAL_15560.py
  • RealView_BASE_15560.py VS RealView_REMOTE_15560.py

ถ้าดิฟแตกต่างกันมากฉันจะค้นหาด้วยพลังพิเศษของ tmux

ใช่คุณทำทางลัดบางอย่างที่ vimdiff ให้ไว้ แต่โดยทั่วไปแล้วการแก้ปัญหาต้องใช้การคัดลอกอย่างระมัดระวังจากทั้งสองเวอร์ชันซึ่งฉันสามารถทำได้ดีในเซสชัน vim ปกติด้วยเครื่องหมายความขัดแย้ง git

การสังเกตและการกระจายไฟล์ในขณะที่vimdiffกำลังทำงาน

ก่อนที่ฉันจะนั่งลงและตั้งค่าที่สมบูรณ์แบบอัตโนมัติด้วยcirosantilli-mergetoolนี่คือสิ่งที่ฉันกำลังทำเพื่อให้ได้ทั้งสองอย่างที่ฉันต้องการ

ในขณะที่git mergetoolกำลังทำงานvimdiffหากมีข้อขัดแย้งในไฟล์ชื่อ, พูดmain.py,, git สร้างไฟล์สำหรับแต่ละรุ่นชื่อเป็น:

main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

ในไดเรกทอรีเดียวกันกับmain.pyที่1367เป็น PID ของ git mergetool และดังนั้นจึงเป็นจำนวนเต็ม "สุ่ม" ตามที่กล่าวไว้ที่: ในความขัดแย้งผสาน git ไฟล์ BACKUP, BASE, LOCAL และ REMOTE ที่ถูกสร้างขึ้นคืออะไร

ดังนั้นเมื่อต้องการดูความแตกต่างที่ฉันต้องการฉันต้องหาไฟล์ที่สร้างขึ้นgit statusก่อนแล้วจึงเปิดเทอร์มินัลใหม่และทำ vimdiff ระหว่างคู่ของไฟล์ที่ฉันสนใจ:

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

ร่วมกับgit mergetoolข้อมูลนี้ช่วยให้มากที่จะคิดออกสิ่งที่เกิดขึ้นได้อย่างรวดเร็ว!

นอกจากนี้แม้ว่า mergetool จะทำงานอยู่คุณก็สามารถเปิดไฟล์ได้:

vim main.py

โดยตรงและแก้ไขที่นั่นถ้าคุณรู้สึกว่ามันจะง่ายขึ้นด้วยหน้าต่างตัวแก้ไขขนาดใหญ่

ข้ามโดยตรงเพื่อรวมความขัดแย้ง

ในขณะที่]cกระโดดไปยังจุดต่างถัดไปภายใน vimdiff มันจะไม่ขัดแย้งกับการรวม

เพื่อช่วยในเรื่องนี้ฉันมีใน~/.vimrc:

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

ซึ่งพบข้อขัดแย้งโดยตรง

ger imerge

บางทีตัวเลือกที่ดีที่สุดคือเพียงแค่ยอมแพ้ในการใช้ vimdiff และพึ่งพา vim + git imergeซึ่งถูกกล่าวถึงที่: ฉันจะทราบได้อย่างไรว่า Git ที่ก่อให้เกิดความขัดแย้งกันอย่างไร เนื่องจากช่วงการเรียนรู้ของ vimdiff นั้นน่ารำคาญและมันไม่ได้ทำหน้าที่ที่เราต้องการมากที่สุด


1
upvoted ฉันคิดว่าฉันบอกว่า 9 ปีที่ผ่านมาในstackoverflow.com/a/3052118/6309 (ดูส่วนสุดท้ายของคำตอบ)
VonC

@VonC ใช่ฉันคิดว่าคุณชนะเกมนี้! XD
Ciro Santilli 法轮功冠状病六四事件法轮功
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.