Close

git rebase

В этом документе подробно рассматривается команда git rebase. Сведения о ней также можно найти на страницах Настройка репозитория и Переписывание истории. На этой странице особое внимание уделяется конфигурации команды git rebase и ее применению. Кроме того, здесь приведены распространенные примеры использования перебазирования и типичные ошибки.

Перебазирование — это один из двух инструментов Git для внедрения изменений из одной ветки в другую. Такие же возможности предоставляет команда git merge (слияние). Операция слияния фиксирует изменения, всегда двигаясь вперед по истории проекта, в то время как перебазирование позволяет эффективно ее переписывать. Подробные сведения об операциях слияния и перебазирования см. в руководстве Сравнение слияния и перебазирования. Перебазирование может выполняться в двух режимах: ручном и интерактивном. Эти режимы будут подробно рассмотрены далее.


Что такое git rebase?


Перебазирование — это процесс перемещения последовательности коммитов к новому базовому коммиту или их объединение. Операцию перебазирования удобнее всего применить и отобразить в контексте создания функциональных веток. В общих чертах процесс можно представить следующим образом:

git rebase

С точки зрения содержимого перебазирование — это замена одного коммита в основании ветки на другой, в результате чего создается впечатление, что ветка получила новое начало. В процессе этой операции Git создает новые коммиты и применяет их к указанному основанию, поэтому важно понимать, что в действительности ветка всегда состоит из совершенно новых коммитов.

Логотип Git
Связанные материалы

Шпаргалка по Git

Логотип Bitbucket
СМ. РЕШЕНИЕ

Изучите Git с помощью Bitbucket Cloud

Использование


Перебазирование выполняется прежде всего для обеспечения линейной истории проекта. Представим ситуацию: вы работаете над функциональной веткой feature, при этом код в главной ветке main уже изменился с начала вашей работы. Вам нужно отразить последние изменения ветки main в ветке feature, не засоряя при этом историю вашей ветки, чтобы создать впечатление, что ваша работа велась на основе последней версии ветки main. Впоследствии это позволит выполнить беспроблемное слияние ветки feature с веткой main. Почему не следует засорять историю? Ее аккуратность сыграет решающую роль при поиске в Git коммита, в котором появилась проблема. Можно привести более реалистичный пример.

Из централизованного репозитория git в локальный репозиторий git

1. В ветке main обнаруживается баг, который нарушает работу одной из функций.

2. A developer examines the history of the main branch using git log because of the "clean history" the developer is quickly able to reason about the history of the project.

3. The developer can not identify when the bug was introduced using git log so the developer executes a git bisect.

4. Because the git history is clean, git bisect has a refined set of commits to compare when looking for the regression. The developer quickly finds the commit that introduced the bug and is able to act accordingly.

Узнайте больше о командах git log и git bisect на соответствующих страницах.

Внедрить функцию в главную ветку main можно двумя способами: прямым слиянием или перебазированием с последующим слиянием. Первая операция выполняет трехстороннее слияние и создает коммит слияния, а вторая обеспечивает ускоренное слияние и абсолютно линейную историю. На приведенной ниже схеме показано, как перебазирование на ветку main обеспечивает ускоренное слияние.

Git rebase: Branch onto main

Перебазирование часто используют для внедрения восходящих изменений в локальный репозиторий. При запросе таких изменений с помощью слияния у вас будет создаваться ненужный коммит слияния всякий раз, когда вы заходите просмотреть изменения в проекте. С другой стороны, перебазирование обеспечит такие условия, когда ваши изменения основываются на результатах работы коллег.

Не выполняйте перебазирование публичной истории

Ранее на странице Переписывание истории мы уже обозначили, что ни при каких обстоятельствах не следует выполнять перебазирование коммитов, отправленных в публичный репозиторий. Команда rebase заменит старые коммиты на новые, и другим разработчикам покажется, будто часть истории проекта просто исчезла.

Git rebase standard vs git rebase interactive

Чтобы выполнить перебазирование в интерактивном режиме, к команде git rebase нужно добавить аргумент -i (от interactive — «интерактивный»). При выполнении команды без аргументов она запустится в стандартном режиме. Для демонстрации обоих режимов представим, что мы создали отдельную функциональную ветку.

