Bagaimana cara saya menggunakan vimdiff untuk menyelesaikan konflik git merge?

159

Saya baru saja menggabungkan cabang ke master saya di git dan saya dapatkan Automatic merge failed; fix conflicts and then commit the result.Sekarang saya berlari git mergetooldan Viffiff dibuka dengan gambar di bawah ini. Saya tidak tahu cara menggunakan vimdiff. Apa arti setiap panel di sini dan bagaimana saya harus melanjutkan untuk memperbaiki konflik gabungan?

masukkan deskripsi gambar di sini

Cool Guy Yo
sumber
3
Lihat halaman ini . Jika itu yang Anda maksud dengan "benar", status kode Anda saat ini ada di kiri atas.
romainl
@romainl Saya masih bingung setelah membaca itu, apa pintasannya dan bagaimana saya memilih file mana yang akan digunakan sebagai cabang utama?
Cool Guy Yo
2
@Danny http://www.rosipov.com/blog/use-vimdiff-as-git-mergetool/ adalah yang bagus.
ᴠɪɴᴄᴇɴᴛ
Lihat juga: ini
skelliam

Jawaban:

142

Keempat buffer memberikan tampilan berbeda dari file yang sama. Buffer kiri atas (LOCAL) adalah bagaimana file terlihat di cabang target Anda (apa yang Anda gabungkan). Buffer kanan atas (REMOTE) adalah bagaimana file terlihat di cabang sumber Anda (tempat Anda bergabung). Penyangga tengah (BASE) adalah leluhur yang sama dari keduanya (sehingga Anda dapat membandingkan bagaimana versi kiri dan kanan berbeda satu sama lain).

Saya mungkin salah pada poin berikut. Saya pikir sumber konflik gabungan adalah bahwa kedua file telah mengubah bagian file yang sama sejak DASAR; LOCAL telah mengubah kuotasi dari dua kali lipat menjadi tunggal, dan REMOTE telah melakukan perubahan yang sama tetapi juga mengubah nilai latar belakang dari warna menjadi URL. (Saya pikir penggabungan ini tidak cukup pintar untuk memperhatikan bahwa semua perubahan pada LOCAL juga ada di REMOTE; ia hanya tahu bahwa LOCAL telah membuat perubahan sejak DASAR di tempat yang sama dengan REMOTE).

Bagaimanapun, buffer bawah berisi file yang benar-benar dapat Anda edit — file yang ada di direktori kerja Anda. Anda dapat membuat perubahan apa pun yang Anda suka; vimmenunjukkan kepada Anda perbedaannya dari setiap tampilan teratas, yang merupakan area yang tidak dapat ditangani oleh penggabungan otomatis. Tarik perubahan dari LOCAL jika Anda tidak ingin perubahan REMOTE. Tarik perubahan dari REMOTE jika Anda lebih suka perubahan LOCAL. Tarik dari BASE jika Anda berpikir bahwa REMOTE dan LOCAL salah. Lakukan sesuatu yang sama sekali berbeda jika Anda memiliki ide yang lebih baik! Pada akhirnya, perubahan yang Anda lakukan di sini adalah yang benar-benar akan dilakukan.

chepner
sumber
4
Pertanyaan cepat bagaimana cara menyimpan dalam vim?
Cool Guy Yo
6
:xatau :w( :xkeluar juga) plus 'kembali'.
Jonathan Leffler
4
Anders: ada alat gabungan lainnya yang bisa Anda gunakan jika Anda tidak terbiasa dengan cara menggunakannya vim.
chepner
3
@AndersKitson, karena Anda menggunakan Mac OS X, FileMerge sempurna, gratis dan dilengkapi dengan XCode.
romainl
8
Mengapa downvote? Jika ada sesuatu yang salah secara faktual, harap perbaiki, atau setidaknya tunjukkan.
chepner
91

@ chepner jawabannya bagus, saya ingin menambahkan beberapa detail pada "bagaimana saya melanjutkan untuk memperbaiki konflik gabungan" bagian dari pertanyaan. Jika Anda melihat bagaimana cara benar-benar menggunakan vimdiff dalam kasus ini, ini berlaku di bawah.


Pertama, untuk mengatasi opsi "batalkan semuanya" - jika Anda tidak ingin menggunakan "vimdiff" dan ingin membatalkan penggabungan: tekan Esc, lalu ketik :qa!dan tekan Enter. (lihat juga Bagaimana cara keluar dari editor Vim? ). Git akan bertanya apakah penggabungan telah selesai, balas dengan n.


