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


4769

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


31
Следующий пост в блоге, кажется, дает очень хороший пример того, как обрабатывать конфликты слияния с Git, которые должны помочь вам двигаться в правильном направлении. Обработка и предотвращение конфликтов в Git
mwilliams

4
Вы можете настроить инструмент слияния (kdiff3 jebaird.com/2013/07/08/… ) и затем использовать git mergetool. Когда вы работаете в больших группах разработчиков, вы всегда будете сталкиваться с конфликтами слияния.
Грэйди Купер

Не забывайте, что вы можете смягчить большинство конфликтов слияний, регулярно сливаясь вниз по течению!
Муравей P


8
Захватывающий вопрос: в 2008 году вопрос о 100% открытии закончился без всякого намека на то, что на самом деле (о графическом интерфейсе, о командах git, о семантике, о толкании / извлечении или просто общих конфликтах?) - совершенно неопровержимый. 30 ответов, все из них (насколько можно судить по беглому взгляду) более или менее касаются различных инструментов сравнения и слияния, ни один из них не принят. В ответе с наибольшим количеством голосов упоминается команда, которая даже не работает из коробки при gitустановке по умолчанию . Мне удалось попасть на стартовую страницу SE сегодня, 2017, с 1,3 млн просмотров и тысячами голосов в обе стороны. Захватывающий.
AnoE

Ответы:


2913

Пытаться: 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.


54
К вашему сведению, вы можете использовать, git mergetool -yчтобы сохранить несколько нажатий клавиш, если вы объединяете много файлов одновременно.
Давр

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

31
Хороший вопрос, Джош. На Ubuntu мне больше всего повезло с meld, его трехстороннее отображение слияния неплохо. На OSX Git выбрал хороший по умолчанию.
Питер Бернс

18
Это открыл KDiff3. Который я понятия не имею, как использовать.
Дэвид Мердок

7
Вы также можете использовать Beyond Compare 3 сейчас ( git mergetool -t bc3).
AzP

1703

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

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

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

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

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.

Та-да!


19
Это было очень полезно, потому что у меня было много ошибок слияния с бинарными файлами (художественные ресурсы), и объединение этих файлов, похоже, всегда завершалось неудачей, поэтому мне нужно всегда перезаписывать его новым файлом, а не «сливать»
petrocket

188
Осторожный! Значение --ours и --theirs поменялось местами. --ours == пульт. --theirs == местные. Смотритеgit merge --help
запомните

57
В моем случае я подтверждаю, что --theirs = удаленный репозиторий, --ours = мой собственный локальный репозиторий. Это противоположность комментариям @mmell.
Арё

24
@mmell Только на ребаз, видимо. Смотритеthis question
Навин

184
Ребята, «наши» и «их» относятся к тому, слились вы или нет. Если вы объединяетесь , то «наш» означает ветвь, в которую вы сливаетесь, а «их» - это ветвь, в которую вы сливаетесь . Когда вы перебазируете , тогда «наш» означает коммиты, на которые вы перебазируете , в то время как «их» относится к коммитам, которые вы хотите перебазировать.

736

Я считаю, что инструменты слияния редко помогают мне понять конфликт или решение. Я обычно более успешно смотрю на маркеры конфликта в текстовом редакторе и использую 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>

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

Совет третий

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

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

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

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

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

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

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

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

Совет пятый

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

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

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


6
Опция diff3 - отличная возможность для слияния. Единственный GUI, с которым я столкнулся, показывает, что это Perforce p4merge, который можно установить и использовать отдельно от других инструментов Perforce (которые я не использовал, но слышал жалобы).
alxndr

3
После попытки перебазировки, которая привела к конфликту слияния: $ git log --merge -p build.xml output: fatal: --merge без MERGE_HEAD?
Эд Рэндалл

Что делать, если у меня есть изменения в одном файле из Branch1 и удаление этого файла в Branch2. Как я могу решить этот конфликт слияния? Есть ли способ использовать git, где я могу объединить их, сохранив изменения одной ветви?
Мед

git config merge.conflictstyle diff3- Спасибо, сэр. Это удивительно и освободило меня от попыток найти (и заплатить $$) за хороший 3-х сторонний графический интерфейс слияния. IMO, это лучше, потому что он показывает общего предка, а также локальный / удаленный, и показывает последние строки журнала коммитов, которые (AFAIK) никакой графический интерфейс не делает. Коммиты определенно помогут вам определить, какой код принадлежит какой ветке.
ffxsam

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

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

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

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

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


