Тур по Git
Ветвление и слияние / Урок 2.6

Fast-Forward и трёхстороннее слияние

Когда вы выполняете git merge, Git выбирает одну из двух стратегий в зависимости от истории веток. Понимание разницы помогает читать граф коммитов и предсказывать результат.

Fast-Forward слияние

Fast-forward слияние происходит, когда в целевой ветке нет новых коммитов с момента создания ветки с функциональностью. Git просто перемещает указатель ветки вперёд -- коммит слияния не нужен.

До:
main:     A --- B
                 \
feature:          C --- D

После (git merge feature):
main:     A --- B --- C --- D
                              ^
                              main, feature

Коммит слияния не создаётся. Указатель main просто "перематывается вперёд" туда, где уже находится feature. История остаётся полностью линейной.

Когда это происходит?

  • Вы создаёте ветку, делаете коммиты, и никто другой не коммитит в main тем временем
  • Это самый простой случай -- расходящейся работы не существует

Трёхстороннее слияние

Трёхстороннее слияние происходит, когда в обеих ветках есть новые коммиты. Git находит общего предка и создаёт новый коммит слияния, объединяющий обе линии работы.

До:
main:     A --- B --- E
                 \
feature:          C --- D

После (git merge feature):
main:     A --- B --- E --- M
                 \         /
feature:          C --- D

Коммит M -- это коммит слияния. У него два родителя: E и D. Git использует три точки для вычисления слияния:

  1. Общий предок (B) -- где ветки разошлись
  2. Вершина main (E) -- ваша текущая ветка
  3. Вершина feature (D) -- ветка, которая сливается

Поэтому это называется "трёхсторонним" слиянием.

Принудительное создание коммита слияния

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

git merge --no-ff feature

Это создаёт коммит слияния в любом случае:

main:     A --- B --------- M
                 \         /
feature:          C --- D

Многие команды предпочитают --no-ff, потому что это сохраняет историю веток видимой в графе.

Принудительный только fast-forward

Если вы хотите гарантировать, что коммит слияния не будет создан (и получить ошибку, если он потребуется):

git merge --ff-only feature

Это полезно в скриптах или CI-пайплайнах, где вы хотите линейную историю и предпочитаете перебазирование вместо слияния.

Итог

СтратегияКогда срабатываетСоздаёт коммит слияния?Форма истории
Fast-forwardНет расходящихся коммитовНетЛинейная
ТрёхстороннееОбе ветки имеют коммитыДаРомб/вилка
--no-ffПринудительно через флагВсегдаРомб/вилка
--ff-onlyПринудительно через флагНикогда (ошибка, если невозможно)Линейная

Ключевая идея

Ни одна стратегия не является "лучше" -- они служат разным целям. Fast-forward сохраняет историю чистой и линейной. Трёхстороннее слияние сохраняет контекст веток с функциональностью. Большинство команд выбирают соглашение и придерживаются его.