Разрешение конфликтов

Понимание, предотвращение и устранение merge-конфликтов в Git

Зачем нужно

  • Конфликты неизбежны при работе в команде
  • Неправильное разрешение может потерять чужой код
  • Умение быстро разрешать конфликты экономит время

Где используется

  • При merge веток с пересекающимися изменениями
  • При rebase
  • При cherry-pick
  • При git pull (pull = fetch + merge)

Предпосылки

Когда возникают конфликты

Конфликт возникает когда две ветки изменили одну и ту же строку одного файла:

# Ветка main: строка 5 файла app.js
const title = "Hello World";

# Ветка feature: строка 5 того же файла
const title = "Welcome";

# При merge Git не знает какую версию оставить → КОНФЛИКТ

Конфликтов не будет если:

  • Изменены разные файлы
  • Изменены разные строки одного файла
  • Одна ветка не трогала файл, а другая изменила

Маркеры конфликтов

При конфликте Git вставляет маркеры в файл:

function getTitle() {
<<<<<<< HEAD
    return "Hello World";
=======
    return "Welcome";
>>>>>>> feature
}
Маркер Значение
<<<<<<< HEAD Начало текущей ветки (куда мержим)
======= Разделитель
>>>>>>> feature Конец входящей ветки (откуда мержим)

Пошаговое разрешение

1. Обнаружить конфликт

git merge feature
# Auto-merging app.js
# CONFLICT (merge conflict): Merge conflict in app.js
# Automatic merge failed; fix conflicts and then commit the result.

git status
# Unmerged paths:
#   both modified:   app.js

2. Открыть файл и разрешить

Варианты разрешения:

Оставить версию текущей ветки (ours):

function getTitle() {
    return "Hello World";
}

Оставить версию входящей ветки (theirs):

function getTitle() {
    return "Welcome";
}

Объединить оба изменения:

function getTitle(isNewUser) {
    return isNewUser ? "Welcome" : "Hello World";
}

3. Убрать маркеры и сохранить

Удалите ВСЕ маркеры (<<<<<<<, =======, >>>>>>>) и оставьте итоговый код.

4. Добавить и закоммитить

git add app.js
git commit
# Git автоматически создаст merge-коммит с описанием конфликта

# Или с кастомным сообщением
git commit -m "Merge feature: совместить оба варианта заголовка"

Разрешение через командную строку

# Принять полностью версию текущей ветки
git checkout --ours app.js

# Принять полностью версию входящей ветки
git checkout --theirs app.js

# Не забыть добавить
git add app.js

Merge-инструменты

VS Code (встроенный)

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

  • Accept Current Change — оставить HEAD
  • Accept Incoming Change — принять входящую ветку
  • Accept Both Changes — оставить оба варианта
  • Compare Changes — сравнить бок о бок

Настройка внешнего mergetool

# Настроить VS Code как mergetool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait --merge $REMOTE $LOCAL $BASE $MERGED'

# Запустить mergetool
git mergetool

Другие инструменты

# Meld (Linux)
git config --global merge.tool meld

# KDiff3
git config --global merge.tool kdiff3

# Beyond Compare
git config --global merge.tool bc3

Отмена merge

# Отменить merge до разрешения конфликтов
git merge --abort

# Отменить rebase с конфликтами
git rebase --abort

# Вернуться к состоянию до merge (если уже закоммитили)
git reset --hard HEAD~1

Конфликты при rebase

При rebase конфликты могут возникать на каждом коммите:

git rebase main
# CONFLICT in app.js

# 1. Разрешить конфликт
# 2. git add app.js
# 3. Продолжить rebase:
git rebase --continue

# Если конфликт снова — повторить
# Или отменить всё:
git rebase --abort

Стратегии предотвращения конфликтов

  1. Чаще обновлять ветку — регулярно git merge main или git rebase main
  2. Маленькие PR — чем меньше изменений, тем меньше конфликтов
  3. Разделение ответственности — разные люди работают с разными файлами
  4. Коммуникация — предупреждать команду о масштабном рефакторинге
  5. Быстро мержить — не держать ветку неделями

Сложные случаи

Конфликт при удалении файла

# Одна ветка удалила файл, другая изменила
git status
# deleted by us:   old-file.js

# Оставить файл:
git add old-file.js

# Удалить файл:
git rm old-file.js

Конфликт в бинарных файлах

# Git не может мержить бинарные файлы (изображения, PDF)
# Нужно выбрать одну из версий:
git checkout --ours image.png
# или
git checkout --theirs image.png
git add image.png

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

  • Не удалить все маркеры конфликтов — код с <<<<<<< не скомпилируется
  • Удалить чужой код случайно — всегда проверяйте что в обеих версиях
  • git merge --abort после частичного разрешения — теряется вся работа по разрешению
  • Не тестировать после разрешения — разрешённый конфликт может содержать логические ошибки
  • Паниковать — конфликты это нормально, Git всегда позволяет отменить

Практика

  1. Создайте конфликт: измените одну строку в двух ветках и попробуйте merge
  2. Разрешите конфликт вручную в текстовом редакторе
  3. Создайте конфликт и разрешите через VS Code с кнопками
  4. Попробуйте git checkout --ours и --theirs
  5. Создайте конфликт при rebase и разрешите через rebase --continue
  6. Отмените merge через git merge --abort

Связанные темы

Ресурсы