W3docs

git rebase

Узнайте, что делает команда git rebase, посмотрите примеры использования и разберитесь в отличиях стандартного и интерактивного режимов.

Что делает git rebase

Rebase означает перемещение серии коммитов на новый базовый коммит. Иначе говоря, git rebase меняет начальную точку текущей ветки с одного коммита на другой — так, словно вы создали ветку из другого места в истории.

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

git rebase

На этой странице рассматривается стандартный 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 master

A', 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В интерактивном режиме выводится предупреждение об удалённых коммитах.
errorRebase останавливается и выводит сообщения об удалённых коммитах.
  • 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 всей ветки.

Практика

Практика
Какие утверждения о команде `git rebase` верны согласно руководству W3Docs по Git?
Какие утверждения о команде `git rebase` верны согласно руководству W3Docs по Git?
Was this page helpful?