Перейти к содержимому

Конфликты слияния

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

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

mergeconflicts

Распространённые прерывания слияния

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

Сбой слияния при запуске

Git не может начать слияние, потому что ожидающие изменения в рабочей директории или области индексации проекта будут перезаписаны коммитами, которые сливаются. Это происходит из-за ожидающих локальных изменений. Чтобы взять под контроль локальное состояние, используются команды git stash, git checkout, git commit и git reset. При возникновении ошибки на этапе запуска появится следующее сообщение:

конфликты git

bash
error: Your local changes to the following files would be overwritten by merge:

Сбой во время слияния

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

сбой во время слияния

bash
CONFLICT (content): Merge conflict in example.txt
Automatic merge failed; fix conflicts and then commit the result.

Создание конфликта слияния

Здесь мы покажем вам симуляцию того, как появляются конфликты слияния.

конфликты слияния

bash
mkdir test-dir
cd test-dir
git init .
echo "some content" > example.txt
git add example.txt
git commit -m "initial commit"
[master (root-commit) a45c22d] initial commit
1 file changed, 1 insertion(+)
create mode 100644 example.txt

В приведённом примере мы создаём новую директорию с именем test-dir. Далее мы создаём текстовый файл example.txt с некоторым содержимым, добавляем его в репозиторий и делаем коммит. В результате у нас появляется новый репозиторий с одной мастер-веткой и файлом example.txt. Следующий шаг — создание другой ветки, которая будет использоваться для конфликтного слияния.

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

bash
git checkout -b branch_to_merge
echo "completely different content to merge later" > example.txt
git commit -m "edit the content of example.txt to make a conflict"
[branch_to_merge 4221135] edit the content of example.txt to make a conflict
1 file changed, 1 insertion(+), 1 deletion(-)

В приведённом выше примере мы создаём и переключаемся на ветку branch_to_merge. После её создания мы перезаписываем содержимое в example.txt и делаем коммит. После выполнения всех этих действий коммит перезаписывает содержимое example.txt:

конфликты слияния git

bash
git checkout master
Switched to branch 'master'
echo "content to add" >> example.txt
git commit -m "added content to example.txt"
[master 11ab34b] added content to example.txt
1 file changed, 1 insertion(+)

Эти команды переключают на мастер-ветку, добавляют содержимое в example.txt и фиксируют изменение. Это переводит репозиторий в состояние, в котором ветки master и branch_to_merge имеют уникальные коммиты. Последний шаг — выполнение команды git merge, после которой возникнет конфликт:

git merge

bash
git merge branch_to_merge
Auto-merging example.txt
CONFLICT (content): Merge conflict in example.txt
Automatic merge failed; fix conflicts and then commit the result.

Определение конфликтов слияния

Как мы уже видели, Git выводит сообщение, указывающее на появление конфликта. Выполните команду git status, чтобы увидеть неслитые пути:

конфликты git

bash
git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified:   example.txt

Файл example.txt отображается в изменённом состоянии. Выполните команду cat, чтобы отобразить содержимое файла example.txt. Мы можем увидеть следующие визуальные маркеры:

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

bash
<<<<<<< HEAD
=======
>>>>>>> branch_to_merge

Маркер ======= указывает на центр конфликта. Содержимое между маркерами <<<<<<< HEAD и ======= принадлежит текущей ветке (master), на которую указывает ссылка HEAD. Чтобы полностью отменить слияние и вернуться к состоянию до слияния, выполните git merge --abort. Подробнее о визуальных маркерах читайте на странице git merge.

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

Чтобы разрешить конфликт слияния, необходимо отредактировать конфликтующий файл. Откройте файл example.txt в редакторе, удалите маркеры конфликтов и сохраните нужные изменения. Разрешённый файл может выглядеть так:

конфликты в git

bash
some content to mess with
content to add

Выполните команду git add, чтобы добавить новое содержимое слияния в индекс. Далее создайте новый коммит, чтобы завершить слияние:

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

bash
git add example.txt
git commit -m "the conflict in example.txt is merged and resolved"

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

ИнструментОписание
git statusПомогает найти конфликтующие файлы.
git mergetoolОткрывает визуальный инструмент сравнения для интерактивного разрешения конфликтов.
git diffПоказывает различия между коммитами, ветками или файлами, помогая выявить потенциальные конфликты до слияния.
git checkout --ours/--theirsЗаменяет конфликтующий файл содержимым из текущей или входящей ветки.
git reset --mixedОтменяет добавление файлов в индекс, но оставляет рабочую директорию без изменений.
git merge --abortОтменяет текущее слияние и восстанавливает рабочую директорию в состояние до начала слияния.
git resetСбрасывает индекс в соответствие с HEAD, помогая отменить добавление конфликтующих файлов.

Практика

Какие аспекты обработки конфликтов слияния в Git существуют?

Считаете ли это полезным?

Предпросмотр dual-run — сравните с маршрутами Symfony на продакшене.