Как разрешить конфликты слияния в Git - PullRequest
4421 голосов
/ 02 октября 2008

Как мне разрешить конфликты слияния в Git?

Ответы [ 34 ]

2651 голосов
/ 02 октября 2008

Попробуйте: git mergetool

Он открывает графический интерфейс, который проходит через каждый конфликт, и вы можете выбрать, как объединить. Иногда это требует небольшого ручного редактирования впоследствии, но обычно этого достаточно само по себе. Это намного лучше, чем делать все вручную.

Согласно комментарию @JoshGlover:

Команда не обязательно открывает графический интерфейс, если вы его не установите. Запуск git mergetool для меня привел к использованию vimdiff. Вместо этого вы можете установить один из следующих инструментов: meld, opendiff, kdiff3, tkdiff, xxdiff, tortoisemerge, gvimdiff, diffuse, ecmerge, p4merge, araxis, vimdiff, emerge.

Ниже приведен пример процедуры для использования vimdiff для разрешения конфликтов слияния. На основании этой ссылки

Шаг 1 : Выполнить следующие команды на вашем терминале

git config merge.tool vimdiff
git config merge.conflictstyle diff3
git config mergetool.prompt false

Это установит vimdiff в качестве инструмента слияния по умолчанию.

Шаг 2 : Выполнить следующую команду в терминале

git mergetool

Шаг 3 : Вы увидите дисплей vimdiff в следующем формате

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

Эти 4 просмотра

LOCAL - это файл из текущей ветки

BASE - общий предок, как файл выглядел до обоих изменений

REMOTE - файл, который вы объединяете в свою ветку

MERGED - результат слияния, это то, что сохраняется в репо

Вы можете перемещаться между этими видами, используя ctrl+w. Вы можете напрямую перейти к просмотру MERGED, используя ctrl+w, а затем j.

Подробнее о навигации vimdiff здесь и здесь

Шаг 4 . Вы можете редактировать MERGED следующим образом

Если вы хотите получить изменения от REMOTE

:diffg RE  

Если вы хотите получать изменения от BASE

:diffg BA  

Если вы хотите получить изменения из LOCAL

:diffg LO 

Шаг 5 . Сохранение, выход, фиксация и очистка

:wqa сохранить и выйти из vi

git commit -m "message"

git clean Удалить лишние файлы (например, * .orig), созданные инструментом diff.

1638 голосов
/ 04 августа 2010

Вот вероятный вариант использования сверху:

Вы собираетесь внести некоторые изменения, но, к сожалению, вы не в курсе:

git fetch origin
git pull origin master

From ssh://gitosis@example.com:22/projectname
 * branch            master     -> FETCH_HEAD
Updating a030c3a..ee25213
error: Entry 'filename.c' not uptodate. Cannot merge.

Итак, вы обновились и попробуйте снова, но у вас возник конфликт:

git add filename.c
git commit -m "made some wild and crazy changes"
git pull origin master

From ssh://gitosis@example.com:22/projectname
 * branch            master     -> FETCH_HEAD
Auto-merging filename.c
CONFLICT (content): Merge conflict in filename.c
Automatic merge failed; fix conflicts and then commit the result.

Итак, вы решили взглянуть на изменения:

git mergetool

О, я, о, мой, вышестоящий изменил некоторые вещи, но просто чтобы использовать мои изменения ... нет ... их изменения ...

git checkout --ours filename.c
git checkout --theirs filename.c
git add filename.c
git commit -m "using theirs"

А потом мы попробуем последний раз

git pull origin master

From ssh://gitosis@example.com:22/projectname
 * branch            master     -> FETCH_HEAD
Already up-to-date.

Та-да!

709 голосов
/ 29 сентября 2011

Я считаю, что инструменты слияния редко помогают мне понять конфликт или решение. Я обычно более успешно смотрю на маркеры конфликта в текстовом редакторе и использую git log в качестве дополнения.

Вот несколько советов:

Совет первый

Лучшее, что я нашел, это использовать стиль конфликта слияния "diff3":

git config merge.conflictstyle diff3

Это приводит к появлению таких маркеров конфликта:

