Как мне использовать vimdiff для разрешения конфликта?
Я просто слил ветку в мой мастер в Git, и я получил Automatic merge failed; fix conflicts and then commit the result.
Теперь я побежал git mergetool
и открылся vimdiff с изображением ниже. Я не знаю, как использовать vimdiff. Что означает каждая панель здесь и как я должен приступить к устранению конфликта слияния?
2 ответа
Все четыре буфера обеспечивают различное представление одного и того же файла. Верхний левый буфер (LOCAL) - это то, как файл выглядел в вашей целевой ветви (во что вы сливаетесь). Верхний правый буфер (REMOTE) - это то, как файл выглядел в вашей исходной ветке (откуда вы объединяетесь). Средний буфер (BASE) является общим предком двух (так что вы можете сравнить, как левая и правая версии отличались друг от друга).
Я могу ошибаться в следующем. Я думаю, что источником конфликта слияния является то, что оба файла изменили одну и ту же часть файла после BASE; LOCAL изменил кавычки с двойных на одинарные, и REMOTE сделал то же самое изменение, но также изменил значение фона с цвета на URL. (Я думаю, что слияние недостаточно умен, чтобы заметить, что все изменения в LOCAL также присутствуют в REMOTE; он просто знает, что LOCAL внес изменения после BASE в тех же местах, что и REMOTE).
В любом случае нижний буфер содержит файл, который вы можете редактировать - тот, который находится в вашем рабочем каталоге. Вы можете вносить любые изменения, которые вам нравятся; vim
показывает, как он отличается от каждого из видов сверху, которые являются областями, которые автоматическое объединение не может обработать. Вытащите изменения из МЕСТНОГО, если вы не хотите УДАЛЕННЫХ изменений. Извлеките изменения из REMOTE, если вы предпочитаете их локальным изменениям. Потяните с BASE, если считаете, что REMOTE и LOCAL ошибочны. Сделайте что-то совершенно другое, если у вас есть идея получше! В конце концов, изменения, которые вы вносите здесь, действительно будут зафиксированы.
Ответ @chepner отличный, я хотел бы добавить некоторые детали вопроса о том, "как мне решить проблему слияния". Если вы посмотрите, как на самом деле использовать vimdiff в этом случае, он пойдет ниже.
Во-первых, чтобы обратиться к опции "прервать все" - если вы не хотите использовать "vimdiff" и хотите прервать слияние: нажмите Esc, затем введите :qa!
и нажмите Enter. (см. также Как выйти из редактора Vim?). Git спросит вас, завершено ли слияние, и ответьте: n
,
Если вы хотите использовать vimdiff, вот несколько полезных ярлыков. Предполагается, что вы знаете основы Vim (навигация и вставка / обычный режим):
- перейти к нижнему буферу (результат слияния): Ctrl-W j
- перейти к следующему diff с помощью j/k; или, лучше, используйте ] c и [ c, чтобы перейти к следующему и предыдущему разности соответственно
- используйте z o на сгибе, чтобы открыть его, если вы хотите увидеть больше контекста
- для каждого сравнения, согласно ответу @chepner, вы можете либо получить версию кода из локальной, удаленной или базовой версии, либо отредактировать ее и повторить, как считаете нужным
- чтобы получить его из локальной версии, используйте
:diffget LO
- с пульта:
:diffget RE
- с базы:
:diffget BA
- или, если вы хотите отредактировать себя, сначала получите версию из локальной / удаленной / базовой, а затем перейдите в режим вставки и отредактируйте остальные.
- чтобы получить его из локальной версии, используйте
- После этого сохраните результат объединения и закройте все окна.
:wqa
- обычно git обнаруживает, что слияние было выполнено, и завершает коммит слияния
Вы можете искать в Интернете другие ярлыки vimdiff. Я нашел это полезным, например: https://gist.github.com/hyamamoto/7783966
Совершенный mergetool для замены vimdiff
Это своего рода насмешка, но это то, к чему я пришел как vimmer после попытки vimdiff.
Чтобы разрешить конфликт слияния, мне почти всегда нужно увидеть:
- УДАЛЕННЫЙ
- МЕСТНЫЙ
- две разницы:
- diff BASE REMOTE
- diff BASE LOCAL
чтобы затем попытаться соединить их обоих.
Хотя vimdiff показывает на экране BASE, LOCAL и REMOTE:
+--------------------------------+
| LOCAL | BASE | REMOTE |
+--------------------------------+
| MERGED |
+--------------------------------+
Я не знаю, как сделать так, чтобы он четко отображал те два различия, которые мне нужны, кроме того, что несколько раз посмотрел направо, налево, направо, налево.
Кроме того, LOCAL и REMOTE уже видны в маркерах конфликтов слияния git, поэтому я не получаю так много от инструмента, который показывает их снова.
Поэтому вместо этого я создал свой собственный крошечный "инструмент для различий", который фактически показывает различия, которые мне не хватало:
~ / 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
И установите его с помощью:
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>
который находит конфликты напрямую.
мерзавец
Возможно, лучший вариант - просто отказаться от использования vimdiff и полагаться на обычный vim + git imerge, о котором упоминалось в: Как я могу узнать, какие коммиты Git вызывают конфликты? поскольку кривая обучения vimdiff раздражает, и он не выполняет те функции, которые нам нужны больше всего.