Làm cách nào để sử dụng vimdiff để giải quyết xung đột hợp nhất git?


159

Tôi vừa sáp nhập một chi nhánh vào chủ nhân của mình trong git và tôi đã nhận được Automatic merge failed; fix conflicts and then commit the result.Bây giờ tôi đã chạy git mergetoolvà vimdiff mở ra với hình ảnh bên dưới. Tôi không biết cách sử dụng vimdiff. Mỗi bảng ở đây có ý nghĩa gì và tôi nên tiến hành khắc phục xung đột hợp nhất như thế nào?

nhập mô tả hình ảnh ở đây


3
Xem trang này . Nếu đó là những gì bạn có nghĩa là "chính xác", trạng thái hiện tại của mã của bạn nằm ở trên cùng bên trái.
romainl

@romainl Tôi vẫn còn bối rối sau khi đọc nó, các phím tắt là gì và làm cách nào để chọn tệp nào được sử dụng làm nhánh chính?
Cool Guy Yo


Cũng xem: này
skelliam

Câu trả lời:


142

Tất cả bốn bộ đệm cung cấp một cái nhìn khác nhau của cùng một tệp. Bộ đệm trên cùng bên trái (LOCAL) là cách tệp nhìn vào nhánh mục tiêu của bạn (những gì bạn đang hợp nhất vào). Bộ đệm trên cùng bên phải (XÓA) là cách tệp nhìn trong nhánh nguồn của bạn (nơi bạn đang hợp nhất từ ​​đó). Bộ đệm giữa (BASE) là tổ tiên chung của cả hai (vì vậy bạn có thể so sánh cách các phiên bản bên trái và bên phải đã chuyển hướng từ nhau).