<<<<<<<
Changes made on the branch that is being merged into. In most cases,
this is the branch that I have currently checked out (i.e. HEAD).
|||||||
The common ancestor version.
=======
Changes made on the branch that is being merged in. This is often a 
feature/topic branch.
>>>>>>>

Средняя часть - это то, на что был похож общий предок. Это полезно, потому что вы можете сравнить его с верхней и нижней версиями, чтобы лучше понять, что было изменено в каждой ветви, что дает вам лучшее представление о том, какова была цель каждого изменения.

Если конфликт состоит всего из нескольких строк, это обычно делает конфликт очень очевидным. (Знание того, как исправить конфликт, совсем другое; вам нужно знать, над чем работают другие люди. Если вы растерялись, лучше всего просто позвонить этому человеку в вашу комнату, чтобы он мог видеть, что вы ищете в.)

Если конфликт будет более продолжительным, я буду вырезать и вставлять каждый из трех разделов в три отдельных файла, таких как «мой», «общий» и «их».

Затем я могу запустить следующие команды, чтобы увидеть два различий, вызвавших конфликт:

diff common mine
diff common theirs

Это не то же самое, что использование инструмента слияния, поскольку инструмент слияния будет также включать все неконфликтующие блоки различий. Я нахожу это отвлекающим.

Совет второй

Кто-то уже упоминал об этом, но понимание намерений, стоящих за каждым другим источником, как правило, очень полезно для понимания того, откуда возник конфликт и как с ним справиться.

git log --merge -p <name of file>

Здесь показаны все коммиты, которые касались этого файла между общим предком и двумя головами, которые вы объединяете. (Таким образом, он не включает коммиты, которые уже существуют в обеих ветках до слияния.) Это помогает вам игнорировать блоки различий, которые явно не являются фактором в вашем текущем конфликте.

Совет три

Проверьте ваши изменения с помощью автоматизированных инструментов.

Если у вас есть автоматические тесты, запустите их. Если у вас есть lint , запустите его. Если это проект для сборки, то создайте его перед фиксацией и т. Д. Во всех случаях вам нужно провести небольшое тестирование, чтобы убедиться, что ваши изменения ничего не сломали. (Черт, даже слияние без конфликтов может нарушить рабочий код.)

Совет четвертый

Планируйте заранее; общаться с коллегами.

Планирование заблаговременно и знание того, над чем работают другие, может помочь предотвратить конфликты слиянием и / или помочь разрешить их раньше - хотя детали еще свежи в памяти.

Например, если вы знаете, что вы и другой человек работаете над различным рефакторингом, который будет влиять на один и тот же набор файлов, вам следует заранее поговорить друг с другом и лучше понять, какие типы изменений каждый из вас делает. Вы можете сэкономить много времени и усилий, если планируете вносить изменения последовательно, а не параллельно.

Для крупных рефакторингов, которые затрагивают большую часть кода, вам следует настоятельно рекомендовать работать последовательно: все прекращают работать над этой областью кода, пока один человек выполняет полный рефакторинг.

Если вы не можете работать последовательно (возможно, из-за нехватки времени), то сообщение об ожидаемых конфликтах слияния по крайней мере поможет вам быстрее решить проблемы, пока детали еще свежи. Например, если сотрудник совершает серию разрушительных коммитов в течение однонедельного периода, вы можете выбрать слияние / перебазирование в этом филиале коллег один или два раза в день в течение этой недели. Таким образом, если вы обнаружите конфликты слияния / перебазирования, вы сможете разрешить их быстрее, чем если бы вы подождали несколько недель, чтобы объединить все в один большой кусок.

Совет пятый

Если вы не уверены в слиянии, не форсируйте его.

Слияние может показаться ошеломляющим, особенно когда существует много конфликтующих файлов, а маркеры конфликта занимают сотни строк. Часто при оценке программных проектов мы не учитываем достаточно времени для таких накладных расходов, как обработка грубого слияния, поэтому кажется, что это настоящая трата - потратить несколько часов на анализ каждого конфликта.

В долгосрочной перспективе планирование заранее и понимание того, над чем работают другие, являются лучшими инструментами для предвидения конфликтов слияний и подготовки к их правильному разрешению за меньшее время.

