Слияние веток: merge, fast-forward и merge-коммит

Соединяем работу из разных веток воедино и разбираемся в двух видах слияния.

Слияние (merge) — объединение изменений из одной ветки в другую.

Как выполнить merge

Главное правило: вы переключаетесь на ветку, в которую хотите влить изменения, и затем сливаете в неё другую ветку. Чтобы влить feature в main:

git switch main
git merge feature

Звучит контринтуитивно, но запомните: «куда вливаем — там и стоим».

Fast-forward: просто двигаем указатель

Если в main не было новых коммитов с момента создания feature, git делает fast-forward: ему достаточно сдвинуть указатель main вперёд на последний коммит feature. Новый коммит не создаётся, история остаётся линейной.

Вывод:

Updating 9f8e7d6..a1b2c3d
Fast-forward
 login.py | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

Merge-коммит: когда история разошлась

Если за время работы над feature в main тоже появились коммиты, истории разошлись. Простым сдвигом указателя не обойтись — git создаёт особый merge-коммит с двумя родителями, который объединяет обе линии истории.

Вывод:

Merge made by the 'ort' strategy.
 search.py | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
ТипКогдаРезультат
Fast-forwardв целевой ветке не было новых коммитовуказатель просто сдвигается, новый коммит не создаётся
Merge-коммитистории разошлисьсоздаётся коммит с двумя родителями

Управляем поведением

Иногда merge-коммит хотят создать всегда — чтобы в истории было явно видно факт слияния ветки:

git merge --no-ff feature

А флаг --ff-only, наоборот, разрешает слияние только если оно возможно fast-forward, иначе откажет. Это удобно, чтобы держать историю линейной.

После слияния

Влитую ветку обычно удаляют, чтобы не захламлять список:

git branch -d feature

Откуда у merge-коммита два родителя

Обычный коммит ссылается на один предыдущий — своего родителя. Merge-коммит особенный: у него два родителя — последний коммит каждой из сливаемых веток. Именно так git «сшивает» две разошедшиеся линии истории в одну. Если позже посмотреть историю с графом (git log --graph), вы увидите, как две ветки расходятся, а потом снова сходятся в merge-коммите.

Линейная история или явные слияния

У команд разный вкус к виду истории. Одни любят, когда каждое слияние ветки видно явным merge-коммитом — так нагляднее, какая фича когда влилась; для этого используют --no-ff. Другие предпочитают плоскую линейную историю без «развилок» — её добиваются через rebase (последний раздел курса). Оба подхода рабочие; главное — договориться внутри команды и придерживаться одного.

Итог

  • Стойте на ветке-получателе, затем git merge <ветка-источник>.
  • Fast-forward просто двигает указатель, если история не расходилась.
  • Merge-коммит с двумя родителями создаётся, когда истории разошлись.
Проверьте себя
1. Вы хотите влить ветку feature в main. Какая последовательность верна?
Agit switch feature; git merge main
Bgit switch main; git merge feature
Cgit merge main feature
Dgit switch feature; git merge feature
2. Когда git выполняет слияние через fast-forward?
AВсегда при любом merge
BКогда в целевой ветке не было новых коммитов и историю можно просто продлить
CТолько при конфликтах
DКогда сливаются три ветки сразу
3. Что такое merge-коммит?
AКоммит, который удаляет ветку
BКоммит с двумя родителями, объединяющий разошедшиеся истории
CПервый коммит в репозитории
DКоммит без сообщения
Поддержать проект