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 использует три точки для вычисления слияния:
- Общий предок (
B) -- где ветки разошлись - Вершина main (
E) -- ваша текущая ветка - Вершина 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 сохраняет историю чистой и линейной. Трёхстороннее слияние сохраняет контекст веток с функциональностью. Большинство команд выбирают соглашение и придерживаются его.