Конфликт слияния
Конфликт слияния (англ. merge conflict) возникает, когда Git пытается объединить изменения, но не может сам решить, какая версия файла должна победить.
Несмотря на название, конфликты слияния могут происходить во время разных операций Git, а не только при выполнении git merge. Они могут случиться, если:
- Слить одну ветку с другой через
git merge. - Перенести коммиты поверх другой ветки через
git rebase. - Получить изменения с сервера через
git pull, так как это действие обычно запускает merge или rebase после скачивания. - Применить один коммит в другом месте через
git cherry-pick. - Отменить правки коммита через
git revert, если обратные изменения нельзя применить чисто. - Применить спрятанные изменения через
git stash popилиgit stash apply.
Обычно конфликты возникают, если в двух ветках поменялись одни и те же строки в файле, или если одна ветка изменила файл, который другая ветка удалила или переименовала. В таком случае Git останавливает процесс, чтобы оставить финальное решение за тобой.
Похожие ошибки, вроде «your local changes would be overwritten» («твои локальные изменения будут перезаписаны»), — это немного другое. В этом случае Git обычно останавливается ещё до начала операции, чтобы можно было сначала сохранить или отменить свои локальные изменения.
Когда в текстовом файле возникает конфликт содержимого, Git добавляет в него маркеры конфликта:
<<<<<<< HEAD
версия из твоей текущей ветки
=======
версия, которую Git пытается влить
>>>>>>> feature-branchЧасть над ======= — это одна сторона конфликта. Часть под ней — другая. Твоя задача — отредактировать файл так, чтобы получилась нужная финальная версия, а затем удалить все маркеры конфликта.
Ours и theirs
Иногда Git и редакторы кода помечают две стороны конфликта как ours (наши) и theirs (их). Некоторые инструменты используют для этого названия current (текущие) и incoming (входящие). Будь осторожнее с этими метками: они описывают стороны текущей операции Git, а не обязательно «твою работу» и «работу кого-то другого».
При обычном слиянии (merge) смысл обычно понятен:
git switch maingit merge feature
- Ours — это
main, ветка, на которой ты находишься перед началом слияния. - Theirs — это
feature, ветка, которая вливается.
А вот при rebase метки могут казаться перевёрнутыми с ног на голову:
git switch featuregit rebase main
При rebase Git временно переносит твою работу поверх main. Если во время повторного применения коммита из feature возникает конфликт:
- Ours — это сторона
main, потому что во время rebase именно она выступает текущей базовой веткой. - Theirs — это применяемый коммит из
feature.
Это значит, что выбор ours во время rebase может привести к удалению правок из ветки, которую ты считаешь «своей». Команды вроде git restore --ours path/to/file и git restore --theirs path/to/file выбирают целиком одну сторону конфликта в файле, поэтому используй их только тогда, когда точно понимаешь, что именно Git имеет в виду под каждой из сторон в текущей операции.
Как разрешить конфликт
Обычный процесс выглядит так:
- Запусти
git status, чтобы увидеть, в каких файлах есть конфликты. - Открой каждый конфликтный файл и отредактируй его, оставив правильную финальную версию.
- Удали строки с маркерами
<<<<<<<,=======и>>>>>>>. - Добавь исправленные файлы в область подготовки с помощью
git add. - Продолжи операцию: зафиксируй слияние коммитом, запусти
git merge --continueилиgit rebase --continue, в зависимости от того, что подскажет Git.
Git не проверяет, насколько логично разрешён конфликт. Как только файл добавлен в область подготовки, Git считает его содержимое финальным ответом. Обязательно проверь результат перед продолжением.
Если конфликт произошёл неожиданно и не хочется разбираться с ним прямо сейчас, часто можно вернуться к предыдущему состоянию с помощью git merge --abort или git rebase --abort.
.gitignoregit checkoutgit configgit taggit worktree