Программирование и IT
git merge
Слияние переносит работу из одной ветки в другую. Команда git merge берёт указанную ветку и соединяет её историю с текущей — иногда просто сдвигая указатель, иногда создавая отдельный коммит, а иногда останавливаясь и прося помощи.
В этой статье
Куда и что вливается#
Направление у слияния всегда одно: из названной ветки в ту, где ты стоишь.
Поэтому первым делом переключаются на приёмник, а уже потом называют
источник:
Ветка-источник после этого никуда не девается и остаётся на своём коммите —
её либо удаляют как отработавшую, либо продолжают в ней работать. Как
устроены сами указатели, разобрано в статье про
git branch.
Перемотка и настоящее слияние#
Если в main с момента ответвления не появилось ни одного коммита, git не
станет ничего придумывать — просто передвинет указатель вперёд:
Updating 4f1c2ab..9d31c07
Fast-forward
export.py | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 export.py
Если же обе ветки успели уйти вперёд, появляется коммит с двумя
родителями:
Merge made by the 'ort' strategy.
export.py | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
ort — имя алгоритма слияния в свежих версиях git, в старых на его месте
было recursive; на смысл вывода это не влияет.
| Ключ | Что меняет |
|---|---|
--no-ff |
коммит слияния создаётся всегда, даже когда хватило бы перемотки |
--ff-only |
наоборот, слить только перемоткой, иначе отказать |
--squash |
сложить все коммиты ветки в один набор правок без коммита слияния |
--no-commit |
остановиться до записи, чтобы посмотреть результат |
-m "текст" |
своё сообщение для коммита слияния |
--abort |
бросить незавершённое слияние и вернуть всё назад |
--no-ff любят там, где важно видеть в истории, что группа коммитов —
одна задача. --squash удобен, когда в ветке двадцать мелких коммитов
вроде «опечатка», и в общей истории они не нужны: после него правки лежат в
индексе, и их надо закоммитить самому через
git commit.
Конфликт: что это и что делать#
Конфликт возникает, когда один и тот же кусок файла изменён по-разному в
обеих ветках. Автоматика тут не угадывает:
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
Git не откатывается назад, а оставляет работу посередине: слитое уже лежит
в индексе, спорное помечено прямо в файле.
<<<<<<< HEAD
Запуск: python app.py
=======
Запуск: python -m app
>>>>>>> feature/export
Сверху — версия из текущей ветки, снизу — из вливаемой. Разбор идёт так:
git status— раздел «Unmerged paths» перечислит спорные файлы.- Открыть каждый, оставить верный текст и убрать все три строки разметки.
git add README.md— этим ты говоришь, что файл разрешён.git merge --continue(илиgit commit) — записать коммит слияния.
Полезная мелочь: git checkout --ours README.md берёт целиком версию
текущей ветки, --theirs — версию вливаемой. Это спасает в конфликтах
служебных файлов, где смешивать нечего.
Как отменить слияние#
Слияние не завершено, файл в разметке конфликта, хочется начать заново:
Ветка и рабочий каталог возвращаются в состояние до команды.
Коммит слияния уже создан и никуда не отправлен:
ORIG_HEAD хранит положение ветки до начала слияния. Ключ --hard стирает
незакоммиченное, поэтому сначала убедись, что несохранённой работы нет.
Слияние уже на сервере и его видели другие — переписывать историю нельзя,
отменяют новым коммитом:
Число после -m — номер родителя, которого нужно считать основной линией;
1 означает ту ветку, в которую вливали. Подробнее про отправку и её
отказы — в статье про git push.
Как посмотреть результат#
Косые линии слева показывают, где история расходилась и где соединялась.
Если картинка не похожа на ожидаемую, ничего страшного: пока коммиты не
отправлены, любое слияние отменяется без следа, а прежние положения ветки
перечислены в git reflog.
План по этапам
- Обновить приёмникПереключиться на ветку-приёмник и забрать свежие коммиты с сервера.
- Посмотреть, что вольётсяgit log --oneline main..feature — список коммитов источника.
- Выполнить слияниеgit merge feature; при необходимости --no-ff или --squash.
- Разобрать конфликтыПоправить файлы, убрать разметку, git add, git merge --continue.
- Проверить и прибратьсяПрогнать тесты, затем удалить отработавшую ветку git branch -d.
Начать изучать эту тему у себя
План ляжет в твой репозиторий: отмечай этапы, веди конспект — история изменений покажет, как ты продвинулся.
Проверь себя
1.Слияние остановилось на конфликте. Какая команда вернёт всё как было до merge?
2.Что делает git merge --no-ff?
3.Конфликтный файл отредактирован, разметка убрана. Что дальше?
Источники
-
Pro Git, книга на русскомРазделы про слияние веток и разрешение конфликтовбесплатно
-
Справка git mergeСтратегии, ключи и поведение при конфликтебесплатно
Было полезно?