332 голосов
/ 02 октября 2008
  1. Определите, какие файлы конфликтуют (Git должен сообщить вам об этом).

  2. Откройте каждый файл и изучите различия; Git разграничивает их. Надеемся, будет очевидно, какую версию каждого блока сохранить. Возможно, вам придется обсудить это с другими разработчиками, которые передали код.

  3. После разрешения конфликта в файле git add the_file.

  4. Как только вы разрешите все конфликты, выполните git rebase --continue или любую другую команду Git сказал делать, когда ты закончил.

102 голосов
/ 03 октября 2008

Ознакомьтесь с ответами на вопрос переполнения стека Отмена слияния в Git , особенно Ответ Чарльза Бэйли , который показывает, как просмотреть различные версии файла с проблемами, например,

# Common base version of the file.
git show :1:some_file.cpp

# 'Ours' version of the file.
git show :2:some_file.cpp

# 'Theirs' version of the file.
git show :3:some_file.cpp
90 голосов
/ 05 августа 2015

Конфликты слияния происходят, когда изменения вносятся в файл одновременно. Вот как это решить.

git CLI

Вот простые шаги, которые нужно предпринять, когда вы попадаете в конфликтное состояние:

  1. Обратите внимание на список конфликтующих файлов: git status (в разделе Unmerged paths).
  2. Разрешение конфликтов отдельно для каждого файла одним из следующих подходов:

    • Используйте GUI для разрешения конфликтов: git mergetool (самый простой способ).

    • Чтобы принять удаленную / другую версию, используйте: git checkout --theirs path/file. Это отклонит любые локальные изменения, которые вы сделали для этого файла.

    • Чтобы принять локальную / нашу версию, используйте: git checkout --ours path/file

      Однако вы должны быть осторожны, так как удаленные изменения, которые были вызваны конфликтами по какой-то причине.

      Похожие: Каково точное значение «наших» и «их» в git?

    • Отредактируйте конфликтующие файлы вручную и найдите блок кода между <<<<< / >>>>>, затем выберите версию сверху или снизу =====. См .: Как представлены конфликты .

    • Конфликты пути и имени файла могут быть решены с помощью git add / git rm.

  3. Наконец, просмотрите файлы, готовые для фиксации, используя: git status.

    Если у вас все еще есть файлы в Unmerged paths, и вы действительно решили конфликт вручную, то сообщите Git, что вы решили его с помощью: git add path/file.

  4. Если все конфликты были успешно разрешены, зафиксируйте изменения: git commit -a и отправьте на удаленное устройство, как обычно.

См. Также: Разрешение конфликта слияния из командной строки в GitHub

DiffMerge

Я успешно использовал DiffMerge , который может визуально сравнивать и объединять файлы в Windows, macOS и Linux / Unix.

Он может графически отображать изменения между 3 файлами и позволяет автоматически объединять (когда это безопасно) и полностью контролировать редактирование полученного файла.

DiffMerge

Источник изображения: DiffMerge (скриншот Linux)

Просто скачайте его и запустите в репозитории как:

git mergetool -t diffmerge .

1099 * MacOS * На macOS вы можете установить через: brew install caskroom/cask/brew-cask brew cask install diffmerge И, возможно (если не указано иное) вам понадобится следующая дополнительная простая обертка, помещенная в вашу переменную PATH (например, /usr/bin): #!/bin/sh DIFFMERGE_PATH=/Applications/DiffMerge.app DIFFMERGE_EXE=${DIFFMERGE_PATH}/Contents/MacOS/DiffMerge exec ${DIFFMERGE_EXE} --nosplash "$@" Тогда вы можете использовать следующие сочетания клавиш: - Alt - Вверх / Вниз для перехода к предыдущим / следующим изменениям. - Alt - Влево / Вправо для принятия изменений слева или справа В качестве альтернативы вы можете использовать opendiff (часть Xcode Tools), который позволяет объединить два файла или каталога вместе, чтобы создать третий файл или каталог.

76 голосов
/ 02 октября 2008

Если вы часто делаете небольшие коммиты, начните с просмотра комментариев коммитов с git log --merge. Тогда git diff покажет вам конфликты.

Для конфликтов, которые включают в себя несколько строк, легче увидеть, что происходит во внешнем инструменте с графическим интерфейсом. Мне нравится opendiff - Git также поддерживает vimdiff, gvimdiff, kdiff3, tkdiff, meld, xxdiff, появляются из коробки, и вы можете установить другие: git config merge.tool "your.tool" установит выбранный вами инструмент и затем git mergetool после неудачного слияния покажет Вы различия в контексте.

