↓Перейти к содержанию
  1. Git: руководства и команды/

git rebase: что это и когда использовать вместо merge

·7 минут·

git rebase — один из самых мощных и при этом наиболее неправильно понимаемых инструментов Git. Он позволяет переписывать историю коммитов, делать её линейной и чистой. Но за эту чистоту приходится платить осторожностью: неправильное использование rebase может испортить историю репозитория для всей команды.

Что такое rebase и как он работает #

Rebase буквально означает «сменить базу». Когда вы делаете git rebase master, Git берёт все коммиты из вашей текущей ветки и «пересаживает» их на вершину другой ветки.

Представьте ситуацию: вы создали ветку feature от коммита C2 в master. Пока вы работали, в master появились коммиты C3 и C4.

До rebase история выглядит так:

master:  C1 - C2 - C3 - C4
                \
feature:         F1 - F2

После git rebase master из ветки feature:

master:  C1 - C2 - C3 - C4
                          \
feature:                   F1' - F2'

Коммиты F1 и F2 пересозданы как F1' и F2' — они содержат те же изменения, но имеют другие SHA-хеши, потому что их «родитель» изменился с C2 на C4.

Это принципиально отличает rebase от merge: merge создаёт новый коммит слияния и сохраняет исходную историю, rebase переписывает историю, делая её линейной.

Rebase vs Merge: различия #

# Merge: создаёт коммит слияния, история нелинейная
git checkout feature
git merge master
# Результат: F1 - F2 - M (merge commit)
#            /
# C1-C2-C3-C4

# Rebase: переписывает коммиты, история линейная
git checkout feature
git rebase master
# Результат: C1-C2-C3-C4-F1'-F2'

Когда использовать merge:

  • Публичные ветки, которые видят другие разработчики
  • Нужно сохранить точную историю слияния
  • Хотите зафиксировать момент, когда ветки объединились

Когда использовать rebase:

  • Локальные ветки до их публикации
  • Хотите «подтянуть» вашу ветку к актуальному состоянию main
  • Готовите чистую историю перед pull request
  • Хотите squash нескольких коммитов в один

Базовый rebase #

# Переключиться на feature ветку
git checkout feature
# или
git switch feature

# Выполнить rebase на master
git rebase master

# Аналогично, но переключение не нужно
git rebase master feature

# Посмотреть результат
git log --oneline

После успешного rebase, чтобы слить feature в master без лишнего merge-коммита:

git checkout master
git merge feature
# Это будет fast-forward merge — просто перемотка HEAD

Interactive rebase: полный контроль над историей #

Интерактивный rebase — самый мощный инструмент для управления историей коммитов. Он позволяет изменить порядок, объединить, разделить или удалить коммиты.

# Интерактивный rebase последних 3 коммитов
git rebase -i HEAD~3

# Интерактивный rebase всей ветки на master
git rebase -i master

# Интерактивный rebase начиная с конкретного коммита
git rebase -i a1b2c3d

Git откроет редактор с таким содержимым:

pick a1b2c3d Добавить авторизацию
pick b2c3d4e Исправить ошибку в авторизации
pick c3d4e5f Добавить тесты

# Rebase d5e6f7g..c3d4e5f onto d5e6f7g (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <commit> = remove commit

Команды interactive rebase:

  • pick — использовать коммит как есть
  • reword — использовать коммит, но изменить сообщение
  • squash — объединить с предыдущим коммитом, объединить сообщения
  • fixup — объединить с предыдущим коммитом, отбросить сообщение
  • drop — удалить коммит из истории
  • edit — остановиться для изменения коммита

Squash коммитов в один #

Частый сценарий: вы сделали несколько коммитов в процессе работы («WIP», «fix typo», «ещё одно исправление»), и хотите объединить их в один перед merge.

# Запустить интерактивный rebase для последних 3 коммитов
git rebase -i HEAD~3

В редакторе измените:

pick a1b2c3d Добавить авторизацию
squash b2c3d4e Исправить ошибку в авторизации
squash c3d4e5f Добавить тесты

Git объединит все три в один коммит и предложит отредактировать итоговое сообщение.

Если хотите просто объединить без редактирования сообщений — используйте fixup вместо squash:

pick a1b2c3d Добавить авторизацию
fixup b2c3d4e WIP
fixup c3d4e5f fix

Разрешение конфликтов при rebase #

В отличие от merge, при rebase конфликты могут возникать несколько раз — для каждого переносимого коммита. Это объясняется тем, что каждый коммит применяется последовательно.

# При конфликте Git останавливается и сообщает:
# CONFLICT (content): Merge conflict in src/auth.js
# error: could not apply a1b2c3d... Добавить авторизацию
# Resolve all conflicts manually...

# Проверить статус
git status

# Разрешить конфликты в файлах (открыть и отредактировать)
# Убрать маркеры <<<<<<, =======, >>>>>>>

