Компьютеры · Инструкция
GitHub Pull Request: merge commit, squash или rebase — в чём разница
GitHub Pull Request можно завершить merge commit, squash merge или rebase merge, и результат в истории будет разным.
Короткий ответ
Merge commit сохраняет ветвление и создаёт merge-коммит; squash объединяет изменения PR в один новый коммит; rebase переносит коммиты PR на базовую ветку без merge-коммита и создаёт новые SHA. Выбирать стоит по правилам истории проекта, а не по принципу «какая кнопка короче».
Что именно делает каждый способ
- Merge commit. Сохраняет коммиты ветки и добавляет merge-коммит с двумя родителями. Нужно сохранить структуру ветвления и контекст отдельных коммитов.
- Squash and merge. Сворачивает изменения PR в один новый коммит в целевой ветке. PR содержит много промежуточных/fixup-коммитов, а в main нужна компактная история.
- Rebase and merge. Добавляет коммиты PR последовательно поверх base без merge-коммита; SHA коммитов меняются. Нужна линейная история, но важно сохранить отдельные логические коммиты PR.
Важно: Если команда использует подписи коммитов, обязательные проверки или автоматизацию по SHA, отдельно проверьте последствия rebase: GitHub создаёт новые commit SHA при таком слиянии.
Merge commit: максимум контекста, но граф становится разветвлённым
При обычном merge GitHub объединяет head-ветку PR с base-веткой и сохраняет существующие коммиты как часть истории, добавляя merge-коммит. Это удобно, если каждый PR рассматривается как отдельная единица работы и по графу важно видеть, где именно ветка вошла в main. Такой подход хорошо сочетается с командами, которые отлаживают регрессии по отдельным коммитам внутри PR и не хотят переписывать их SHA. Обратная сторона — на активном проекте граф быстро наполняется merge-коммитами, особенно если ветки короткоживущие. Сам по себе более сложный граф не является ошибкой: он лишь требует, чтобы команда сознательно считала merge-коммит частью истории и формировала сообщения PR так, чтобы позже было понятно, что именно было объединено.
Совет: Если вы регулярно делаете `git revert -m` для отката целых merge-коммитов, обычный merge может давать удобную границу PR в истории.
Squash merge: один PR — один коммит в основной ветке
Squash and merge берёт совокупный diff PR и создаёт для него один новый коммит в base-ветке. Промежуточные «fix typo», «address review» и «try again» не засоряют основную историю, поэтому `git log` становится короче, а поиск PR по одному коммиту — проще. Цена такой чистоты в том, что отдельные коммиты ветки перестают существовать в base как самостоятельные точки истории. Если внутри PR было несколько важных логических шагов, которые могут понадобиться для `bisect`, cherry-pick или точечного revert, squash стирает эту гранулярность. Поэтому squash особенно хорошо работает, когда PR сам является минимальной логической единицей релиза, а качество внутренних коммитов ветки не гарантируется.
Rebase and merge: линейная история с отдельными коммитами
Rebase and merge сохраняет последовательность отдельных изменений, но ставит их поверх текущей base-ветки без дополнительного merge-коммита. GitHub прямо отмечает, что при таком процессе commit SHA обновляются: старые коммиты из ветки и новые коммиты в base — не один и тот же объект. Это важно для ссылок из внешних систем, подписей, кэшей сборки и любых процессов, где SHA используется как неизменный идентификатор. Метод полезен, если команда строго поддерживает содержательные атомарные коммиты и хочет линейный `git log`. Если же PR состоит из случайного набора исправлений после review, rebase сохраняет этот шум почти таким же, поэтому сначала имеет смысл привести историю ветки в порядок.
Предупреждение: Не обещайте пользователям стабильность SHA после rebase merge. Ссылка на старый commit hash и коммит, попавший в base, могут различаться.
Как выбрать способ слияния
- Нужен явный след границы PR. Да. Один коммит представляет PR. Нет отдельного merge-коммита
- Сохранить исходные коммиты как есть. Да. Нет. Нет, SHA меняются
- Линейная история. Не всегда. Да. Да
- Сохранить детализацию коммитов. Да. Нет. Да, но новыми SHA
- Компактный main. Средне. Максимально. Зависит от качества коммитов
Что согласовать в репозитории до выбора
- Считается ли PR одной логической единицей, которую удобно откатывать одним коммитом.
- Требуется ли сохранять отдельные авторские коммиты и их структуру.
- Насколько критичны исходные SHA для внешних систем и аудита.
- Нужна ли строго линейная история и включено ли соответствующее правило/Ruleset.
- Как merge queue и branch protection взаимодействуют с разрешёнными методами.
- Кто отвечает за хороший commit history: автор PR до merge или политика squash в момент merge.
Как избежать хаоса, когда в репозитории работают разные команды
Главная проблема обычно не в самом методе, а в непоследовательности. Если один PR попадает через squash, другой через merge commit, а третий через rebase без понятной причины, историю сложнее интерпретировать и автоматизировать. Зафиксируйте политику в CONTRIBUTING: какие методы разрешены, что должен означать один commit, как именуются PR и какой способ отката считается стандартным. В настройках GitHub можно включить или выключить конкретные методы merge, поэтому правила не обязательно оставлять только на уровне договорённости. Для репозиториев с merge queue дополнительно проверьте его настройки: очередь должна формировать историю тем способом, который совместим с выбранной политикой. Тогда кнопка merge становится продолжением инженерного процесса, а не отдельным решением каждого автора.
Что происходит с review-контекстом после merge
Способ слияния меняет Git-историю, но сам Pull Request на GitHub остаётся важным источником review-контекста: обсуждения, проверки и описание решения не превращаются автоматически в commit message. Поэтому команда должна решить, какую информацию обязательно переносить в итоговый коммит или changelog. При squash особенно полезно отредактировать итоговое сообщение перед merge, чтобы один коммит не получил бессодержательный заголовок. При merge commit стоит следить за названием PR, а при rebase — за качеством каждого сохраняемого логического коммита.
Что произойдёт с коммитами после каждого метода
При обычном merge commit исходные коммиты ветки PR остаются видимыми с теми же идентификаторами, а в базовой ветке появляется отдельная точка слияния. При squash GitHub создаёт один новый коммит, содержащий итог изменений PR; отдельные коммиты ветки больше не становятся отдельными коммитами base-ветки, поэтому ссылки на их SHA не описывают историю base после слияния. При rebase and merge GitHub переносит каждый коммит на вершину базы без merge-коммита, но GitHub прямо указывает, что при таком действии обновляется committer information и создаются новые SHA. Это различие важно не только для красоты графа: на SHA могут быть завязаны ссылки из инцидентов, автоматические отчёты, подписи, build provenance и команды отката. Если проект часто расследует, какой именно промежуточный коммит внёс регрессию, сохранение отдельных коммитов полезно только тогда, когда сами коммиты были аккуратно подготовлены. Если PR состоит из множества `fix typo` и `address review`, squash обычно делает основную ветку проще для чтения, но это уже правило процесса команды, а не универсально лучший вариант.
Что учитывать
Условия меняются. Страница отражает состояние на 2026-09-20; при расхождении с официальной документацией приоритет у первоисточника.
Источники и проверка
Фактическая часть сверена по первичным источникам (в т.ч. About pull request merges). Пример и формулировки — редакция N1RO на 2026-09-20.