Как работает git merge и какие стратегии слияния существуют
Что проверяют
Понимаете ли вы, что происходит с историей при слиянии и откуда берутся конфликты. Для QA это практический вопрос: следом часто спрашивают, как найти коммит, который принёс баг в сборку, и где тестировать, в ветке фичи или после слияния.
Как отвечать
git merge feature вливает ветку в текущую. Git находит общего предка (merge base) и дальше идёт одним из путей:
- fast-forward: в текущей ветке нет новых коммитов после предка, и Git просто сдвигает указатель.
--ff-onlyзапрещает другие варианты,--no-ffвсегда создаёт коммит слияния, чтобы сохранить границы фичи; - трёхстороннее слияние: изменения есть в обеих ветках. Git сравнивает предка с каждой вершиной, переносит непересекающиеся правки и создаёт коммит с двумя родителями. Где обе стороны меняли одно место, возникает конфликт.
Стратегии задаются флагом -s:
ort: по умолчанию начиная с Git 2.34, заменилаrecursive;resolve: старый простой вариант для двух веток;octopus: слияние больше двух веток сразу, при конфликте отказывается работать;ours: берёт результат текущей ветки целиком, чужие изменения отбрасываются, остаётся только запись в истории.
Отдельно опции стратегии: -X ours и -X theirs решают в пользу одной стороны только конфликтные куски. --squash сжимает ветку в один набор изменений без коммита слияния. Rebase не стратегия слияния, а другой способ интеграции, который переписывает коммиты.
При конфликте правите маркеры <<<<<<<, делаете git add и git commit или откатываетесь через git merge --abort.
Где спотыкаются
Путают -s ours и -X ours. Первая стратегия выбрасывает всю чужую работу, вторая опция касается только конфликтов.
Считают, что слияние без конфликтов безопасно. Две ветки могут пройти тесты по отдельности и сломаться вместе, поэтому регресс гоняют на результате слияния.
Не умеют искать виновника. Помогают git log --merges --first-parent main и git bisect, который двоичным поиском находит коммит, где тест начал падать.