38
@Justin Думайте о Git как о трекинге контента, а не как трекинг файлов. Тогда легко увидеть, что контент, который вы обновили , отсутствует в репозитории и должен быть добавлен. Этот способ мышления также объясняет, почему Git не отслеживает пустые папки: хотя технически они являются файлами, контент для отслеживания отсутствует.
Гарет

7
контент есть, конфликт возникает потому что есть 2 версии контента. Поэтому «git add» не звучит правильно. И это не работает (git add, git commit), если вы хотите зафиксировать только тот файл, который был разрешен после конфликта («фатально: не может выполнить частичную фиксацию во время слияния».)
Dainius

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

5
Тульфир: кто сказал что-то о том, чтобы сделать одну ветку такой же, как другую? Существуют разные сценарии, в которых вам нужно объединить, не «делая одну ветвь такой же, как другая». Во-первых, когда вы закончили с веткой разработки и хотите включить ее изменения в основную ветку; после этого ветка разработки может быть удалена. Другой - когда вы хотите перебазировать свою ветку разработки, чтобы облегчить окончательное слияние с мастером.
Теему Лейсти

4
@JustinGrant помещает git addфайлы в индекс; это ничего не добавляет к хранилищу. git commitдобавляет вещи в хранилище. Такое использование имеет смысл для слияний - слияние автоматически ставит все изменения, которые могут быть слиты автоматически; Вы несете ответственность за объединение остальных изменений и добавление их в индекс после завершения.
Марк Э. Хааз

105

Ознакомьтесь с ответами на вопрос переполнения стека. Отмена слияния в 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

Также проверьте опцию «-m» для «git checkout -m» - она ​​позволяет вам извлекать различных мух обратно в ваше рабочее пространство
qneill

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

99

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

git CLI

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

  1. Обратите внимание на список конфликтующих файлов с: git statusUnmerged 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

Для практического руководства, проверьте: Сценарий 5 - Исправление конфликтов слияния по Katacoda .

DiffMerge

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

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

DiffMerge

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

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

git mergetool -t diffmerge .

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- Up/ Downдля перехода к предыдущим / следующим изменениям.
  • - Alt- Left/ Rightпринять изменения слева или справа

В качестве альтернативы вы можете использовать opendiff (часть инструментов Xcode), который позволяет объединить два файла или каталоги вместе, чтобы создать третий файл или каталог.


79

Если вы часто делаете небольшие коммиты, начните с просмотра комментариев коммитов 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, git commitзавершится слияние.


8
Использование «git add» - вот настоящий трюк. Вы можете даже не хотеть коммитить (может быть, вы хотите спрятать), но вы должны сделать «git add», чтобы завершить слияние. Я думаю, что mergetool сделает добавление за вас (хотя оно не находится на странице руководства), но если вы делаете слияние вручную, вам нужно использовать «git add» для его завершения (даже если вы не хотите фиксировать).
Нобар

47

Посмотрите, как представлены конфликты или, в 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 « Основные конфликты слияния» .


42

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

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

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

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.


Эта команда: git checkout --theirs - <имя_файла> изменило все файлы на свои, а не только на <имя_файла>
Donato

На самом деле я был неправ. Это только обновляет указанный файл.
Донато

40

Для пользователей 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

закончить слияние.


33

Бонус:

Говоря о pull / fetch / merge в приведенных выше ответах, я хотел бы поделиться интересным и продуктивным приемом:

git pull --rebase

Эта команда является самой полезной в моей жизни Git, которая сэкономила много времени.

Перед отправкой вашего недавно зафиксированного изменения на удаленный сервер, попробуйте git pull --rebaseскорее git pullвручную, mergeи он автоматически синхронизирует последние изменения удаленного сервера (с извлечением + объединением) и поместит ваш локальный последний коммит наверху в журнале git. Не нужно беспокоиться о ручном вытягивании / слиянии.

В случае конфликта просто используйте

git mergetool
git add conflict_file
git rebase --continue

Найти подробности на: http://gitolite.com/git-pull--rebase


32

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

git checkout . --ours

разрешить изменения в пользу вашего хранилища , или

git checkout . --theirs

разрешить изменения в пользу другого или основного хранилища .

Или же вам придется использовать инструмент слияния GUI для пошагового просмотра файлов, скажем, инструмент слияния p4merge, или написать любое имя, которое вы уже установили

git mergetool -t p4merge

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


2
Git Checkout. - они решили мою проблему, спасибо
Рамеш Чанд