# Create a feature branch based off of main 
git checkout -b feature_branch main
# Edit files 
git commit -a -m "Adds new feature" 

В стандартном режиме команда git rebase автоматически берет коммиты из текущей рабочей ветки и применяет их в конце переданной ветки.

git rebase <base>

Текущая ветка автоматически перебазируется на основание <base>. Для этого можно использовать любую ссылку на коммит (например, идентификатор, название ветки, тег или относительную ссылку на HEAD).

Если запустить команду git rebase с флагом -i, перебазирование будет выполняться в интерактивном режиме. Этот режим исключит необходимость перемещения коммитов вслепую на новое основание и позволит изменять отдельные коммиты при выполнении операции. Так вы можете очистить историю путем удаления, разделения и изменения коммитов в существующей последовательности. Получится что-то вроде команды git commit --amend на стероидах!

git rebase --interactive <base>

Текущая ветка будет перенесена на основание <base> в интерактивном режиме. Откроется редактор, где вы сможете вводить команды (описаны ниже) для каждого перебазируемого коммита. С помощью этих команд можно определить способ переноса отдельных коммитов на новое основание, а также переупорядочить список коммитов, чтобы изменить их будущий порядок. Когда команды будут указаны для каждого актуального коммита, Git начнет их применение. При перебазировании можно использовать следующие команды:

pick 2231360 some old commit
pick ee2adc2 Adds new feature


# Rebase 2cf755d..ee2adc2 onto 2cf755d (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

Дополнительные команды перебазирования

Как описано на странице Переписывание истории, с помощью перебазирования можно изменять предыдущие коммиты, группы коммитов, зафиксированные с помощью коммитов файлы и группы сообщений. Существуют и более сложные примеры использования, которые требуют добавления к команде git rebase различных опций.

  • git rebase -d — во время операции коммит будет исключен из окончательного блока объединенных коммитов.
  • git rebase -p — коммит останется в исходном виде. Операция не затронет сообщение и содержимое коммита. При этом сам коммит сохранится в истории веток отдельно.
  • git rebase -x — для каждого отмеченного коммита будет выполнен скрипт командной строки. Эта опция может быть полезной при тестировании базы кода на отдельных коммитах, поскольку с ее помощью можно выявить ошибки в ходе перебазирования.

Обзор

Интерактивное перебазирование позволяет полностью контролировать состояние истории проекта. Это дает разработчикам большую свободу, поскольку они могут зафиксировать засоренную историю, не отрываясь от написания кода, и очистить ее позже.

Большинство разработчиков используют интерактивное перебазирование, чтобы придать функциональной ветке аккуратность перед слиянием с основной базой кода. Они могут склеить незначительные коммиты, удалить устаревшие элементы и в целом навести порядок в ветке, прежде чем выполнить перенос в «официальную» историю проекта. Со стороны будет казаться, что для разработки функции потребовалось лишь несколько коммитов и тщательное планирование.

Оценить эффективность интерактивного перебазирования можно, взглянув на получившуюся историю ветки main. В глазах окружающих вы будете блестящим разработчиком, который внедрил новую функцию с первого раза и без лишних коммитов. Так интерактивное перебазирование помогает поддерживать порядок в истории проекта, а также сохраняет целесообразность каждого ее элемента.

Варианты конфигурации

С помощью команды git config можно задать ряд опций перебазирования. Так вы определяете, какие элементы будут выводиться на экран при выполнении команды git rebase.

  • rebase.stat принимает логические значения (по умолчанию false). Эта опция отвечает за наглядное отображение статистики по различиям, с помощью которой можно увидеть изменения с момента последнего перебазирования.
  • rebase.autoSquash принимает логические значения и отвечает за поведение опции --autosquash.
  • rebase.missingCommitsCheck принимает несколько значений, которые определяют поведение операции перебазирования относительно отсутствующих коммитов.

warn

Выводит в интерактивном режиме предупреждения о том, что коммиты были удалены.

error

Останавливает перебазирование и выводит предупреждения о том, что коммиты были удалены.

ignore