Tôi có thể bị nhầm lẫn về điểm sau. Tôi nghĩ nguồn gốc của xung đột hợp nhất là cả hai tệp đã thay đổi cùng một phần của tệp kể từ BASE; LOCAL đã thay đổi các trích dẫn từ gấp đôi thành đơn và REMote đã thực hiện cùng một thay đổi nhưng cũng thay đổi giá trị nền từ màu thành URL. (Tôi nghĩ rằng việc hợp nhất không đủ thông minh để nhận thấy rằng tất cả các thay đổi đối với ĐỊA PHƯƠNG cũng có trong XÓA

Trong mọi trường hợp, bộ đệm dưới cùng chứa tệp mà bạn thực sự có thể chỉnh sửa, một trong những thư mục làm việc của bạn. Bạn có thể thực hiện bất kỳ thay đổi nào bạn muốn; vimđang cho bạn thấy nó khác với các chế độ xem hàng đầu như thế nào, đó là các khu vực mà việc hợp nhất tự động không thể xử lý. Kéo các thay đổi từ ĐỊA PHƯƠNG nếu bạn không muốn các thay đổi XÓA. Kéo các thay đổi từ XÓA nếu bạn thích những thay đổi đó cho các thay đổi ĐỊA PHƯƠNG. Kéo từ BASE nếu bạn nghĩ rằng cả TỪ XA và ĐỊA PHƯƠNG đều sai. Làm một cái gì đó hoàn toàn khác nếu bạn có một ý tưởng tốt hơn! Cuối cùng, những thay đổi bạn thực hiện ở đây là những thay đổi thực sự sẽ được cam kết.


4
Câu hỏi nhanh làm thế nào để tôi lưu trong vim?
Cool Guy Yo

6
:xhoặc :w( :xthoát quá) cộng với 'trở lại'.
Jonathan Leffler

4
Anders: có những công cụ hợp nhất khác mà bạn có thể sử dụng nếu bạn không quen với cách sử dụng vim.
chepner

3
@AndersKitson, vì bạn đang dùng Mac OS X, FileMerge hoàn hảo, miễn phí và đi kèm với XCode.
romainl

8
Tại sao các downvote? Nếu có một cái gì đó thực sự không chính xác, xin vui lòng sửa nó, hoặc ít nhất là chỉ ra nó.
chepner

91

Câu trả lời của @ chepner là tuyệt vời, tôi muốn thêm một số chi tiết về "làm thế nào tôi nên tiến hành khắc phục xung đột hợp nhất" của câu hỏi. Nếu bạn xem xét làm thế nào để thực sự sử dụng vimdiff trong trường hợp này, nó sẽ đi bên dưới.


Đầu tiên, để giải quyết tùy chọn "hủy bỏ mọi thứ" - nếu bạn không muốn sử dụng "vimdiff" và muốn hủy bỏ hợp nhất: nhấn Esc, sau đó nhập :qa!và nhấn Enter. (xem thêm Làm cách nào để thoát trình soạn thảo Vim? ). Git sẽ hỏi bạn nếu hợp nhất hoàn tất, trả lời với n.


Nếu bạn muốn sử dụng vimdiff, đây là một số phím tắt hữu ích. Điều này giả định rằng bạn biết những điều cơ bản về Vim (điều hướng và chế độ chèn / bình thường):

  • điều hướng đến bộ đệm dưới cùng (kết quả hợp nhất): Ctrl-W j
  • điều hướng đến khác tiếp theo với j/ k; hoặc, tốt hơn, sử dụng ] c[ cđể điều hướng đến khác biệt tiếp theo và trước đó tương ứng
  • sử dụng z otrong khi gấp để mở nó, nếu bạn muốn xem thêm ngữ cảnh
  • đối với mỗi khác, theo câu trả lời của @ chepner, bạn có thể lấy mã từ phiên bản cục bộ, từ xa hoặc cơ sở hoặc chỉnh sửa mã và làm lại khi bạn thấy phù hợp
    • để lấy nó từ phiên bản địa phương, hãy sử dụng :diffget LO
    • từ xa :diffget RE
    • từ cơ sở: :diffget BA
    • hoặc, nếu bạn muốn tự chỉnh sửa mã, trước tiên hãy lấy phiên bản từ cục bộ / từ xa / cơ sở, sau đó chuyển sang chế độ chèn và chỉnh sửa phần còn lại
  • Sau khi hoàn thành, lưu kết quả hợp nhất và thoát khỏi tất cả các cửa sổ :wqa
  • thông thường, git phát hiện ra rằng hợp nhất đã được thực hiện và tạo ra cam kết hợp nhất

Dường như không thể thêm các khối xung đột cục bộ và từ xa mà không cần sao chép hoặc các phím tắt tùy chỉnh: /vi/10534/is-there-a-way-to-take-both- khi sử dụng-vim-as-merge-tool là một sự xấu hổ vì add add là một loại xung đột phổ biến như vậy.

Để ngăn vimdiff yêu cầu bạn nhấn enter mỗi khi nó khởi động, hãy thêm vào .vimrc:

set shortmess=Ot

như đã đề cập tại: /vi/771/how-can-i-suppress-the-press-enter-prompt-when-opening-files-in-diff-mode

Bạn có thể tìm kiếm trên Internet các phím tắt vimdiff khác. Tôi đã tìm thấy cái này hữu ích: https://gist.github.com/hyamamoto/7783966


10
Điều này nên được nâng cấp x1000 lần và được chấp nhận như một câu trả lời tốt hơn.
Andrey Portnoy

để nhanh chóng chuyển sang xung đột tiếp theo, chỉ cần tìm kiếm ===. làm "/ ===" và nhập
Apit John Ismail

Xem bài đăng này ( stackoverflow.com/questions/51520705/ Ấn ) nếu có nhiều hơn một trận đấu được tìm thấy bằng cách sử dụng :diffget.
Jason

7

Sự hợp nhất cuối cùng để thay thế vimdiff

Đây là một kiểu nói rất hay, nhưng cuối cùng tôi đã hội tụ thành một vimmer sau khi thử vimdiff.

Để giải quyết xung đột hợp nhất, điều tôi hầu như luôn cần là xem:

  • XA XÔI
  • ĐỊA PHƯƠNG
  • hai khác biệt:
    • khác biệt
    • khác biệt địa phương

để sau đó cố gắng đặt cả hai cùng nhau.

Trong khi vimdiff không hiển thị BASE, LOCAL và REMote trong màn hình:

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

Tôi không biết làm thế nào để làm cho nó hiển thị rõ ràng hai khác biệt mà tôi cần bên cạnh đó bằng cách nhìn phải trái phải rất nhiều lần.

Hơn nữa, ĐỊA PHƯƠNG và XÓA đã được hiển thị trong các dấu xung đột hợp nhất git, vì vậy tôi không thu được nhiều từ một công cụ hiển thị lại chúng.

Do đó, thay vào đó, tôi đã tạo ra "Difftool" nhỏ bé của riêng mình, thứ thực sự cho thấy sự khác biệt mà tôi đã thiếu:

~ / 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 ngược dòng .

Và cài đặt nó với:

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'

Bây giờ, khi bạn làm:

git mergetool -t cirosantilli-mergetool

nó hiển thị hai khác biệt mà tôi muốn trên thiết bị đầu cuối, ví dụ: một cái gì đó cùng:

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

Vì vậy, bạn có thể thấy ở đây hai khác biệt đổ vào thiết bị đầu cuối:

  • RealView_BASE_15560.py đấu với RealView_LOCAL_15560.py
  • RealView_BASE_15560.py đấu với RealView_REMOTE_15560.py

Nếu khác biệt là lớn, tôi sẽ chỉ tìm kiếm với siêu năng lực tmux của mình .

Có, bạn sẽ mất một số phím tắt mà vimdiff cung cấp, nhưng trong việc giải quyết xung đột chung đòi hỏi phải sao chép cẩn thận từ cả hai phiên bản, tôi có thể làm tốt trong phiên vim bình thường với các dấu xung đột git.

Quan sát và khuếch tán các tập tin trong khi vimdiffđang chạy

Trước khi tôi ngồi xuống và tự động thiết lập hoàn hảo với cirosantilli-mergetool, đây là những gì tôi đã làm để có được hai khác biệt tôi cần.

Trong khi git mergetoolđang chạy vimdiff, nếu có xung đột trên một tệp có tên, giả sử main.py, git sẽ tạo các tệp cho mỗi phiên bản, được đặt tên là:

main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

trong cùng thư mục với main.pyvị trí 1367PID của git mergetool, và do đó là một số nguyên "ngẫu nhiên", như đã đề cập tại: Trong xung đột hợp nhất git, các tệp BACKUP, BASE, LOCAL và REMOTE được tạo ra là gì?

Vì vậy, để xem các khác biệt mà tôi muốn, trước tiên tôi tìm các tệp được tạo git statusvà sau đó mở các thiết bị đầu cuối mới và thực hiện một vimdiff giữa các cặp tệp mà tôi quan tâm:

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

Cùng với git mergetool, thông tin này giúp rất nhiều để tìm hiểu những gì đang xảy ra một cách nhanh chóng!

Ngoài ra, ngay cả khi mergetool đang chạy, bạn chỉ có thể mở tệp:

vim main.py

trực tiếp và chỉnh sửa nó ở đó nếu bạn cảm thấy rằng nó sẽ dễ dàng hơn với một cửa sổ soạn thảo lớn hơn.

Nhảy trực tiếp để hợp nhất xung đột

Trong khi ]cnhảy đến điểm khác biệt tiếp theo bên trong vimdiff, không phải lúc nào cũng có xung đột hợp nhất ở đó.

Để giúp với điều này, tôi có trong ~/.vimrc:

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

trong đó tìm thấy các xung đột trực tiếp.

git nhập

Có lẽ lựa chọn tốt nhất là từ bỏ việc sử dụng vimdiff và dựa vào vim + git imerge thông thường đã được đề cập tại: Làm thế nào tôi có thể tìm ra Git nào gây ra xung đột? vì đường cong học tập của vimdiff gây phiền nhiễu và nó không thực hiện các chức năng chúng ta cần nhất.


1
Nâng cao. Tôi nghĩ rằng tôi đã đề cập rằng 9 năm trước trong stackoverflow.com/a/3052118/6309 . (xem phần cuối của câu trả lời)
VonC

@VonC vâng, tôi nghĩ bạn đã thắng giải này! XD
Ciro Santilli 郝海东 冠状 病
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.