Каждый раз, когда вы редактируете файл для разрешения конфликта, git add filename будет обновлять индекс, и ваш diff больше не будет его показывать. Когда все конфликты будут обработаны и их файлы будут git add -ed, git commit завершит ваше слияние.

44 голосов
/ 14 июля 2013

См. Как представлены конфликты или, в Git, документация git merge, чтобы понять, что такое маркеры конфликта слияния.

Также в разделе Как разрешать конфликты объясняется, как разрешать конфликты:

Увидев конфликт, вы можете сделать две вещи:

  • Решите не сливаться. Единственные операции очистки, которые вам нужны, - это сброс файла индекса на HEAD, зафиксированный для изменения 2. и очистка изменений рабочего дерева, сделанных на 2. и 3 .; git merge --abort может использоваться для этого.

  • Разрешение конфликтов. Git отметит конфликты в рабочем дереве. Отредактируйте файлы в форму и git add их в индекс. Для заключения сделки используйте git commit.

Вы можете преодолеть конфликт с помощью ряда инструментов:

  • Используйте mergetool. git mergetool для запуска графического инструмента слияния, который проведет вас через слияние.

  • Посмотрите на различия. git diff покажет трехстороннюю разницу, выделив изменения как в версиях HEAD, так и MERGE_HEAD.

  • Посмотрите на различия из каждой ветви. git log --merge -p <path> сначала покажет различия для HEAD версии, а затем MERGE_HEAD версии.

  • Посмотрите на оригиналы. git show :1:filename показывает общего предка, git show :2:filename показывает версию HEAD, а git show :3:filename показывает версию MERGE_HEAD.

Вы также можете прочитать о маркерах конфликта слияния и о том, как их разрешить, в разделе книги Pro Git Основные конфликты слияния .

38 голосов
/ 23 февраля 2013

Для Emacs пользователей, которые хотят разрешить конфликты слияния полу-вручную:

git diff --name-status --diff-filter=U

показывает все файлы, требующие разрешения конфликта.

Откройте каждый из этих файлов по одному или все сразу:

emacs $(git diff --name-only --diff-filter=U)

При посещении буфера, требующего редактирования в Emacs, введите

ALT+x vc-resolve-conflicts

Это откроет три буфера (мой, их и выходной буфер). Перемещайтесь, нажимая «n» (следующий регион), «p» (регион предвидения). Нажмите «a» и «b», чтобы скопировать мой или их регион в выходной буфер, соответственно. И / или отредактируйте выходной буфер напрямую.

Когда закончите: нажмите «q». Emacs спросит вас, хотите ли вы сохранить этот буфер: да. После завершения буфера пометьте его как разрешенный, выполнив из терминалима:

git add FILENAME

Когда закончите со всеми буферами, наберите

git commit

для завершения слияния.

35 голосов
/ 29 сентября 2016

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

Полностью принять мою или их версию :

Примите мою версию (локальную, нашу):

git checkout --ours -- <filename>
git add <filename>              # Marks conflict as resolved
git commit -m "merged bla bla"  # An "empty" commit

Примите их версию (удаленную, их):

git checkout --theirs -- <filename>
git add <filename>
git commit -m "merged bla bla"

Если вы хотите сделать для всех конфликтных файлов запустите:

git merge --strategy-option ours

или

git merge --strategy-option theirs

Просмотрите все изменения и примите их индивидуально

  1. git mergetool
  2. Просмотрите изменения и примите любую версию для каждого из них.
  3. git add <filename>
  4. git commit -m "merged bla bla"

По умолчанию mergetool работает в командной строке . Как использовать командную строку mergetool должно быть отдельным вопросом.

Для этого вы также можете установить визуальный инструмент , например, meld и запустить

git mergetool -t meld

Будет открыта локальная версия (наша), «базовая» или «объединенная» версия (текущий результат слияния) и удаленная версия (их). Сохраните объединенную версию, когда закончите, снова запустите git mergetool -t meld, пока не появится сообщение «Нет необходимости объединять файлы», затем перейдите к Шагу 3. и 4.

...