Установлено по умолчанию. Игнорирует все предупреждения об отсутствии коммитов.

  • rebase.instructionFormat — форматная строка git log, включающая опции форматирования вывода команды rebase при ее выполнении в интерактивном режиме.

Расширенные возможности перебазирования

Команде git rebase можно передать аргумент командной строки --onto. При использовании аргумента --onto команда git rebase примет следующий вид:

git rebase --onto <newbase> <oldbase>

The --onto command enables a more powerful form or rebase that allows passing specific refs to be the tips of a rebase. Let’s say we have an example repo with branches like:

   o---o---o---o---o  main
        \
         o---o---o---o---o  featureA
              \
               o---o---o  featureB

Ветка featureB основана на featureA. При этом мы понимаем, что ветка featureB не зависит ни от одного изменения в ветке featureA, поэтому она могла бы отходить от главной ветки main.

git rebase --onto main featureA featureB

featureA — это старое основание <oldbase>. Главная ветка main становится новым основанием <newbase>, а ветка featureB — указателем коммита, на который будет ссылаться указатель HEAD нового основания <newbase>. В результате получаем:

                      o---o---o  featureB
                     /
    o---o---o---o---o  main
     \
      o---o---o---o---o  featureA
                           

Опасности перебазирования


При работе с командой git rebase важно помнить о нескольких трудностях. Одна из них заключается в конфликтах слияния, которые проявляются чаще, если ветка существует достаточно долго и имеет значительные отличия от главной. К тому времени, когда вы захотите перебазировать такую ветку на главную, в последней может возникнуть множество новых коммитов, которые будут конфликтовать с изменениями вашей ветки. Чтобы избежать этого, необходимо регулярно выполнять перебазирование ветки на главную и чаще делать коммиты. Аргументы командной строки --continue и --abort определяют поведение git rebase при возникновении конфликтов и служат соответственно для продолжения и прерывания операции.

Более серьезная проблема перебазирования заключается в том, что при перезаписи истории в интерактивном режиме некоторые коммиты могут быть утрачены. Выполнение перебазирования в интерактивном режиме вместе с такими подкомандами, как squash или drop, приведет к удалению коммитов из локальной истории вашей ветки. Сначала покажется, что коммиты удалены навсегда, но их можно восстановить с помощью команды git reflog. При этом операция перебазирования будет полностью отменена. Подробные сведения о том, как команда git reflog позволяет найти утраченные коммиты, см. в документации по команде git reflog.

Сама по себе команда git rebase не сопряжена с серьезной опасностью. Риск возникает, если вы используете интерактивное перебазирование для перезаписи истории и затем принудительно отправляете результаты в удаленную ветку, где работают другие пользователи. Этого делать не стоит, поскольку работа удаленных пользователей может быть перезаписана при осуществлении pull.

Восстановление при перебазировании восходящей ветки


Если другой пользователь выполнил перебазирование и принудительно отправил изменения в ветку, над которой вы работаете, при выполнении команды git pull отправленные коммиты перезапишут все коммиты, от которых отходила эта ветка. К счастью, команда git reflog позволяет получить журнал ссылок удаленной ветки. Вы можете найти в нем ссылку, которая предшествовала перебазированию, затем перебазировать свою ветку с помощью этой ссылки и опции --onto, которая была рассмотрена в разделе «Расширенные возможности перебазирования».

Резюме


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

  • Сравнение стандартного и интерактивного режимов команды git rebase.
  • Опции конфигурации команды git rebase.
  • git rebase --onto
  • Потеря коммитов при выполнении команды git rebase.

We looked at git rebase usage with other tools like git reflog, git fetch, and git push. Visit their corresponding pages for further information.


Поделитесь этой статьей
Следующая тема

Рекомендуемые статьи

Добавьте эти ресурсы в закладки, чтобы изучить типы команд DevOps или получать регулярные обновления по DevOps в Atlassian.

Люди сотрудничают друг с другом, используя стену со множеством инструментов

Блог Bitbucket

Рисунок: DevOps

Образовательные программы DevOps

Демонстрация функций в демо-зале с участием экспертов Atlassian

Как инструмент Bitbucket Cloud работает с Atlassian Open DevOps

Подпишитесь на информационную рассылку по DevOps

Thank you for signing up