Стратегии слияния -- ours, theirs, recursive
Когда вы выполняете git merge, Git не всегда объединяет изменения одинаково. Он выбирает стратегию слияния в зависимости от ситуации, и вы можете переопределить этот выбор. Понимание доступных стратегий даёт вам тонкий контроль над тем, как ветки объединяются.
По умолчанию: стратегия Recursive
Для большинства слияний двух веток Git использует стратегию recursive. Она находит общего предка обеих веток и выполняет трёхстороннее слияние, создавая коммит слияния, если ветки разошлись.
git merge feature
# Эквивалентно:
git merge --strategy=recursive feature
Стратегия recursive хорошо справляется с большинством случаев, включая ситуации, когда есть несколько общих предков (она рекурсивно сливает предков, создавая виртуальную базу).
Опции стратегии: -X ours и -X theirs
Стратегия recursive принимает опции, которые управляют разрешением конфликтов:
git merge -X ours feature
git merge -X theirs feature
-X ours-- При возникновении конфликта автоматически выбирать нашу версию (текущая ветка)-X theirs-- При возникновении конфликта автоматически выбирать их версию (сливаемая ветка)
Неконфликтующие изменения с обеих сторон по-прежнему сливаются нормально. Эти опции влияют только на строки, где обе ветки внесли разные изменения в одно и то же место.
Стратегия ours (это не то же самое!)
Существует совершенно другая стратегия под названием ours:
git merge --strategy=ours feature
Это создаёт коммит слияния, но полностью игнорирует изменения другой ветки. Результат идентичен содержимому текущей ветки. Другая ветка записывается как родитель (чтобы Git знал, что она была "слита"), но ни одно из её изменений не применяется.
Критическое различие
| Команда | Что она делает |
|---|---|
git merge -X ours feature | Сливает нормально, автоматически разрешает конфликты в пользу нашей стороны |
git merge --strategy=ours feature | Игнорирует все изменения из feature, сохраняет наше дерево без изменений |
Первая -- это предпочтение при разрешении конфликтов. Вторая -- способ пометить ветку как слитую, не принимая ни одного из её изменений.
Когда полезна --strategy=ours?
- Закрытие ветки, которую вы не хотите сливать, но хотите пометить как "готовую"
- Установление того, что ваша ветка заменяет другую без включения её изменений
- Предотвращение будущих слияний от повторного внесения изменений из этой ветки
Стратегия theirs
Встроенной --strategy=theirs не существует, но вы можете добиться того же эффекта:
git merge -s ours feature # помечает feature как слитую, сохраняет наше содержимое
# Чтобы сделать обратное (сохранить полностью их версию):
git merge -X theirs feature # сливает, разрешая все конфликты в их пользу
Для настоящей "стратегии theirs" (полностью отбросить наши изменения) потребуется ручной подход, или можно использовать git merge -X theirs, что достаточно близко для большинства случаев.
Octopus-слияние
Когда нужно слить более двух веток одновременно, Git использует стратегию octopus:
git merge feature-a feature-b feature-c
Git автоматически выбирает стратегию octopus, когда указано несколько веток. Она хорошо работает, когда ветки не конфликтуют друг с другом -- например, когда разные команды работали над совершенно разными файлами.
Octopus-слияния не умеют обрабатывать конфликты. Если какая-либо ветка конфликтует с другой, Git прерывает операцию и просит вас сливать ветки по одной.
После octopus-слияния:
main: A --- B ----------- M
\ \ /|
feature-a: C \ / |
feature-b: D \/ |
feature-c: E ---+---
Коммит слияния M имеет несколько родителей -- по одному на каждую слитую ветку.
Итог
| Стратегия | Флаг | Случай использования |
|---|---|---|
| recursive (по умолчанию) | --strategy=recursive | Обычное слияние двух веток |
-X ours | Опция recursive | Автоматическое разрешение конфликтов в нашу пользу |
-X theirs | Опция recursive | Автоматическое разрешение конфликтов в их пользу |
ours | --strategy=ours | Записать слияние, но полностью отбросить их изменения |
| octopus | --strategy=octopus | Слияние нескольких веток одновременно (конфликты не допускаются) |
Ключевая идея
Самый частый источник путаницы -- это --strategy=ours и -X ours. Запомните: стратегия определяет общий алгоритм, а -X опции настраивают разрешение конфликтов внутри этого алгоритма. Когда кто-то говорит "слей с ours", всегда уточняйте, что именно имеется в виду.