git rebase
Узнайте, что делает команда git rebase, посмотрите примеры использования и разберитесь в отличиях стандартного и интерактивного режимов.
Что делает git rebase
Rebase означает перемещение серии коммитов на новый базовый коммит. Иначе говоря, git rebase меняет начальную точку текущей ветки с одного коммита на другой — так, словно вы создали ветку из другого места в истории.
Главное, что нужно понять: rebase не перемещает ваши исходные коммиты. Он создаёт совершенно новые коммиты с теми же изменениями и сообщениями, но с другими родительскими коммитами, а значит, и с другими хешами (SHA). Старые коммиты становятся недостижимыми, хотя ветка выглядит так же.

На этой странице рассматривается стандартный rebase, интерактивный rebase, форма --onto, разрешение конфликтов и способы восстановления после неудачного rebase.
Rebase vs. merge
Обе команды — git rebase и git merge — интегрируют изменения из одной ветки в другую, но формируют историю по-разному:
- Merge создаёт новый merge-коммит, связывающий истории двух веток. История нелинейна, но полностью сохранена — ничего не перезаписывается.
- Rebase воспроизводит ваши коммиты поверх целевой ветки. История остаётся линейной (без merge-коммитов), но исходные коммиты перезаписываются.
Используйте rebase, когда хотите получить чистую, прямолинейную историю для feature-ветки перед её публикацией. Используйте merge, когда нужно сохранить точную историю того, как ветки соединились, или когда ветка уже опубликована.
Стандартный rebase
В стандартном режиме git rebase берёт коммиты, уникальные для текущей ветки, и воспроизводит их поверх <base>. В качестве <base> может выступать имя ветки, тег или идентификатор коммита.
git rebase <base>Типичный сценарий: с момента ответвления ветка master продвинулась вперёд, и вы хотите получить последние изменения master под вашей feature-работой без merge-коммита.
# you are on your feature branch
git switch feature
# replay feature's commits on top of the current tip of master
git rebase masterДо rebase история выглядит так (feature ответвилась от старого состояния master):
A---B---C feature
/
D---E---F---G masterПосле git rebase master коммиты feature пересоздаются поверх G:
A'--B'--C' feature
/
D---E---F---G masterA', B' и C' несут те же изменения, что и A, B, C, но являются новыми коммитами с новыми хешами.
Никогда не делайте rebase публичной истории
Никогда не делайте rebase коммитов, которые уже были отправлены на сервер и на которых другие люди могли основать свою работу. Поскольку rebase заменяет коммиты новыми, у тех, кто уже получил старые коммиты, история окажется рассинхронизированной — будет казаться, что часть проекта исчезла, а при следующем pull появятся дублирующиеся или конфликтующие коммиты.
Золотое правило rebase: делайте rebase только тех коммитов, которые существуют исключительно в вашей локальной ветке и не были никому переданы. Rebase уже опубликованных коммитов — наиболее распространённый способ сломать репозиторий для всей команды.
Безопасная граница проста: свободно делайте rebase приватной работы; никогда не делайте rebase общей ветки master/main или любой ветки, на которой активно работают другие. Эта же осторожность применима к git reset и git commit --amend.
Интерактивный rebase
Интерактивный режим (-i, сокращение от "interactive") позволяет редактировать, переупорядочивать, объединять или удалять отдельные коммиты в процессе их воспроизведения. Это инструмент, к которому разработчики обращаются, чтобы привести feature-ветку в порядок перед слиянием — объединить мелкие коммиты вроде «исправить опечатку», переформулировать неясные сообщения и удалить тупиковые эксперименты.
git rebase -i <base>Например, чтобы привести в порядок последние 3 коммита ветки:
git rebase -i HEAD~3Это откроет редактор со списком задач — по одной строке на каждый коммит, старые сверху:
pick 11a1456 Add login form
pick a23db19 Fix typo in label
pick 31d332c Add password validation
# Rebase d4e5f6a..31d332c onto d4e5f6a (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commitЧтобы объединить исправление опечатки с коммитом формы входа и переименовать коммит с валидацией, измените список следующим образом:
pick 11a1456 Add login form
fixup a23db19 Fix typo in label
reword 31d332c Add password validationСохраните и закройте редактор; Git воспроизведёт коммиты, применяя каждую инструкцию по порядку.
Команды интерактивного rebase
Каждая строка в списке задач начинается с одной из этих команд:
pick— оставить коммит как есть. Это значение по умолчанию для каждой строки.reword— сохранить изменения коммита, но остановиться для редактирования его сообщения.edit— остановиться на этом коммите, чтобы изменить его содержимое (разбить, добавить файлы и т. д.), затем выполнитьgit rebase --continue.squash— объединить этот коммит с предыдущим и совместить оба сообщения в одно.fixup— какsquash, но сообщение этого коммита отбрасывается (сохраняется только предыдущее).drop— полностью удалить коммит из истории.exec— выполнить команду оболочки после предшествующего коммита (полезно для запуска тестов на каждом шаге).
Изменение порядка строк меняет порядок коммитов; удаление строки равнозначно drop.
Форма --onto
Флаг --onto даёт точный контроль над тем, какие коммиты перемещаются и куда они попадают:
git rebase --onto <newbase> <oldbase> <branch>Он берёт коммиты, которые есть в <branch>, но нет в <oldbase>, и воспроизводит их поверх <newbase>. Это способ переместить ветку с базы, которая ей больше не нужна.
Предположим, что featureY была ответвлена от featureX, но на самом деле не зависит от изменений featureX и должна базироваться на master:
o---o---o featureY
/
o---o---o---o featureX
/
o---o---o---o masterВыполните:
git rebase --onto master featureX featureYЗдесь featureX — это <oldbase>, master — <newbase>, а featureY — ветка, для которой выполняется rebase. Git воспроизводит только собственные коммиты featureY поверх master, отсоединяя их от featureX:
o'--o'--o' featureY
/
o---o---o---o---o master
\
o---o---o---o featureXРазрешение конфликтов в процессе rebase
Поскольку rebase повторно применяет ваши коммиты по одному, конфликт может остановить процесс на любом из них. Когда это происходит, Git делает паузу и сообщает, в каких файлах есть конфликты.
Порядок действий для продолжения:
# 1. fix the conflicted files in your editor, then stage them
git add <resolved-file>
# 2. continue replaying the remaining commits
git rebase --continueДругие управляющие команды во время паузы rebase:
git rebase --skip— пропустить текущий коммит и продолжить (используйте с осторожностью: изменения этого коммита будут потеряны).git rebase --abort— остановить всё и восстановить ветку в точности до состояния, в котором она была до начала rebase.
Долгоживущая ветка, сильно разошедшаяся с master, порождает наибольшее количество конфликтов — иногда один и тот же конфликт в нескольких коммитах. Две привычки снижают эту боль: делайте rebase относительно master часто, а не один раз в конце, и держите коммиты маленькими и сфокусированными.
Параметры конфигурации
Некоторые параметры rebase по умолчанию можно задать через git config. Они влияют на поведение git rebase и его вывод:
rebase.stat— boolean (по умолчаниюfalse), включающий визуальный diffstat изменений с момента последнего rebase.rebase.autoSquash— boolean, включающий поведение--autosquash(автоматическое переупорядочивание коммитовfixup!/squash!во время интерактивного rebase).rebase.missingCommitsCheck— определяет, что происходит при удалении коммитов из списка задач. Принимает одно из значений:
| Значение | Поведение |
|---|---|
ignore | По умолчанию. Все предупреждения об отсутствующих коммитах игнорируются. |
warn | В интерактивном режиме выводится предупреждение об удалённых коммитах. |
error | Rebase останавливается и выводит сообщения об удалённых коммитах. |
rebase.instructionFormat— строка в формате git log, используемая для форматирования каждой строки коммита в интерактивном списке задач.
Восстановление после неудачного rebase
Rebase может казаться деструктивным: при использовании squash или drop коммиты исчезают из лога ветки, и кажется, что они потеряны навсегда. Но это не так. Git хранит запись о том, куда указывала ветка до каждой операции, в git reflog.
Чтобы отменить rebase, найдите запись прямо перед ним и сбросьте ветку на неё:
# see where the branch was before the rebase
git reflog
# example output:
# a23db19 HEAD@{0}: rebase (finish): returning to refs/heads/feature
# 31d332c HEAD@{5}: rebase (start): checkout master
# c0ffee1 HEAD@{6}: commit: the state you want back
# move the branch back to the pre-rebase commit
git reset --hard HEAD@{6}Это ваша страховочная сеть — пока вы можете читать reflog, ни один rebase не является по-настоящему необратимым.
Восстановление после rebase в upstream
Если коллега сделал rebase и выполнил force-push ветки, над которой вы тоже работаете, обычный git pull попытается согласовать ваши коммиты с перезаписанным верхним коммитом удалённой ветки и может оставить вас с дублированной или запутанной историей.
Решение использует reflog ветки слежения за удалённым репозиторием, чтобы найти, куда она указывала до rebase, а затем воспроизводит вашу работу поверх нового верхнего коммита с помощью --onto:
# find the old tip of origin/feature in the remote-tracking reflog
git reflog show origin/feature
# replay your local commits from the old base onto the new one
git rebase --onto origin/feature <old-origin-tip> featureЭто перемещает только ваши коммиты на верхний коммит после force-push, не захватывая старые, уже перезаписанные коммиты.
Связанные темы
- git merge — альтернатива без перезаписи истории для интеграции веток.
- git reflog — журнал отмены действий для восстановления после неудачного rebase.
- git reset — перемещение указателя ветки, в том числе на состояние до rebase.
- git cherry-pick — воспроизведение отдельных коммитов без rebase всей ветки.