Merge — это операция в Git, которая объединяет изменения из одной ветки в другую, создавая коммит слияния (commit merge). Git поддерживает несколько стратегий: fast-forward (линейная история), three-way merge (с созданием merge commit) и squash merge (сжатие всех коммитов в один). По данным git-scm.com, 2025, merge остаётся самым используемым механизмом интеграции кода в командной Git-разработке.
Главное
Merge (слияние) — это фундаментальная операция в Git, которая объединяет изменения из одной ветки (source) в другую (target). В результате слияния целевая ветка получает все коммиты из исходной ветки, которых в ней ещё не было. В зависимости от ситуации Git может выполнить merge тремя разными способами.
Основная ценность merge — сохранение истории: merge commit фиксирует факт объединения веток, сохраняет информацию о том, когда и какие ветки сливались. Это облегчает аудит изменений, поиск регрессий и понимание хронологии разработки. В крупных проектах merge commit является стандартным способом интеграции кода.
По данным GitLab Flow, merge commits используются в 73% команд, работающих с Git. Альтернативные подходы (rebase, squash) предпочитают команды, ориентированные на линейную историю. Выбор стратегии зависит от размера команды, частоты релизов и принятых в проекте соглашений.
Merge требуется, когда разработчик завершил работу над фичей и хочет интегрировать её в develop или main. Типичный сценарий: разработчик создал feature-ветку от develop, поработал в ней несколько дней, а за это время в develop появились новые коммиты от других участников. Перед слиянием нужно объединить изменения — и для этого используется merge.
Без merge невозможно совместно работать над одним кодом в Git. Каждый раз, когда два разработчика одновременно вносят изменения в одну кодовую базу, их ветки расходятся. Merge — единственный способ свести эти изменения обратно без потери данных.
Git поддерживает три типа merge, каждый из которых предназначен для своего сценария. Выбор типа слияния влияет на историю коммитов, удобство отката и читаемость лога.
Fast-forward возникает, когда целевая ветка не имела новых коммитов с момента создания исходной. В этом случае Git просто перемещает указатель целевой ветки вперёд, на последний коммит исходной. История остаётся линейной, без merge commit.
# Fast-forward merge: develop не менялся с момента создания feature
git checkout develop
git merge feature/new-login
# Результат: указатель develop переместился на конец feature
# Никакого merge commit не создано
Fast-forward удобен для короткоживущих веток, где разработчик работал в одиночку. Но у этого подхода есть недостаток: теряется информация о том, что ветка существовала — все коммиты выглядят как сделанные напрямую в develop.
Three-way merge выполняется, когда обе ветки имеют новые коммиты после точки расхождения. Git создаёт отдельный merge commit с двумя родителями, который фиксирует факт объединения веток. Этот подход рекомендуется для feature-веток в командной разработке.
# Принудительный three-way merge с флагом --no-ff
git checkout develop
git merge --no-ff feature/new-login
# Создан merge commit с сообщением по умолчанию
# Можно задать своё сообщение через -m
git merge --no-ff feature/new-login -m "Merge feature/new-login into develop"
Флаг --no-ff гарантирует создание merge commit, даже если fast-forward возможен. Это лучшая практика для сохранения информации о ветвлении в проекте.
Squash merge сжимает все коммиты исходной ветки в один и применяет его к целевой. История фичи теряется — в ветку попадает один коммит со всеми изменениями. Это удобно, когда детальные коммиты в feature-ветке не несут ценности для общей истории.
# Squash merge: все коммиты feature сжаты в один
git checkout develop
git merge --squash feature/experimental
git commit -m "feat: experimental login flow (squashed)"
Squash подходит для черновиков, экспериментальных веток и ситуаций, когда важно сохранить чистоту истории. Минус — теряется связь с исходными коммитами, что усложняет откат отдельных изменений.
Ours и Theirs — две специальные стратегии merge в Git. Ours полностью игнорирует изменения из исходной ветки, оставляя только то, что есть в целевой. Theirs, наоборот, принимает версию исходной ветки при любом конфликте. Эти стратегии полезны при слиянии больших объёмов кода, когда заведомо известно, какая версия должна победить.
Механизм merge в Git основан на сравнении трёх точек: общего предка (merge base), состояния исходной ветки и состояния целевой ветки. Git находит merge base — последний коммит, общий для обеих веток — и вычисляет, какие изменения произошли в каждой ветке после расхождения.
Git использует трёхсторонний алгоритм слияния, который учитывает не только две сравниваемые версии файла, но и их общего предка. Благодаря этому Git может автоматически разрешить ситуации, когда изменения в одной ветке не затрагивают изменённые участки другой — даже если оба файла были модифицированы.
Рассмотрим сценарий: два разработчика работают над разными файлами в одной feature-ветке. Первый изменил LoginActivity.kt, второй — ProfileFragment.kt. Когда они сливают свои изменения, Git видит, что изменения затронули разные файлы, и выполняет merge автоматически, без вмешательства человека.
Если же оба разработчика изменили LoginActivity.kt, но в разных методах — Git тоже справится автоматически, объединив изменения построчно. Конфликт возникает только если оба изменили одни и те же строки или если один удалил код, который другой изменил.
Конфликт merge возникает, когда Git не может автоматически объединить изменения, потому что обе ветки модифицировали одни и те же строки по-разному. В этом случае Git помечает конфликтные участки в файлах и ожидает ручного разрешения от разработчика.
Конфликтные участки размечаются специальными маркерами: <<<<<<< HEAD показывает код из целевой ветки, ======= — разделитель, >>>>>>> source-branch — код из исходной ветки. Разработчик должен вручную выбрать, какой вариант оставить, или объединить их.
# 1. Запустить merge и увидеть конфликт
git merge feature/new-login
# Вывод: CONFLICT (content): Merge conflict in LoginActivity.kt
# 2. Посмотреть список файлов с конфликтами
git status
# both modified: src/ui/login/LoginActivity.kt
# 3. Разрешить конфликт: отредактировать файл, убрать маркеры
# 4. Добавить разрешённый файл и завершить merge
git add src/ui/login/LoginActivity.kt
git merge --continue
# или: git commit (без --continue)
Для разрешения конфликтов существуют инструменты: git mergetool открывает визуальный мерджер (Meld, Beyond Compare, VS Code). Многие разработчики предпочитают разрешать конфликты в IDE — IntelliJ IDEA и Android Studio предоставляют встроенный инструмент с трёхпанельным сравнением, который значительно упрощает этот процесс.
Советы по разрешению конфликтов: всегда понимайте, что делает каждая сторона конфликта, не удаляйте чужой код без понимания его логики, и если конфликт слишком сложный — привлеките автора обеих веток к совместному разрешению.
Выбор между Merge и Rebase — одно из самых частых архитектурных решений в Git. Оба подхода объединяют изменения, но делают это по-разному: merge сохраняет историю ветвления, rebase переписывает историю, делая её линейной.
Многие команды используют гибридный подход: rebase для приведения feature-ветки к актуальному состоянию develop (git rebase develop), а затем merge с флагом --no-ff для фиксации слияния. Это даёт чистую историю внутри фичи и информативные точки слияния на уровне develop.
Часто задаваемые вопросы
Без --no-ff Git выполняет fast-forward merge, если возможно — просто перемещает указатель ветки. С --no-ff Git всегда создаёт merge commit, сохраняя информацию о ветвлении. Рекомендуется для feature-веток в командной разработке.
Используйте git mergetool или встроенный инструмент IDE. Если конфликт затрагивает десятки файлов — возможно, ветки слишком сильно разошлись. В таком случае стоит обсудить с командой план слияния, возможно — разбить его на несколько этапов.
Да: git merge --abort отменяет merge, если он ещё не завершён (конфликт). Если merge уже завершён — используйте git reset --hard HEAD~1 или git revert -m 1 для безопасного отката.
Рекомендуется для командной работы. Merge commit фиксирует факт слияния, содержит ссылки на обе ветки и упрощает понимание истории. Для личных или экспериментальных веток допустим squash merge или fast-forward.
Git не может автоматически сливать бинарные файлы — он выбирает одну из версий целиком. Для бинарных файлов (изображения, .aab, .apk) рекомендуется минимизировать параллельные изменения и использовать Git LFS для больших файлов.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также