git rebase

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

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

Что такое git rebase?

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

Обучающий материал по Git: команда git rebase

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

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

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

г
  1. В основной ветке обнаруживается баг, который нарушает работу одной из функций.
  2. Разработчик изучает историю основной ветки с помощью команды git log, при этом логичный порядок элементов в истории позволяет ему быстро разобраться в ситуации.
  3. Время появления бага не удается определить с помощью команды git log, поэтому разработчик выполняет команду git bisect.
  4. История Git имеет логичный порядок, поэтому команда git bisect успешно выдает ряд коммитов — их нужно сравнить между собой, чтобы найти проблему. Разработчик быстро находит проблемный коммит и может применить необходимые исправления.

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

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

git rebase: перебазирование ветки на основную

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

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

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

Сравнение стандартного и интерактивного режимов команды git rebase

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

 # Создание функциональной ветки на основе master git checkout -b feature_branch master # Редактирование файлов git commit -a -m "Adds new feature" 

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

 git rebase 

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

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

 git rebase --interactive 

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

  pick 2231360 some old commit pick ee2adc2 Adds new feature # Перебазирование 2cf755d..ee2adc2 на 2cf755d (9 команд) # # Команды: # p, pick = использовать коммит # r, reword = использовать коммит, но изменить его сообщение # e, edit = использовать коммит, но остановиться для внесения поправок # s, squash = использовать коммит, но объединить с предыдущим коммитом # f, fixup = аналогично "squash", но отбросить сообщение журнала этого коммита # x, exec = выполнить команду (остаток строки) с помощью оболочки # d, drop = удалить коммит 

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

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

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

Обзор

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

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

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

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

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

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

error

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

ignore

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

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

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

  git rebase --onto   

Опция --onto расширяет возможности перебазирования: теперь команде rebase можно назначать конкретные ссылки на основания для перебазирования.
Рассмотрим тестовый репозиторий с такими ветками:

     o---o---o---o---o master         \          o---o---o---o---o featureA               \                o---o---o featureB 

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

  git rebase --onto master featureA featureB 

featureA — это старое основание . Основная ветка master становится новым основанием , а ветка featureB — указателем коммита, на который укажет HEAD нового основания . В результате получаем:

                        o---o---o featureB                      /     o---o---o---o---o master      \       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
  • Опция --onto команды git rebase
  • Потеря коммитов при выполнении команды git rebase

Мы рассмотрели применение команды git rebase с другими инструментами, например git reflog, git fetch и git push. Подробные сведения о них см. на соответствующих страницах.

Готовы изучить Git?

Попробуйте это интерактивное учебное руководство.

Начните прямо сейчас