Jika Anda ingin menggunakan vimdiff, berikut adalah beberapa cara pintas yang bermanfaat. Ini mengasumsikan Anda tahu dasar-dasar Vim (navigasi dan masukkan / mode normal):

  • arahkan ke buffer bawah (hasil gabungan): Ctrl-W j
  • arahkan ke perbedaan berikutnya dengan j/ k; atau, lebih baik, gunakan ] cdan [ cuntuk bernavigasi ke diff berikutnya dan sebelumnya masing-masing
  • gunakan z osaat di flip untuk membukanya, jika Anda ingin melihat lebih banyak konteks
  • untuk setiap perbedaan, sesuai jawaban @ chepner, Anda bisa mendapatkan kode dari versi lokal, jarak jauh atau basis, atau mengeditnya dan mengulangnya sesuai keinginan Anda
    • untuk mendapatkannya dari versi lokal, gunakan :diffget LO
    • dari jarak jauh: :diffget RE
    • dari basis: :diffget BA
    • atau, jika Anda ingin mengedit kode sendiri, dapatkan versi dari local / remote / base terlebih dahulu, lalu pergi ke mode insert dan edit sisanya.
  • setelah selesai, simpan hasil gabungan, dan tutup semua jendela :wqa
  • biasanya, git mendeteksi bahwa gabungan dibuat dan menciptakan komit gabungan

Tampaknya tidak mungkin untuk menambahkan bakhil konflik lokal dan jarak jauh tanpa menempelkan salinan atau pintasan khusus: /vi/10534/is-there-a-wayway-to-take-both- when-using-vim-as-merge-tool yang memalukan karena add add adalah tipe konflik yang umum.

Agar vimdiff tidak meminta Anda menekan enter setiap kali dimulai, tambahkan ke .vimrc:

set shortmess=Ot

seperti yang disebutkan di: /vi/771/how-can-i-suppress-the-press-enter-prompt-when-opening-files-in-diff-mode

Anda dapat mencari di Internet untuk pintasan vimdiff lainnya. Saya menemukan ini berguna: https://gist.github.com/hyamamoto/7783966

Timur
sumber
10
Ini harus ditingkatkan x1000 kali dan diterima sebagai jawaban yang lebih baik.
Andrey Portnoy
untuk melompat cepat ke konflik berikutnya, lakukan pencarian untuk ===. lakukan "/ ===" dan masukkan
Apit John Ismail
Lihat posting ini ( stackoverflow.com/questions/51520705/… ) jika lebih dari satu kecocokan ditemukan menggunakan :diffget.
Jason
7

The mergetool utama untuk menggantikan vimdiff

Ini semacam lidah-di-pipi, tetapi akhirnya saya bertemu sebagai seorang vimmer setelah mencoba vimdiff.

Untuk menyelesaikan konflik gabungan, yang hampir selalu saya butuhkan adalah melihat:

  • TERPENCIL
  • LOKAL
  • dua perbedaan:
    • beda BASE REMOTE
    • berbeda BASE LOCAL

untuk kemudian mencoba menyatukan keduanya.

Sementara vimdiff menampilkan BASE, LOCAL dan REMOTE di layar:

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

Saya tidak tahu bagaimana membuatnya dengan jelas menunjukkan dua perbedaan yang saya butuhkan selain dengan melihat ke kiri kanan ke kiri beberapa kali.

Selain itu, LOCAL dan REMOTE sudah terlihat di penanda konflik git merge, jadi saya tidak mendapatkan banyak dari alat yang menunjukkan mereka lagi.

Karena itu, saya malah membuat "difftool" kecil saya sendiri yang sebenarnya menunjukkan diffs yang saya lewatkan:

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

Dan instal dengan:

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'

Sekarang, ketika Anda melakukannya:

git mergetool -t cirosantilli-mergetool

ini menunjukkan dua perbedaan yang saya inginkan di terminal, mis. sesuatu bersama:

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

Jadi Anda bisa lihat di sini dua diff yang dibuang ke terminal:

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

Jika perbedaannya besar, saya hanya akan mencari dengan kekuatan super tmux saya .

Ya, Anda kehilangan beberapa pintasan yang disediakan vimdiff, tetapi secara umum penyelesaian konflik memerlukan penyalinan yang hati-hati dari kedua versi, yang dapat saya lakukan dengan baik di dalam sesi vim normal dengan spidol git.

Mengamati dan membedakan file saat vimdiffsedang berjalan

Sebelum saya duduk dan otomatis setup sempurna saya dengan cirosantilli-mergetool , inilah yang saya lakukan untuk mendapatkan dua perbedaan yang saya butuhkan.

Ketika git mergetoolsedang berjalan vimdiff, jika ada konflik pada file bernama, katakan main.py,, git menghasilkan file untuk setiap versi, dinamai sebagai:

main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

di direktori yang sama seperti main.pydi mana 1367adalah PID dari mergetool git, dan karena itu "acak" integer, seperti yang disebutkan di: Dalam gabungan konflik git, apa CADANGAN, BASE, LOKAL, dan file REMOTE yang dihasilkan?

Jadi, untuk melihat perbedaan yang saya inginkan, saya pertama-tama menemukan file yang dihasilkan git status, dan kemudian membuka terminal baru dan melakukan vimdiff antara pasangan file yang saya pedulikan:

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

Bersama dengan git mergetool , informasi ini membantu BANYAK untuk mencari tahu apa yang sedang terjadi dengan cepat!

Juga, bahkan ketika mergetool sedang berjalan, Anda bisa membuka file:

vim main.py

langsung dan edit di sana jika Anda merasa akan lebih mudah dengan jendela editor yang lebih besar.

Langsung langsung untuk menggabungkan konflik

Sementara ]cmelompat ke titik diff berikutnya di dalam vimdiff, tidak selalu ada konflik gabungan di sana.

Untuk membantu ini, saya miliki di ~/.vimrc:

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

yang menemukan konflik secara langsung.

git imerge

Mungkin pilihan terbaik adalah menyerah menggunakan vimdiff dan mengandalkan vim + git imerge reguler yang disebutkan di: Bagaimana cara mengetahui Git yang melakukan konflik? karena kurva belajar vimdiff mengganggu, dan itu tidak melakukan fungsi yang paling kita butuhkan.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
1
Terpilih. Saya pikir saya sebutkan itu 9 tahun yang lalu di stackoverflow.com/a/3052118/6309 . (lihat bagian terakhir dari jawabannya)
VonC
@VonC ya, saya pikir Anda memenangkan yang ini! XD
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功