Разрешение конфликтов
Понимание, предотвращение и устранение 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
Стратегии предотвращения конфликтов
- Чаще обновлять ветку — регулярно
git merge mainилиgit rebase main - Маленькие PR — чем меньше изменений, тем меньше конфликтов
- Разделение ответственности — разные люди работают с разными файлами
- Коммуникация — предупреждать команду о масштабном рефакторинге
- Быстро мержить — не держать ветку неделями
Сложные случаи
Конфликт при удалении файла
# Одна ветка удалила файл, другая изменила
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 всегда позволяет отменить
Практика
- Создайте конфликт: измените одну строку в двух ветках и попробуйте merge
- Разрешите конфликт вручную в текстовом редакторе
- Создайте конфликт и разрешите через VS Code с кнопками
- Попробуйте
git checkout --oursи--theirs - Создайте конфликт при rebase и разрешите через
rebase --continue - Отмените merge через
git merge --abort