Перейти к содержанию
Innovialabs

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

Практика4 мин

Коротко

Конфликт возникает, когда две ветки по-разному изменили одни и те же строки; вы выбираете итоговый вариант, удаляете маркеры, делаете git add и завершаете слияние.

Короткий ответ

Конфликт слияния — это не ошибка, а вопрос Git к вам: «две ветки изменили одно и то же место по-разному, какой вариант оставить?». Алгоритм всегда одинаковый:

  1. Запустите git status и найдите файлы в разделе Unmerged paths.
  2. Откройте каждый файл, найдите маркеры <<<<<<<, =======, >>>>>>>.
  3. Оставьте правильный код и удалите маркеры.
  4. Выполните git add <файл> для каждого исправленного файла.
  5. Завершите операцию: git commit для merge или git rebase --continue для rebase.

Почему возникают конфликты

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

  • в обеих ветках изменили одни и те же строки одного файла;
  • в одной ветке файл удалили, а в другой — изменили;
  • обе ветки создали файл с одинаковым именем и разным содержимым.

Чем дольше ветка живет отдельно от основной, тем выше шанс, что кто-то поменяет тот же код.

Как читать маркеры конфликта

Внутри файла Git показывает обе версии:

<<<<<<< HEAD
const timeout = 3000;
=======
const timeout = 5000;
>>>>>>> feature/retry
  • Между <<<<<<< HEAD и ======= — ваша текущая ветка (та, в которую вы сливаете).
  • Между ======= и >>>>>>> feature/retry — входящие изменения.

Важная деталь: при rebase роли меняются местами. HEAD там — это ветка, на которую вы перебазируетесь, а «входящие» — ваши собственные коммиты.

Если включить стиль diff3 (или zdiff3 в новых версиях Git), появится еще и исходная версия до изменений — это сильно упрощает понимание, кто что поменял:

git config --global merge.conflictStyle diff3

Разрешение в терминале

git merge feature/retry
# CONFLICT (content): Merge conflict in src/config.js

git status                 # список конфликтных файлов
# правим файл вручную
git add src/config.js
git commit                 # Git предложит готовое сообщение merge-коммита

Если нужно целиком взять одну из сторон для файла:

git checkout --ours src/config.js    # оставить версию текущей ветки
git checkout --theirs src/config.js  # взять входящую версию
git add src/config.js

Помните про подмену ролей при rebase: там --ours и --theirs тоже меняются местами.

Разрешение в VS Code

VS Code подсвечивает конфликты и показывает над ними кнопки:

  • Accept Current Change — оставить вашу версию;
  • Accept Incoming Change — взять входящую;
  • Accept Both Changes — оставить обе (часто потом нужно доработать руками);
  • Compare Changes — открыть сравнение.

Для сложных случаев есть Merge Editor: три панели — входящие изменения, текущие и итоговый результат. После правки сохраните файл и нажмите «+» (stage) в панели Source Control.

Как безопасно отменить

Если запутались, можно вернуться в исходное состояние:

git merge --abort    # отменить слияние
git rebase --abort   # отменить rebase
git cherry-pick --abort

Эти команды возвращают ветку к состоянию до начала операции. Перед слиянием лучше закоммитить или спрятать (git stash) незавершенную работу, чтобы отмена ничего не задела.

Частые ошибки

  • Забытые маркеры. Код с <<<<<<< закоммитили — сборка падает. Перед коммитом выполните поиск по маркерам или git diff --check.
  • «Accept Both» без проверки. Две версии функции рядом — это часто дубликат или сломанная логика.
  • Не запустили тесты. Конфликт решен синтаксически, но поведение могло измениться. Прогоните тесты и соберите проект.
  • Решение наугад. Если не понимаете, зачем коллега изменил код, спросите его — это быстрее, чем искать баг потом.

Как снизить количество конфликтов

  • Маленькие PR. Чем меньше изменений и чем быстрее они вливаются, тем меньше пересечений.
  • Регулярно подтягивайте основную ветку в свою (git pull --rebase или merge из main).
  • Единое форматирование. Prettier, Black и подобные инструменты убирают конфликты из-за пробелов и кавычек.
  • Не смешивайте рефакторинг и фичи. Массовое переименование лучше вынести в отдельный быстрый PR.
  • Договоритесь о зонах ответственности, когда несколько человек работают в одном модуле.

Частые вопросы

Конфликты те же самые, разница в истории. Merge решает их один раз в merge-коммите, rebase — на каждом перебазируемом коммите. Для своих локальных веток удобен rebase, для общих — merge.

Поможем с этим

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

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.