# Добавить исправленные файлы
git add src/auth.js

# Продолжить rebase
git rebase --continue

# Если конфликтов несколько — Git остановится снова для следующего коммита
# Повторить процесс

# Если хотите отменить rebase и вернуться к исходному состоянию
git rebase --abort

Rebase с опцией –onto #

--onto позволяет «пересадить» ветку на другую базу, минуя промежуточные ветки:

# Синтаксис: git rebase --onto <newbase> <upstream> <branch>
# Перенести ветку feature на main, минуя develop
git rebase --onto main develop feature

# Пример: была ветка server, от неё client
# Хотим перенести client прямо на master
git rebase --onto master server client

Практические примеры #

# Обновить feature ветку до актуального состояния main
git fetch origin
git rebase origin/main

# Squash последних 5 коммитов
git rebase -i HEAD~5

# Исправить сообщение коммита (не последнего)
git rebase -i HEAD~3
# Заменить 'pick' на 'reword' для нужного коммита

# Удалить коммит из истории
git rebase -i HEAD~5
# Заменить 'pick' на 'drop' для нужного коммита

# Отменить неудачный rebase через reflog
git reflog
git reset --hard ORIG_HEAD

# Автоматически применить нашу версию при конфликтах (осторожно!)
git rebase -X ours master

# Применить их версию при конфликтах
git rebase -X theirs master

# Показать историю после rebase
git log --oneline --graph

Когда использовать rebase #

Rebase отлично подходит для следующих ситуаций:

Локальные ветки до публикации. Пока ваша ветка только у вас — свободно используйте rebase для чистоты истории.

Подтягивание ветки к актуальному состоянию. Вместо git pull (который делает merge) можно настроить git pull --rebase или использовать git fetch && git rebase origin/main.

Очистка истории перед pull request. Объедините «WIP» коммиты в осмысленные, исправьте опечатки в сообщениях.

Поддержание линейной истории в проекте. Некоторые команды требуют линейной истории как часть политики.

Когда избегать rebase #

Главное правило: никогда не делайте rebase опубликованных (публичных) веток.

Если ваши коммиты уже в удалённом репозитории, и другие разработчики их видели или работают на их основе — rebase создаст проблемы. После rebase SHA-хеши коммитов изменятся. Для других разработчиков это выглядит как полностью разная история, и при следующем pull/merge возникнут конфликты и дублированные коммиты.

# Опасно: rebase общей ветки
git checkout develop
git rebase main  # НЕ делайте этого, если develop — общая ветка

# Безопасно: rebase своей feature ветки
git checkout feature/my-task
git rebase main  # Нормально, если только вы работаете в feature/my-task

Настройка pull с rebase #

Вместо стандартного git pull (который делает merge) можно использовать rebase:

# Pull с rebase для текущего раза
git pull --rebase

# Настроить rebase по умолчанию для pull
git config --global pull.rebase true

# Или для конкретного репозитория
git config pull.rebase true

Часто задаваемые вопросы #

Какая разница между merge и rebase? Merge создаёт новый коммит слияния и сохраняет историю обеих веток. Rebase переносит коммиты на новую базу, создавая линейную историю. Merge безопаснее для публичных веток, rebase даёт чистую историю для локальной работы.

Когда я должен использовать rebase вместо merge? Используйте rebase для локальных веток перед публикацией, для «подтягивания» вашей ветки к актуальному состоянию main, для объединения мелких коммитов. Избегайте rebase на опубликованных ветках.

Что произойдёт, если я сделаю rebase опубликованной ветки? Git переписывает SHA-хеши коммитов. Другие разработчики, у которых есть старые версии этих коммитов, получат конфликты при следующем pull. История раздвоится, коммиты продублируются.

Как отменить неудачный rebase? Если rebase ещё не завершён — git rebase --abort. Если уже завершён — git reflog для поиска исходного коммита, затем git reset --hard ORIG_HEAD или git reset --hard <hash>.

Что такое interactive rebase и зачем он нужен? git rebase -i открывает редактор с возможностью изменить историю: объединить коммиты (squash), удалить (drop), переупорядочить, изменить сообщения (reword). Незаменимо для подготовки чистой истории перед pull request.

Можно ли использовать rebase вместо git pull? Да, git pull --rebase вместо обычного pull избежит лишних merge-коммитов при обновлении локальной ветки. Можно настроить по умолчанию через git config --global pull.rebase true.

Заключение #

git rebase — инструмент для тех, кто хочет поддерживать чистую и читаемую историю коммитов. Ключевое правило: rebase локальных неопубликованных веток — хорошо; rebase общих публичных веток — опасно. Interactive rebase (git rebase -i) особенно полезен для подготовки pull request: можно объединить черновые коммиты в один осмысленный.

Подробнее о слиянии веток — полное руководство по git merge. Для понимания истории изменений — git log и git reflog.