Как использовать vimdiff для разрешения конфликта git merge?

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

enter image description here

Ответ 1

Все четыре буфера предоставляют другой вид того же файла. Верхний левый буфер (ЛОКАЛЬНЫЙ) - это то, как файл просматривался в вашей целевой ветке (с чем вы сливаетесь). Верхний правый буфер (REMOTE) - это то, как файл выглядел в вашей ветки источника (где вы сливаетесь). Средний буфер (BASE) является общим предком двух (так что вы можете сравнить, как левая и правая версии отличаются друг от друга).

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

В любом случае, нижний буфер содержит файл, который вы можете редактировать, и тот, который находится в вашем рабочем каталоге. Вы можете внести любые изменения; vim показывает вам, как он отличается от каждого из видов сверху, которые являются областями, которые автоматическое слияние не могло обрабатывать. Извлеките изменения из LOCAL, если вы не хотите, чтобы изменения REMOTE менялись. Извлеките изменения из REMOTE, если вы предпочитаете их для ЛОКАЛЬНЫХ изменений. Потяните с BASE, если считаете, что оба REMOTE и LOCAL ошибочны. Сделайте что-то совершенно другое, если у вас есть лучшая идея! В конце, изменения, которые вы здесь делаете, - это те, которые действительно будут совершены.

Ответ 2

Ответ @chepner великолепен, я хотел бы добавить некоторые детали вопроса о том, "как мне решить проблему слияния". Если вы посмотрите, как на самом деле использовать 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
    • если вы хотите прервать слияние текущего файла и не пометить его как разрешенный, :cquit с помощью :cquit вместо: Как отменить внешний git diff?
  • обычно git обнаруживает, что слияние было выполнено, и создает коммит слияния

По-видимому, невозможно добавить как локальные, так и удаленные блоки конфликтов без вставки копий или пользовательских ярлыков: https://vi.stackexchange.com/questions/10534/is-there-a-way-to-take-both- Когда-использование-vim-as-merge-tool - это позор, так как add-add - такой распространенный тип конфликта.

Чтобы vimdiff не просил вас нажимать клавишу ввода при каждом запуске, добавьте в свой .vimrc:

set shortmess=Ot

как упомянуто в: https://vi.stackexchange.com/questions/771/how-can-i-suppress-the-press-enter-prompt-when-opening-files-in-diff-mode

Вы можете искать в Интернете другие ярлыки vimdiff. Я нашел это полезным: https://gist.github.com/hyamamoto/7783966

Ответ 3

Как провести различие между (BASE и LOCAL) и (BASE и REMOTE) с помощью vim -d

При разрешении конфликтов слияния, одна из самых важных вещей, которые вы хотите увидеть, это:

  • как мой новый коммит изменил базовый коммит
  • как существующий коммит изменил базовый коммит

затем попытаться соединить их обоих.

В то время как vimdiff хорошо показывает бок о бок все BASE, LOCAL и REMOTE, я не могу ясно увидеть из этого два отдельных diff файла из BASE:

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

Чтобы решить эту проблему, я заметил, что пока 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 merge какие файлы 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>

который находит конфликты напрямую.