git branches

git rebase

Перенос или переупорядочивание коммитов на новую базу

Описание

git rebase перемещает или «переигрывает» серию коммитов поверх другой базы. В отличие от git merge, который создаёт новый merge-коммит с двумя родителями, rebase переписывает историю, создавая новые коммиты с теми же изменениями, но с новыми хешами и родителями. Результат — чистая линейная история без «замёрзших» веток.

Интерактивный rebase (git rebase -i) — мощный инструмент редактирования истории. Он позволяет: объединять несколько коммитов в один (squash/fixup), переформулировать сообщения коммитов (reword), переставлять коммиты местами, удалять ненужные коммиты (drop), разбивать один коммит на несколько (edit).

Важнейшее правило rebase: никогда не перебазируйте коммиты, которые уже опубликованы в общем репозитории. Rebase переписывает хеши, и другие разработчики, которые работали на основе этих коммитов, столкнутся с серьёзными проблемами при синхронизации.

Синтаксис

# Перебазировать текущую ветку на указанную git rebase <базовая-ветка> # Перебазировать на конкретный коммит git rebase <хеш-коммита> # Интерактивный rebase (редактировать последние N коммитов) git rebase -i HEAD~<N> # Интерактивный rebase от точки ветвления git rebase -i <базовая-ветка> # Продолжить после разрешения конфликта git rebase --continue # Пропустить текущий конфликтный коммит git rebase --skip # Прервать и вернуться к состоянию до rebase git rebase --abort # Перебазировать, сохраняя merge-коммиты git rebase -r <ветка> # Перенести коммиты на другую базу (--onto) git rebase --onto <новая-база> <старая-база> <ветка>

Флаги и опции

Флаг Описание
-i, --interactive Интерактивный режим: открывает редактор со списком коммитов для редактирования (pick/reword/squash/fixup/drop/edit)
--onto <ветка> Указать новую базу для перебазирования (пересадить коммиты на произвольную точку)
--continue Продолжить rebase после разрешения конфликта и выполнения git add
--abort Отменить rebase и вернуть ветку в исходное состояние
--skip Пропустить текущий проблемный коммит и перейти к следующему
--quit Прервать rebase, оставив рабочий каталог как есть
-r, --rebase-merges Сохранить merge-коммиты при перебазировании (иначе они удаляются)
--autosquash Автоматически переупорядочить коммиты с fixup! и squash! в префиксе сообщения
--autostash Автоматически создать stash перед rebase и применить после
--no-ff Создавать новые коммиты даже если можно применить fast-forward
-x <команда> Выполнять shell-команду после каждого переигранного коммита (напр. для тестов)
--stat Показать диффстат изменений с момента последнего rebase

Паттерны использования

Обновление feature-ветки от main

# Находясь на feature-ветке
git switch feature/payments

# Получить изменения main
git fetch origin

# Перебазировать поверх свежего main
git rebase origin/main

# Если всё OK — обновить remote (force-push!)
git push --force-with-lease origin feature/payments

Интерактивное редактирование коммитов

# Редактировать последние 4 коммита
git rebase -i HEAD~4

# В редакторе:
# pick a1b2c3 feat: add login form
# squash d4e5f6 fix: typo in login
# reword g7h8i9 feat: add password reset
# drop j0k1l2 WIP: debug output

Автоматическое squash через fixup!

# Создать fixup-коммит для более раннего
git commit --fixup=HEAD~2

# При rebase --autosquash fixup! автоматически
# переместится и сольётся с нужным коммитом
git rebase -i --autosquash main

Перенос коммитов (--onto)

# Ветка server создана от client,
# но нужно пересадить её на main
git rebase --onto main client server

# Удалить коммиты с неправильной базой
# (убрать 3 коммита из середины истории)
git rebase --onto HEAD~5 HEAD~3

Rebase с автоматическим stash

# Есть незафиксированные изменения,
# но нужно перебазироваться
git rebase --autostash origin/main

# Git сам выполнит:
# 1. git stash
# 2. rebase
# 3. git stash pop

Запуск тестов при каждом коммите

# Проверить, что каждый коммит собирается
git rebase -i --exec "npm test" main

# При ошибке rebase остановится.
# Исправить, затем:
git rebase --continue

Советы и подводные камни

Золотое правило rebase: перебазируйте только локальные (неопубликованные) коммиты. Если ветка уже отправлена на remote и другие разработчики могут её использовать — не делайте rebase. Если всё же нужно — используйте --force-with-lease вместо --force: он проверяет, что remote не изменился с момента вашего последнего fetch.
rebase vs merge: когда что использовать: rebase даёт чистую линейную историю — хорошо для feature-веток перед merge в main. merge --no-ff сохраняет точную историю развития — хорошо для основных веток (main, develop). Многие команды используют оба: rebase для обновления feature-ветки, merge для принятия в main.
Rebase переписывает хеши всех коммитов: каждый коммит после точки перебазирования получает новый SHA-1. Если вы уже сделали git push этих коммитов, потребуется force-push. Никогда не делайте force-push в ветки main/master или другие общие ветки — это перепишет историю для всей команды.