Rebase vs Merge
Updated Jul 2026
Два способа интеграции изменений
И merge, и rebase интегрируют изменения из одной ветки в другую, но создают разную историю коммитов. Понимание различий помогает вам поддерживать чистую историю, избегать конфликтов и эффективно работать с командой.
Merge
Merge создаёт новый «коммит слияния», объединяющий истории двух веток. Полная история ветки сохраняется в графе.
git checkout main
git merge feature/login-tests
# Creates a merge commit; feature branch history visible in graph
Как выглядит история после merge:
main: A --- B --- C --- M (merge commit)
/ /
feature: D --- E --/
Видны и коммиты основной ветки (A, B, C), и коммиты фича-ветки (D, E). Коммит слияния (M) отмечает точку интеграции.
Преимущества merge
- Сохраняет историю: вы можете точно увидеть, когда фича-ветка была создана и слита
- Безопасен для общих веток: никогда не переписывает существующие коммиты
- Легко откатить: откатите коммит слияния, чтобы отменить всю фичу
Недостатки merge
- Загромождённая история: множество коммитов слияния может сделать лог трудночитаемым
- Шумные диффы: коммиты слияния могут усложнить просмотр
git log --oneline
Rebase
Rebase воспроизводит ваши коммиты поверх целевой ветки, создавая линейную историю, как если бы вы написали код после последних изменений в целевой ветке.
git checkout feature/login-tests
git rebase main
# Your commits are rewritten on top of main's HEAD
Как выглядит история после rebase:
Before rebase:
main: A --- B --- C
\
feature: D --- E
After rebase:
main: A --- B --- C
\
feature: D' --- E' (new commits with same changes)
Коммиты D и E заменяются на D' и E' — те же изменения, но новые хэши. История линейна.
Преимущества rebase
- Чистая, линейная история: нет коммитов слияния, загромождающих лог
- Легче ревьюировать: диффы PR показывают только изменения фичи, без шума слияния
- Проще bisect:
git bisectработает надёжнее на линейной истории
Недостатки rebase
- Переписывает историю: коммиты получают новые хэши, что опасно для общих веток
- Может запутать: при неправильном rebase можно потерять работу
- Разрешение конфликтов для каждого коммита: может потребоваться разрешать один и тот же конфликт несколько раз, если несколько коммитов затрагивают один файл
Когда использовать каждый вариант
| Ситуация | Используйте | Причина |
|---|---|---|
| Обновление фича-ветки с последними изменениями main | Rebase | Сохраняет ваш PR чистым и удобным для ревью |
| Слияние PR в main | Merge (или squash merge) | Коммит слияния отмечает точку интеграции |
| Интеграция долгоживущей ветки | Merge | Сохраняет полную историю работы |
| Общая ветка с несколькими контрибьюторами | Merge | Никогда не делайте rebase коммитов, на которых другие могли основать свою работу |
| Очистка коммитов перед открытием PR | Interactive rebase | Объединение WIP-коммитов в логичные, удобные для ревью единицы |
Золотое правило: никогда не делайте rebase коммитов, которые были запушены в общую ветку и на которых другие могли основать свою работу. Переписывание общей истории вызывает конфликты у всех, кто эти коммиты уже получил.
Разрешение конфликтов при rebase
При rebase Git воспроизводит каждый коммит по одному. Если коммит конфликтует с целевой веткой, Git приостанавливается и просит вас разрешить конфликт.
git rebase main
# CONFLICT (content): Merge conflict in tests/login.spec.ts
# Fix stopped at abc123f... Add login retry test
# Step 1: Open the conflicting file and resolve the conflict markers
# <<<<<<< HEAD
# current main version
# =======
# your version from the feature branch
# >>>>>>> Add login retry test
# Step 2: After resolving, stage the file
git add tests/login.spec.ts
# Step 3: Continue the rebase
git rebase --continue
# If you want to abort and go back to the state before rebase:
git rebase --abort
Советы по разрешению конфликтов:
- Внимательно читайте обе версии. Не принимайте слепо одну сторону.
- Если конфликт в тестовом коде, проверьте, не добавили ли обе стороны тесты для одной и той же функции. Возможно, нужно сохранить оба варианта.
- Используйте
git rebase --abort, если не уверены. Всегда можно попробовать снова. - После разрешения запустите тесты локально, чтобы убедиться в корректности решения.
Interactive rebase: очистка перед PR
Interactive rebase позволяет переписывать, объединять, переупорядочивать или удалять коммиты перед их публикацией.
# Rebase the last 4 commits interactively
git rebase -i HEAD~4
Открывается редактор с вашими коммитами:
pick abc1234 WIP: start login tests
pick def5678 fix typo
pick ghi9012 WIP: more login tests
pick jkl3456 finish login tests
Измените действия:
pick abc1234 WIP: start login tests
fixup def5678 fix typo # Merge into previous, discard message
squash ghi9012 WIP: more login tests # Merge into previous, combine messages
pick jkl3456 finish login tests
Распространённые действия:
pick: оставить коммит как естьsquash: объединить с предыдущим коммитом, отредактировать объединённое сообщениеfixup: объединить с предыдущим коммитом, отбросить сообщение этого коммитаreword: изменить сообщение коммитаdrop: удалить коммит полностью
Когда QA-инженерам стоит использовать interactive rebase:
- Объединить несколько «WIP» или «fix typo» коммитов в один логичный коммит
- Переформулировать расплывчатые сообщения типа «fix tests» во что-то описательное
- Удалить коммиты-эксперименты (например, «add console.log»)
- Переупорядочить коммиты, чтобы связанные изменения были сгруппированы
Squash merge
Многие команды используют squash merge при завершении PR. Squash merge объединяет все коммиты PR в один коммит в main.
# GitHub PR merge options:
# 1. Create a merge commit (preserves all commits)
# 2. Squash and merge (combines into one commit)
# 3. Rebase and merge (linear history, preserves individual commits)
Предпочтение QA: squash merge обычно лучше всего для фича-веток. Он сохраняет историю main чистой (один коммит на фичу), а детальная история коммитов сохраняется в самом PR.
Практический рабочий процесс для QA-инженеров
Вот ежедневный рабочий процесс, который поддерживает ваши ветки в чистоте:
# 1. Start a new feature branch
git checkout main
git pull origin main
git checkout -b feature/add-checkout-tests
# 2. Work on your tests, making multiple commits
git add tests/checkout.spec.ts
git commit -m "WIP: add checkout happy path test"
# ... more work ...
git commit -m "add checkout error handling tests"
git commit -m "fix selector for payment button"
# 3. Before opening a PR, update with latest main
git fetch origin
git rebase origin/main
# 4. Clean up commits with interactive rebase
git rebase -i HEAD~3
# Squash "fix selector" into the relevant commit
# 5. Force-push to your feature branch (safe because it's your branch)
git push --force-with-lease origin feature/add-checkout-tests
# 6. Open PR. After approval, squash merge into main.
Флаг --force-with-lease безопаснее, чем --force. Он отказывается пушить, если кто-то другой запушил в ветку после вашего последнего fetch, предотвращая случайное затирание чужой работы.
Практическое упражнение
- Создайте фича-ветку, сделайте 5 коммитов (включая несколько «WIP» и «fix typo»)
- Сделайте rebase ветки на последнюю версию main
- Используйте interactive rebase для объединения WIP-коммитов в чистые, логичные коммиты
- Намеренно создайте конфликт и потренируйтесь в его разрешении во время rebase
- Запушьте с
--force-with-leaseи проверьте чистую историю - Откройте PR и используйте squash merge для его завершения