Перейти к содержимому

git rebase

Определение

Rebasing означает перемещение или объединение серии коммитов к новому базовому коммиту. Иными словами, он меняет основу текущей ветки с одного коммита на другой, создавая впечатление, что ветка была создана от другого коммита. Это делается с помощью команды git rebase. Имейте в виду, что даже если ветка выглядит той же самой, она состоит из совершенно новых коммитов.

git rebase

Использование команды git rebase

Прежде всего, эта команда нужна нам для поддержания линейной истории проекта. Например, ветка master продвигается дальше после того, как вы начали работать над feature-веткой. Вам нужны последние обновления ветки master в вашей feature-ветке, но история ветки master должна оставаться чистой. Нам нужна понятная история при выполнении операций Git, чтобы отслеживать регрессии. Ниже вы найдёте больше информации об использовании git rebase:

Недопустимость rebasing публичной истории

Никогда не выполняйте rebase коммитов после их публикации в публичной истории. Как и в случае с amend и reset, это создаст проблемы для командной работы. Если вы это сделаете, старый коммит будет заменён новым, и будет казаться, будто часть вашего проекта исчезла.

Разница между стандартным и интерактивным Git rebase.

У команды git rebase есть два режима: стандартный и интерактивный. В стандартном режиме git rebase автоматически применяет коммиты в текущей рабочей ветке к головe переданной ветки. Текущая ветка будет перебазирована на <code><base></code>. Это могут быть разные типы ссылок на коммит, например тег, ID, имя ветки и так далее.

git rebase command

bash
git rebase <base>

В интерактивном режиме git rebase выполняется с флагом -i, который означает “interactive”. Преимущество перебазирования в интерактивном режиме заключается в том, что можно изменять отдельные коммиты в процессе, не перемещая все коммиты на новую базу. Благодаря этому режиму вы можете очистить историю, удаляя и изменяя существующую последовательность коммитов.

Выполнение следующей команды откроет редактор:

git rebase -i

bash
git rebase --interactive <base>

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

git rebase example

bash
pick 11a1456 some old commit
pick a23db19 Adds new feature
# Rebase 31d332c..a23db19 onto 31d332c (9 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

Команды интерактивного rebase

Во время интерактивного rebase вы можете использовать следующие команды для каждого коммита в списке todo:

  • drop: удаляет коммит из итогового объединённого блока коммитов во время воспроизведения.
  • pick: оставляет коммит как есть, без изменения сообщения или содержимого, сохраняя его как отдельный коммит в истории ветки.
  • exec: позволяет запускать shell-скрипт командной строки для каждого отмеченного коммита во время воспроизведения.

Кратко о Git

Одно из преимуществ интерактивного перебазирования заключается в том, что оно позволяет разработчикам не беспокоиться о беспорядке в истории проекта, поскольку позже они могут вернуться и привести её в порядок. Поэтому многие разработчики используют этот инструмент, чтобы сделать историю feature-ветки чище перед слиянием её в ветку master. Очистка ветки означает удаление бессмысленных или уже неактуальных коммитов. В результате у разработчиков получается хорошо спланированная история, и они могут легко понять, какие коммиты были выполнены.

Параметры конфигурации

Существуют некоторые параметры rebase, которые задаются с помощью команды git config. Эти параметры изменяют поведение и вывод git rebase.

  • rebase.stat: по умолчанию false-значение boolean, которое переключает отображение визуального diffstat-контента, показывающего изменения с момента последнего rebase.
  • rebase.autoSquash: boolean-значение, переключающее поведение --autosquash.
  • rebase.missingCommitsCheck: может быть установлено в несколько значений, изменяющих поведение rebase в отношении отсутствующих коммитов. | warn | Вывод предупреждения печатается в интерактивном режиме и предупреждает об удалённых коммитах. | |---|---| | error | Rebase останавливается, и печатаются сообщения-предупреждения об удалённых коммитах. | | ignore | Значение по умолчанию, которое игнорирует любые предупреждения об отсутствующих коммитах. |
  • rebase.instructionFormat: строка в формате git log, используемая для форматирования отображения интерактивного rebase.

Продвинутое применение rebase

Команде git rebase можно передать аргумент командной строки --onto, и в этом случае команда расширяется до следующего:

git rebase --onto

bash
git rebase --onto <newbase> <oldbase> <branch>

Параметр --onto обеспечивает продвинутое применение rebase, позволяя передавать конкретные refs в качестве базовых коммитов rebase.

Давайте посмотрим, как это работает на примере:

git rebase --onto example

bash
o---o---o---o---o master
 \
 o---o---o---o---o featureX
 \
 o---o---o featureY

Хотя featureY изначально была основана на featureX, она не зависит от изменений featureX и может быть перебазирована напрямую на master. Эта команда воспроизводит коммиты из featureY поверх master, фактически отделяя featureY от featureX.

git rebase --onto command

bash
git rebase --onto master featureX featureY

FeatureX — это <code><oldbase></code>, master — это <code><newbase></code>, а featureY — это ветка, которая перебазируется. Вот результат:

git rebase usage

bash
o---o---o featureY
 /
 o---o---o---o---o master
 \
 o---o---o---o---o featureX

Опасности rebasing

Первая опасность использования команды git rebase заключается в том, что она может вызвать больше merge-конфликтов во время процесса перебазирования, особенно в случаях, когда у вас есть долго живущая ветка, которая разошлась с master. Рано или поздно вы можете решить выполнить rebase относительно master, который может содержать новые коммиты, с изменениями которых могут конфликтовать изменения вашей ветки. Решение описанной выше ситуации — чаще выполнять rebase ветки относительно master и делать более частые коммиты. Чтобы продолжить или отменить rebase при разрешении конфликтов, вы можете использовать аргументы --continue и --abort с git rebase. Ещё один, более серьёзный риск заключается в том, что некоторые коммиты могут быть потеряны при интерактивном переписывании истории. Запуск rebase в интерактивном режиме с некоторыми подкомандами, такими как squash или drop, удаляет коммиты из непосредственного журнала ветки. Может показаться, что коммиты удалены навсегда. Решение — git reflog, который позволяет восстановить эти коммиты, и вы можете отменить весь rebase.

Восстановление после upstream rebase

Если другой пользователь выполнил rebase и force-push в ветку, в которую вы коммитите, то git pull перезапишет любой ваш коммит, основанный на той предыдущей ветке, с помощью принудительно отправленного tip-коммита. Git rebase позволяет использовать reflog удалённой ветки. Там вы можете найти ref до того, как он был перебазирован. Затем вы можете перебазировать свою ветку относительно этого удалённого ref с помощью опции --onto.

Практика

What are the correct statements about the `git rebase` command as described in the W3Docs Git Tutorial?

Считаете ли это полезным?

Предпросмотр dual-run — сравните с маршрутами Symfony на продакшене.