если вы предпочитаете разрешать конфликты вручную, попробуйте открыть папку в коде Visual Studio, она помечает файлы с конфликтами и конфликтует между цветами внутри каждой строки
Мохамед Селим

31

Пожалуйста, выполните следующие шаги, чтобы исправить конфликты слияния в Git:

  1. Проверьте статус Git: статус Git

  2. Получите набор патчей: git fetch (проверьте правильный патч из вашего коммита Git)

  3. Извлечь локальную ветку (в моем примере это temp1): git checkout -b temp1

  4. Извлеките недавнее содержимое из master: git pull --rebase origin master

  5. Запустите mergetool, проверьте конфликты и исправьте их ... и проверьте изменения в удаленной ветке с вашей текущей веткой: git mergetool

  6. Проверьте статус еще раз: git status

  7. Удалите ненужные файлы, локально созданные с помощью mergetool, обычно mergetool создает дополнительный файл с расширением * .orig. Пожалуйста, удалите этот файл, так как это просто дубликат, исправьте изменения локально и добавьте правильную версию ваших файлов. git add #your_changed_correct_files

  8. Проверьте статус еще раз: git status

  9. Зафиксируйте изменения в одном и том же идентификаторе (это позволяет избежать нового отдельного набора патчей): git commit --amend

  10. Push в ветку master: git push (в ваш репозиторий Git)


28

Есть 3 шага:

  1. Найти какие файлы вызывают конфликты по команде

    git status
    
  2. Проверьте файлы, в которых вы найдете конфликты, помеченные как

    <<<<<<<<head
    blablabla
    
  3. Измените его так, как вы хотите, затем подтвердите с помощью команд

    git add solved_conflicts_files
    git commit -m 'merge msg'
    

Работал на меня! Спасибо!
Nuwan Jayawardene

Вы должны обратить внимание, если делаете это во время ребазинга. Вы должны использовать git rebase - продолжить вместо git commit
Сэмюэль Даузон

27

Вы можете исправить конфликты слиянием несколькими способами, как подробно описано в других.

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

Я лично привык к двум вещам, чтобы избежать этого.

Вместо:

git add .
git commit -m"some msg"

Который имеет два недостатка -

а) Все новые / измененные файлы добавляются, и это может включать некоторые нежелательные изменения.
б) Вы не можете сначала просмотреть список файлов.

Так что вместо этого я делаю:

git add file,file2,file3...
git commit # Then type the files in the editor and save-quit.

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

[Обновление - со временем я переключился на:

git status # Make sure I know whats going on
git add .
git commit # Then use the editor

]

Также (и более актуально для вашей ситуации) я стараюсь избегать:

git pull

или

git pull origin master.

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

Вместо этого я пытаюсь сделать

git checkout master
git fetch   
git rebase --hard origin/master # or whatever branch I want.

Вы также можете найти это полезным:

git branch, fork, fetch, merge, rebase и clone, в чем различия?


Эй, я вроде понял твой ответ. Но так как я новичок в конфликтах github слияния, я думаю, что-то не хватает. Что происходит с местными изменениями , когда вы делаете git checkout masterи git fetch и git rebase --hard origin/master
Suhaib

Я считаю, что вы должны добавить более подробную информацию о том, что делать. Другой пример, который меня смущает, вы упомянули в своем ответе: мы сделаем git add ., сохранит ли он наши локальные изменения, чтобы мы могли продолжить git checkout master? или это два разных сценария?
Сухайб

@MichaelDurrant $ git rebase --hard origin/master b5a30cc159ba8dd error: unknown option hard 'использование: git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>] или: git rebase [-i] [ параметры] [--exec <cmd>] [--onto <newbase>] --root [<branch>] или: git rebase --continue | --abort | --skip | --edit-todo `
likejudo

24

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

(Code not in Conflict)
>>>>>>>>>>>
(first alternative for conflict starts here)
Multiple code lines here
===========
(second alternative for conflict starts here)
Multiple code lines here too    
<<<<<<<<<<<
(Code not in conflict here)

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

git commit -a -m "commit message"
git push origin master

17
git log --merge -p [[--] path]

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

То, что я делаю, чтобы обойти эту проблему, это открыть две командные строки и в один запуск

git log ..$MERGED_IN_BRANCH --pretty=full -p [path]

а в другом

git log $MERGED_IN_BRANCH.. --pretty=full -p [path]

Заменив $MERGED_IN_BRANCHветку я слил и [path]конфликтующим файлом. Эта команда будет записывать все коммиты в форме патча между ( ..) двумя коммитами. Если вы оставите одну сторону пустой, как в приведенных выше командах, git будет автоматически использовать HEAD(в данном случае ветку, с которой вы объединяетесь).

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


