Программирование и IT

git merge

Слияние переносит работу из одной ветки в другую. Команда git merge берёт указанную ветку и соединяет её историю с текущей — иногда просто сдвигая указатель, иногда создавая отдельный коммит, а иногда останавливаясь и прося помощи.

Обновлено
В этой статье

Куда и что вливается#

Направление у слияния всегда одно: из названной ветки в ту, где ты стоишь.
Поэтому первым делом переключаются на приёмник, а уже потом называют
источник:

git switch main
git merge feature/export

Ветка-источник после этого никуда не девается и остаётся на своём коммите —
её либо удаляют как отработавшую, либо продолжают в ней работать. Как
устроены сами указатели, разобрано в статье про
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

Сверху — версия из текущей ветки, снизу — из вливаемой. Разбор идёт так:

  1. git status — раздел «Unmerged paths» перечислит спорные файлы.
  2. Открыть каждый, оставить верный текст и убрать все три строки разметки.
  3. git add README.md — этим ты говоришь, что файл разрешён.
  4. git merge --continue (или git commit) — записать коммит слияния.

Полезная мелочь: git checkout --ours README.md берёт целиком версию
текущей ветки, --theirs — версию вливаемой. Это спасает в конфликтах
служебных файлов, где смешивать нечего.

Как отменить слияние#

Слияние не завершено, файл в разметке конфликта, хочется начать заново:

git merge --abort

Ветка и рабочий каталог возвращаются в состояние до команды.

Коммит слияния уже создан и никуда не отправлен:

git reset --hard ORIG_HEAD

ORIG_HEAD хранит положение ветки до начала слияния. Ключ --hard стирает
незакоммиченное, поэтому сначала убедись, что несохранённой работы нет.

Слияние уже на сервере и его видели другие — переписывать историю нельзя,
отменяют новым коммитом:

git revert -m 1 8b2d5e9

Число после -m — номер родителя, которого нужно считать основной линией;
1 означает ту ветку, в которую вливали. Подробнее про отправку и её
отказы — в статье про git push.

Как посмотреть результат#

git log --oneline --graph -12

Косые линии слева показывают, где история расходилась и где соединялась.
Если картинка не похожа на ожидаемую, ничего страшного: пока коммиты не
отправлены, любое слияние отменяется без следа, а прежние положения ветки
перечислены в git reflog.

План по этапам

  1. Обновить приёмникПереключиться на ветку-приёмник и забрать свежие коммиты с сервера.
  2. Посмотреть, что вольётсяgit log --oneline main..feature — список коммитов источника.
  3. Выполнить слияниеgit merge feature; при необходимости --no-ff или --squash.
  4. Разобрать конфликтыПоправить файлы, убрать разметку, git add, git merge --continue.
  5. Проверить и прибратьсяПрогнать тесты, затем удалить отработавшую ветку git branch -d.

Начать изучать эту тему у себя

План ляжет в твой репозиторий: отмечай этапы, веди конспект — история изменений покажет, как ты продвинулся.

Начать план

Проверь себя

1.Слияние остановилось на конфликте. Какая команда вернёт всё как было до merge?

2.Что делает git merge --no-ff?

3.Конфликтный файл отредактирован, разметка убрана. Что дальше?

Источники

Было полезно?

Ещё темы

Программирование и IT git push Пока ты не выполнил git push, твои коммиты существуют только на твоём диске. Команда отправляет их в удалённый репозиторий и сдвигает там указатель ветки — поэтому она же чаще всего и отказывает, если кто-то успел отправить своё раньше. Программирование и IT git commit Коммит — это сохранённое состояние проекта с автором, временем и сообщением. Команда git commit берёт то, что ты заранее отобрал командой git add, и записывает это в историю одной неделимой порцией. Программирование и IT git clone Команда git clone забирает репозиторий с сервера целиком — со всей историей, ветками и тегами — и кладёт копию в новую папку на твоём компьютере. С неё начинается работа с любым уже существующим проектом, своим или чужим. Программирование и IT git rebase Команда переносит коммиты твоей ветки так, будто ты начал работу не от старого состояния, а от текущего. История становится линейной, но коммиты при этом создаются заново — с новыми хешами. Отсюда главное ограничение: переносить можно только то, чем не пользуется никто другой. Программирование и IT Как разрешить конфликт слияния Конфликт — не поломка, а вопрос. Git сливает изменения автоматически, пока они в разных местах файла; когда две ветки правят одни и те же строки, выбрать правильный вариант может только человек. Задача — прочитать оба варианта, собрать из них рабочий код и сказать git, что вопрос закрыт. Программирование и IT Как создать репозиторий с нуля Репозиторий — это папка проекта плюс скрытая папка `.git`, в которой хранится вся история. Создаётся одной командой, но между ней и первым осмысленным коммитом есть несколько шагов, которые потом трудно переделать: имя ветки, список игнорируемых файлов, привязка к серверу.

Ещё сценарии