Git rebase vs merge: когда что использовать и в чём разница
git merge и git rebase решают одну задачу — интеграцию изменений из веток, — но по-разному. Разбираем оба подхода, объясняем interactive rebase и формулируем золотое правило, которое сохранит нервы вашей команды.
Если вы работаете с Git в команде, рано или поздно встаёт вопрос: как объединить ветки — через git merge или через git rebase? Оба инструмента решают одну задачу — интегрируют изменения из одной ветки в другую, — но делают это совершенно по-разному. Неправильный выбор может превратить историю репозитория в хаос или создать проблемы для всей команды.
В этой статье разберём, как работает каждая команда, когда что применять и почему нарушение золотого правила rebase ведёт к конфликтам у коллег. Статья подойдёт разработчикам, которые уже знакомы с базовыми командами Git и хотят разобраться с ветвлением и историей коммитов.
Ключевые выводы
— merge создаёт merge-коммит и сохраняет полную историю веток — когда и откуда пришли изменения.
— rebase переносит коммиты на новую базу и создаёт линейную историю без лишних merge-коммитов.
— Золотое правило: никогда не ребейсить публичные ветки, которые уже запушены и используются другими.
— feature-ветки перед слиянием — rebase; main/develop при получении чужих изменений — merge или pull --rebase.
— interactive rebase (git rebase -i) позволяет склеить, переименовать и отредактировать коммиты до публикации.
Также полезно изучить полезные команды Git — там собраны практические приёмы на каждый день.
Как работает git merge
git merge объединяет две ветки, создавая новый коммит — merge-коммит. Этот коммит имеет двух родителей: последний коммит текущей ветки и последний коммит ветки, которую вы вливаете. История полностью сохраняется: видно, когда ветка была создана, что в ней менялось, когда слита обратно.
Merge безопасен для публичных веток: он только добавляет новый коммит, не меняя существующие. Коллеги, которые уже склонировали репозиторий, без проблем сделают git pull и получат обновлённую историю.
Минус — при активной разработке история быстро засоряется merge-коммитами. Если в команде 10 человек и у каждого по несколько веток, граф становится нечитаемым.
Как работает git rebase
git rebase переносит коммиты текущей ветки на новую базу — то есть «перекладывает» их поверх другой ветки. При этом Git создаёт новые коммиты с теми же изменениями, но другими хешами. Результат — линейная история без лишних merge-коммитов.
Обратите внимание: D и E превращаются в D' и E' — это другие коммиты. Именно поэтому rebase опасен для ветки, которую уже видели другие разработчики: у них в локальных репозиториях останутся старые D и E, а в origin появятся новые D' и E'. При следующем git pull возникнет путаница и конфликты.
Interactive rebase: squash, fixup, reword
Флаг -i (interactive) открывает редактор со списком коммитов, которые можно переупорядочить и изменить перед публикацией. Это мощный инструмент для «уборки» истории feature-ветки до создания pull request.
Откроется список вида:
Команды, доступные в interactive rebase:
squash(илиs) — склеить коммит с предыдущим, объединить сообщенияfixup(илиf) — склеить с предыдущим, выбросить сообщение этого коммитаreword(илиr) — изменить только сообщение коммитаedit(илиe) — остановиться на коммите и внести изменения в файлыdrop(илиd) — удалить коммит
Типичный сценарий: перед созданием PR склеить несколько черновых коммитов («WIP», «ещё правки», «исправить тест») в один чистый коммит с понятным сообщением. Команда увидит осмысленную историю, а не рабочий дневник.
Когда что использовать
Нет универсального ответа — выбор зависит от контекста и договорённостей в команде. Вот практические ориентиры.
feature-ветка → используйте rebase
Если вы работаете над личной feature-веткой, которую ещё не публиковали (или публиковали, но работаете в одиночку), — обновляйтесь через rebase:
Так ваши коммиты окажутся поверх актуального main, и PR будет применяться чисто, без merge-коммита. История останется линейной.
Слияние в main → используйте merge
Когда feature-ветка проверена и одобрена, её сливают в основную ветку через merge. В большинстве команд это делается через pull request, и CI автоматически создаёт merge-коммит. Это нормально: merge-коммит в main фиксирует факт слияния и сохраняет связь с веткой.
Общая ветка → никогда rebase
Если над веткой работают несколько разработчиков, git rebase категорически нельзя использовать. Rebase переписывает хеши — и у коллег возникнет рассинхронизация. При следующем git pull Git увидит два «параллельных» набора коммитов с одинаковыми изменениями, и придётся вручную разбираться с конфликтами.
Золотое правило rebase
Никогда не делайте rebase ветки, которая уже запушена в удалённый репозиторий и используется другими разработчиками.
Это правило звучит просто, но регулярно нарушается. Сценарий: вы запушили feature-ветку, открыли PR, получили ревью — и решили «подчистить» историю через git rebase -i. После этого придётся делать git push --force. Если коллега уже склонировал вашу ветку — у него сломается история.
Исключение: git push --force-with-lease — более безопасная версия force push, которая откажет, если кто-то успел запушить в ту же ветку. Но лучше договориться в команде заранее: нужна ли вам линейная история или достаточно merge-коммитов.
Сравнение: merge vs rebase
- История: merge — нелинейная с merge-коммитами; rebase — линейная, как будто ветки не было
- Безопасность для команды: merge — всегда безопасен; rebase — только на локальных или личных ветках
- Трассировка: merge — видно, когда и откуда пришли изменения; rebase — история «переписана», оригинальные хеши утеряны
- Конфликты: merge — разрешаются один раз; rebase — могут появляться на каждом переносимом коммите
- Читаемость: merge — граф коммитов быстро загромождается; rebase — чистая линейная история
- Откат: merge —
git revertпо merge-коммиту; rebase — откатить сложнее, так как хеши изменились
Часто задаваемые вопросы
Можно ли сделать rebase после того, как открыл pull request?
Технически да, но это требует git push --force-with-lease и договорённости с командой. Если коллеги уже оставили ревью или добавили коммиты в вашу ветку — rebase создаст проблемы. Безопаснее делать rebase до открытия PR, а после — только merge.
Что такое squash merge и чем он отличается от rebase?
Squash merge (git merge --squash) склеивает все коммиты ветки в один и добавляет его в основную ветку без merge-коммита. История выглядит чисто, как после rebase, но ветка при этом не привязывается к основной через родительский коммит. GitHub и GitLab предлагают squash merge как опцию при закрытии PR.
Как восстановиться, если rebase пошёл не так?
Воспользуйтесь git reflog — он хранит все состояния HEAD, включая до начала rebase. Найдите нужный коммит в reflog и выполните git reset --hard HEAD@{N}, где N — номер записи. Также во время rebase можно в любой момент выполнить git rebase --abort, чтобы вернуться к исходному состоянию.
Заключение
Выбор между merge и rebase — это не вопрос «что лучше», а вопрос «что нужно здесь». Merge сохраняет полную картину истории и безопасен для общих веток. Rebase даёт чистую линейную историю и идеален для подготовки feature-веток перед слиянием. Главное правило: не переписывайте то, что уже видели другие. Договоритесь о конвенции с командой — и придерживайтесь её.