Урок 7. Конфликты слияния и как их решать
Конфликт возникает, когда две ветки изменили одно и то же место в файле по-разному, и Git не может сам решить, какой вариант верный. Это не ошибка и не поломка: Git останавливает слияние и просит человека выбрать. Конфликт бывает при git merge, при git pull (внутри него тоже слияние) и при git rebase (переносе коммитов на другую ветку).
Как получается конфликт
В файле page.txt первая строка — Заголовок: Привет. В ветке title её заменили на Заголовок: Добро пожаловать, а в main в это же время — на Заголовок: Здравствуйте. Слияние:
$ git merge title
Auto-merging page.txt
CONFLICT (content): Merge conflict in page.txt
Automatic merge failed; fix conflicts and then commit the result.Git слил всё, что смог, и остановился на page.txt. Слияние не закончено — git status это показывает:
$ git status
On branch main
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: page.txt
no changes added to commit (use "git add" and/or "git commit -a")both modified — файл изменён в обеих ветках, и изменения столкнулись.
Как читать файл с конфликтом
Git записал в файл оба варианта и окружил их метками:
<<<<<<< HEAD
Заголовок: Здравствуйте
=======
Заголовок: Добро пожаловать
>>>>>>> title
Текст- от
<<<<<<< HEADдо=======— вариант текущей ветки (той, в которую сливаете, здесьmain); - от
=======до>>>>>>> title— вариант сливаемой веткиtitle; - строка
Текствне меток — она не конфликтует, Git оставил её как есть.
Решите конфликт
- Откройте файл в редакторе.
- Оставьте правильный вариант: один из двух, оба или новый, собранный из обоих.
- Удалите все три строки-метки:
<<<<<<<,=======и>>>>>>>. - Сохраните файл и отметьте конфликт решённым командой
git add. - Когда все файлы решены — завершите слияние коммитом.
Например, оставили Заголовок: Добро пожаловать:
$ git add page.txt
$ git status
On branch main
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: page.txt
$ git commit --no-edit
[main 0a62421] Merge branch 'title'--no-edit берёт готовое сообщение Merge branch 'title'. Без него Git откроет редактор с этим сообщением — сохраните и закройте.
Не делайте коммит, пока в файлах остались метки <<<<<<< и >>>>>>>: Git примет их как обычный текст, и в историю попадёт сломанный файл — программа перестанет запускаться. Забытые метки находит git diff --check до git add и git diff --staged --check после него.
Взять целиком одну сторону
Если ясно, что верен один вариант всего файла, его не нужно править руками — выполните одну из двух команд:
git checkout --ours page.txt
git checkout --theirs page.txtПервая оставляет версию текущей ветки, вторая — сливаемой. После неё — git add page.txt, как обычно. То же делают git restore --ours и git restore --theirs.
При git rebase стороны меняются местами: ours — ветка, на которую переносятся коммиты, а theirs — ваши переносимые коммиты. Если сомневаетесь, откройте файл и выберите вариант глазами.
Передумали — отмените слияние
git merge --abortВсё вернётся к состоянию до git merge, как будто слияния не было. Это безопасный выход, если конфликт оказался сложнее, чем казалось, и нужно сначала разобраться или спросить автора другой ветки.
Конфликт в редакторе
Редакторы кода подсвечивают конфликты и дают кнопки выбора. Например, Visual Studio Code показывает над конфликтом «Accept Current Change» (свой вариант), «Accept Incoming Change» (вариант другой ветки) и «Accept Both Changes» (оба). Нажатие кнопки только правит файл — git add и коммит всё равно нужны.
Как реже попадать в конфликты
- Чаще обменивайтесь. Чем дольше ветка живёт отдельно, тем больше она расходится с основной. Забирайте свежую
mainи сливайте небольшие ветки быстро. - Мелкие коммиты. Небольшие правки легче объединить и проще понять при конфликте.
- Не переформатируйте чужой код без нужды. Замена отступов во всём файле меняет каждую строку — и конфликтует со всеми, кто правил этот файл.
- Договаривайтесь. Если двое правят один и тот же кусок, проще решить это словами до слияния.
Коротко
- Конфликт — две ветки по-разному изменили одни и те же строки; Git просит выбрать.
- Метки:
<<<<<<< HEAD— свой вариант,=======— граница,>>>>>>> ветка— вариант другой ветки. - Решение: поправить файл, убрать метки,
git add, затемgit commit. git checkout --oursили--theirs— взять файл целиком с одной стороны.git merge --abort— отменить слияние и вернуться как было.