git rebase
В этом документе подробно рассматривается команда git rebase
. Сведения о ней также можно найти на страницах Настройка репозитория и Переписывание истории. На этой странице особое внимание уделяется конфигурации команды git rebase
и ее применению. Кроме того, здесь приведены распространенные примеры использования перебазирования и типичные ошибки.
Перебазирование — это один из двух инструментов Git для внедрения изменений из одной ветки в другую. Такие же возможности предоставляет команда git merge
(слияние). Операция слияния фиксирует изменения, всегда двигаясь вперед по истории проекта, в то время как перебазирование позволяет эффективно ее переписывать. Подробные сведения об операциях слияния и перебазирования см. в руководстве Сравнение слияния и перебазирования. Перебазирование может выполняться в двух режимах: ручном и интерактивном. Эти режимы будут подробно рассмотрены далее.
Что такое git rebase?
Перебазирование — это процесс перемещения последовательности коммитов к новому базовому коммиту или их объединение. Операцию перебазирования удобнее всего применить и отобразить в контексте создания функциональных веток. В общих чертах процесс можно представить следующим образом:
С точки зрения содержимого перебазирование — это замена одного коммита в основании ветки на другой, в результате чего создается впечатление, что ветка получила новое начало. В процессе этой операции Git создает новые коммиты и применяет их к указанному основанию, поэтому важно понимать, что в действительности ветка всегда состоит из совершенно новых коммитов.
Связанные материалы
Шпаргалка по Git
СМ. РЕШЕНИЕ
Изучите Git с помощью Bitbucket Cloud
Использование
Перебазирование выполняется прежде всего для обеспечения линейной истории проекта. Представим ситуацию: вы работаете над функциональной веткой feature, при этом код в главной ветке main уже изменился с начала вашей работы. Вам нужно отразить последние изменения ветки main в ветке feature, не засоряя при этом историю вашей ветки, чтобы создать впечатление, что ваша работа велась на основе последней версии ветки main. Впоследствии это позволит выполнить беспроблемное слияние ветки feature с веткой main. Почему не следует засорять историю? Ее аккуратность сыграет решающую роль при поиске в 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 обеспечивает ускоренное слияние.
Перебазирование часто используют для внедрения восходящих изменений в локальный репозиторий. При запросе таких изменений с помощью слияния у вас будет создаваться ненужный коммит слияния всякий раз, когда вы заходите просмотреть изменения в проекте. С другой стороны, перебазирование обеспечит такие условия, когда ваши изменения основываются на результатах работы коллег.
Не выполняйте перебазирование публичной истории
Ранее на странице Переписывание истории мы уже обозначили, что ни при каких обстоятельствах не следует выполнять перебазирование коммитов, отправленных в публичный репозиторий. Команда 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
принимает несколько значений, которые определяют поведение операции перебазирования относительно отсутствующих коммитов.
| Выводит в интерактивном режиме предупреждения о том, что коммиты были удалены. |
| Останавливает перебазирование и выводит предупреждения о том, что коммиты были удалены. |
| Установлено по умолчанию. Игнорирует все предупреждения об отсутствии коммитов. |
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.