Як використовувати vimdiff для вирішення конфлікту git merge?


159

Я просто з’єднав гілку свого господаря в git, і я отримав Automatic merge failed; fix conflicts and then commit the result.Тепер я побіг git mergetoolі vimdiff відкрив із зображенням нижче. Я не знаю, як використовувати vimdiff. Що тут означає кожна панель і як слід діяти, щоб виправити конфлікт злиття?

введіть тут опис зображення


3
Дивіться цю сторінку . Якщо це ви маєте на увазі під "правильним", поточний стан вашого коду знаходиться вгорі зліва.
romainl

@romainl Я все ще плутаюся, прочитавши це, що таке ярлики і як я можу вибрати який файл використовувати як основну гілку?
Cool Guy Yo


Також дивіться: це
skelliam

Відповіді:


142

Усі чотири буфери забезпечують різний вигляд одного і того ж файлу. Лівий верхній буфер (LOCAL) - це те, як виглядав файл у вашій цільовій гілці (у що ви зливаєтесь). Правий верхній буфер (REMOTE) - це як виглядав файл у вашій гілці джерела (звідки ви зливаєтесь). Середній буфер (BASE) є загальним предком обох (тому ви можете порівняти, як ліва і права версія відрізнялися одна від одної).

Я можу помилитися в наступному пункті. Я думаю, що джерелом конфлікту злиття є те, що обидва файли змінили одну і ту ж частину файлу після BASE; LOCAL змінив лапки з подвійних на одиничні, і REMOTE змінив ті ж зміни, але також змінив фонове значення з кольору на URL. (Я думаю, що злиття недостатньо розумне, щоб помітити, що всі зміни в LOCAL також є в REMOTE; воно просто знає, що LOCAL вніс зміни з BASE в тих самих місцях, що і REMOTE).

У будь-якому випадку нижній буфер містить файл, який ви можете фактично редагувати - той, що знаходиться у вашому робочому каталозі. Ви можете вносити будь-які зміни, які вам подобаються; vimпоказує, чим він відрізняється від кожного перегляду зверху, які області автоматичного злиття не змогли обробити. Витягніть зміни з LOCAL, якщо ви не хочете зміни ВИДАЛИТИ. Потягніть зміни з REMOTE, якщо ви віддаєте перевагу змінам LOCAL. Потягніть з BASE, якщо ви думаєте, що REMOTE і LOCAL помиляються. Зробіть щось зовсім інше, якщо маєте кращу ідею! Зрештою, зміни, які ви внесите тут, - це ті, які будуть фактично здійснені.


4
Швидке запитання, як я можу заощадити у vim?
Cool Guy Yo

6
:xабо :w( :xтеж виходить) плюс «повернути».
Джонатан Леффлер

4
Андерс: Є й інші інструменти злиття, якими ви можете скористатися, якщо ви не знайомі з ними vim.
чепнер

3
@AndersKitson, оскільки ви перебуваєте на Mac OS X, FileMerge ідеальний, безкоштовний і постачається з XCode.
romainl

8
Чому потік? Якщо є щось фактично неправильне, виправте це або принаймні вкажіть.
чепнер

91

@ відповідь чепнера чудова, я хотів би додати детальну інформацію про те, як слід продовжувати виправляти конфлікт злиття ". Якщо ви розглядаєте, як насправді використовувати vimdiff у цьому випадку, це іде нижче.


По-перше, звернутися до параметра "скасувати все" - якщо ви не хочете використовувати "vimdiff" і хочете скасувати злиття: натисніть Esc, а потім введіть :qa!і натисніть Enter. (див. також Як вийти з редактора Vim? ). Git запитає вас, чи було злиття завершено, відповідь n.


Якщо ви хочете використовувати vimdiff, ось кілька корисних ярликів. Це передбачає, що ви знаєте основи Vim (навігація та вставка / звичайний режим):

  • перейдіть до нижнього буфера (результат злиття): Ctrl-W j
  • перейти до наступного розрізання з j/ k; або, що краще, використовувати ] cта [ cпереходити до наступного та попереднього відмінності відповідно
  • скористайтеся z o, коли ви хочете побачити більше контексту
  • для кожної різниці, відповідно до відповіді @ chepner, ви можете отримати код з локальної, віддаленої чи базової версії, або відредагувати його та повторити, як вважаєте за потрібне
    • щоб отримати його з локальної версії, використовуйте :diffget LO
    • з віддаленого: :diffget RE
    • від бази: :diffget BA
    • або, якщо ви хочете відредагувати код самостійно, спочатку отримайте версію з локальної / віддаленої / базової, а потім перейдіть до режиму вставки та відредагуйте решту
  • Після цього збережіть результат об'єднання та закрийте всі вікна :wqa
  • як правило, git виявляє, що злиття здійснено і створює комісію злиття

Схоже, неможливо додати як локальні, так і віддалені конфліктні файли без вставлення копій чи спеціальних ярликів: /vi/10534/is-there-a-way-to-take-both- при використанні інструменту-vim-as-merge, що шкода, оскільки add add - це такий поширений тип конфлікту.

Щоб 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
Це повинно бути оновлено x1000 разів і прийнято як кращу відповідь.
Андрій Портний

щоб швидко перейти до наступного конфлікту, просто шукайте ===. зробіть "/ ===" і введіть
Апіт Джон Ісмаїл

Перегляньте цю публікацію ( stackoverflow.com/questions/51520705/… ), якщо більше ніж одна відповідність знайдена з використанням :diffget.
Джейсон

7

Кінцевий mergetool замінити vimdiff

Це свого роду язик у щоці, але це те, що я, нарешті, сходився як вімер після спроби vimdiff.

Щоб вирішити конфлікт злиття, мені майже завжди потрібно це бачити:

  • ВИДАЛЕНО
  • МІСЦЕВО
  • два відмінності:
    • різний ОСНОВНИЙ ПОДАМ
    • відмінна ОСНОВНА МІСЦЕ

щоб потім спробувати скласти їх обох.

У той час як vimdiff на екрані відображає ОСНОВНЕ, МІСЬКЕ та ВІДМОВНЕ:

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

Я не знаю, як чітко показати ті два розбіжності, які мені потрібні, окрім того, дивлячись праворуч ліворуч ліворуч.

Крім того, LOCAL і REMOTE вже видно в маркерах конфлікту git merge конфлікту, тому я не заробляю стільки з інструменту, який знову їх показує.

Тому я натомість створив власний крихітний "дифтоул", який насправді показує розбіжності, які мені не вистачало:

~ / 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 проти RealView_LOCAL_15560.py
  • RealView_BASE_15560.py проти 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>

яка безпосередньо знаходить конфлікти.

git imerge

Можливо, найкращим варіантом є просто відмовитися від використання vimdiff та покластися на регулярний imerge vim + git, про який згадувалось у: Як я можу дізнатись, які Git чини викликають конфлікти? оскільки крива навчання vimdiff дратує, і вона не виконує потрібні нам функції.


1
Отримано. Я думаю, що я згадував це 9 років тому в stackoverflow.com/a/3052118/6309 . (див. останню частину відповіді)
VonC

@VonC так, я думаю, ви виграли цю! XD
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.