16

С помощью patience

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

Например, если вы изменяете отступ вашей программы, стратегия слияния Git по умолчанию иногда сопоставляет отдельные скобки, {которые принадлежат разным функциям. Этого можно избежать с помощью patience:

git merge -s recursive -X patience other-branch

Из документации:

With this option, merge-recursive spends a little extra time to avoid 
mismerges that sometimes occur due to unimportant matching lines 
(e.g., braces from distinct functions). Use this when the branches to 
be merged have diverged wildly.

Сравнение с общим предком

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

git diff $(git merge-base <our-branch> <their-branch>) <their-branch>

Обычно вы хотите видеть изменения только для определенного файла:

git diff $(git merge-base <our-branch> <their-branch>) <their-branch> <file>

В моем случае это не помогло разрешить конфликты слияния, так как по какой-то причине в проектах C # сохранились повторяющиеся строки конфигурации. Хотя это было более дружелюбно, чем ВЕСЬ ФАЙЛ РАЗЛИЧНЫЙ, который у меня был раньше
Mathijs Segers

15

С 12 декабря 2016 года вы можете объединять филиалы и разрешать конфликты на github.com.

Таким образом, если вы не хотите использовать командную строку или какие-либо сторонние инструменты, предлагаемые здесь из более ранних ответов , используйте родной инструмент GitHub.

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

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


это не вопрос о github, поэтому я проголосовал за то, что я считаю очень плохим ответом.
mschuett

1
@mschuett прав, вопрос в том, «как разрешать конфликты в git», а не «как разрешать конфликты в github». Есть разница, и уже слишком много людей думают, что git и github - это одно и то же, поэтому все, что распространяет это чувство, неверно.
Патрик Мевзек,

15

Если вы хотите объединить ветку (тест) с мастером, вы можете выполнить следующие шаги:

Шаг 1 : Перейти в ветку

git checkout test

Шаг 2 :

git pull --rebase origin master

Шаг 3 : Если есть конфликты, перейдите к этим файлам, чтобы изменить его.

Шаг 4 : Добавьте эти изменения

git add #your_changes_files

Шаг 5 :

git rebase --continue

Шаг 6 : Если конфликт продолжается, вернитесь к шагу 3 снова. Если конфликта нет, сделайте следующее:

git push origin +test

Шаг 7 : И тогда между тестом и мастером нет конфликта. Вы можете использовать слияние напрямую.


13

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

  • git checkout master (приходите в ветку master)
  • git pull (обновите мастер, чтобы получить последний код)
  • git checkout -b mybranch (извлеките новую ветку и начните работать над этой веткой, чтобы ваш мастер всегда оставался верхом ствола.)
  • мерзавец добавить. И git commit И git push (в вашей локальной ветке после ваших изменений)
  • Git Checkout Master (Вернись к своему хозяину.)

Теперь вы можете делать то же самое и поддерживать столько локальных веток, сколько хотите, и работать одновременно, просто когда я делаю git checkout в вашу ветку, когда это необходимо.


12

Конфликты слияния могут возникать в разных ситуациях:

  • При запуске "git fetch", а затем "git merge"
  • При запуске «git fetch», а затем «git rebase»
  • Когда запускается «git pull» (что фактически соответствует одному из вышеупомянутых условий)
  • Когда работает "git stash pop"
  • Когда вы применяете git-патчи (коммиты, которые экспортируются в файлы для передачи, например, по электронной почте)

Вам необходимо установить инструмент слияния, совместимый с Git, для разрешения конфликтов. Я лично использую KDiff3, и я нашел это хорошим и удобным. Вы можете скачать его версию для Windows здесь:

https://sourceforge.net/projects/kdiff3/files/

Кстати, если вы устанавливаете Git Extensions, в его мастере настройки есть опция для установки Kdiff3.

Затем настройте git config для использования Kdiff в качестве mergetool:

$ git config --global --add merge.tool kdiff3
$ git config --global --add mergetool.kdiff3.path "C:/Program Files/KDiff3/kdiff3.exe"
$ git config --global --add mergetool.kdiff3.trustExitCode false

$ git config --global --add diff.guitool kdiff3
$ git config --global --add difftool.kdiff3.path "C:/Program Files/KDiff3/kdiff3.exe"
$ git config --global --add difftool.kdiff3.trustExitCode false

(Не забудьте заменить путь на фактический путь к исполняемому файлу Kdiff.)

Затем каждый раз, когда вы сталкиваетесь с конфликтом слияния, вам просто нужно выполнить эту команду:

$git mergetool

Затем он открывает Kdiff3 и сначала пытается автоматически разрешить конфликты слияния. Большинство конфликтов будут разрешены спонтанно, а остальные нужно исправить вручную.

Вот как выглядит Kdiff3:

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

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

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

$git mergetool
No files need merging

8

Этот ответ - добавить альтернативу тем пользователям VIM, как я, которые предпочитают делать все в редакторе.


TL; DR

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


Tpope придумали этот замечательный плагин для VIM под названием fugitive . После установки вы можете запустить, :Gstatusчтобы проверить конфликтующие файлы и :Gdiffоткрыть Git тремя способами слияния.

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

  • :diffget //2получить изменения из оригинальной ( HEAD ) ветки:
  • :diffget //3получить изменения из сливающейся ветки:

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


6

Gitlense For VS Code

Вы можете попробовать Gitlense для VS Code, ключевые характеристики которого:

3. Легко разрешать конфликты.

Мне уже нравится эта функция:

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

2. Текущая Линия Вины.

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

3. Виноват желоб

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

4. Строка состояния винить

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

И есть много возможностей, вы можете проверить их здесь .


5

git fetch
git checkout ваша ветка
git rebase master

На этом этапе вы попытаетесь исправить конфликт, используя предпочитаемую IDE

Вы можете перейти по этой ссылке, чтобы проверить, как исправить конфликт в файле
https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/

git add
git rebase - продолжить
git commit --amend
git push origin HEAD: refs / drafts / master (push как черновики)

Теперь все хорошо, и вы найдете свой коммит в геррите

Я надеюсь, что это поможет всем, кто занимается этим вопросом.


3

Попробуйте Visual Studio Code для редактирования, если вы еще этого не сделали. После попытки слияния (и попадания в конфликты слияния) .VS код автоматически обнаруживает конфликты слияния.

Это может очень помочь вам, показывая, какие изменения были внесены в оригинал и должны ли вы принять incomingили

current change(имеется в виду оригинальный перед слиянием) '?.

Это помогло мне, и это может работать на вас тоже!

PS: он будет работать, только если вы настроили git с помощью своего кода и кода Visual Studio.


2

Более безопасный способ разрешения конфликтов - это использовать git-mediate (общие решения, предлагаемые здесь, довольно подвержены ошибкам imho).

Посмотрите этот пост для краткого введения о том, как его использовать.


2

Для тех, кто использует Visual Studio (2015 в моем случае)

  1. Закройте свой проект в VS. Особенно в больших проектах VS имеет тенденцию сходить с ума при слиянии с использованием пользовательского интерфейса.

  2. Выполните слияние в командной строке.

    git checkout target_branch

    git merge source_branch

  3. Затем откройте проект в VS и перейдите в Team Explorer -> Branch. Теперь есть сообщение о том, что Merge находится на рассмотрении, а конфликтующие файлы перечислены прямо под сообщением.

  4. Нажмите конфликтующий файл, и у вас будет возможность объединить, сравнить, взять источник, взять цель. Инструмент слияния в VS очень прост в использовании.


Я использую VS Code 2017 для очень большого проекта, и мне не нужно закрывать проект. Он справляется с этим довольно хорошо :)
protoEvangelion

2

Если вы используете intelliJ в качестве IDE, попробуйте объединить родителя с вашей веткой

git checkout <localbranch>
git merge origin/<remotebranch>

Это покажет все конфликты, как это

A_MBPro: проверить происхождение слияния anu $ git / автоматическое слияние src / test / java / com /.../ TestClass.java CONFLICT (content): конфликт слияния в src / test / java / com /.../ TestClass.java

Теперь обратите внимание, что файл TestClass.java показан красным цветом в intelliJ. Также будет показан статус git.

Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified:   src/test/java/com/.../TestClass.java

Откройте файл в IntelliJ, он будет иметь разделы с

  <<<<<<< HEAD
    public void testMethod() {
    }
    =======
    public void testMethod() { ...
    }
    >>>>>>> origin/<remotebranch>

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

   git add TestClass.java
   git commit -m "commit message"
   git push

2

Я использую визуальный код Microsoft для разрешения конфликтов. Его очень просто использовать. Я держу свой проект открытым в рабочей области. Он обнаруживает и выделяет конфликты, кроме того, дает опции графического интерфейса, чтобы выбрать любое изменение, которое я хочу сохранить от HEAD или входящего. введите описание изображения здесь

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.