Rebase - это Расширение Mercurial, позволяющее нам менять непропушенную часть дерева изменений в репозитории. Мы можем менять родителей непропушенных коммитов. В идеале мы должны получить вытянутую в одну линию цепочку изменений без ветвления в рамках одной ветки.
Как это работает
Когда мы хотим протолкнуть наш коммит, но обнаруживаем, что кто-то до нас успел протолкнуть что-то ещё, мы не сможем этого сделать, поэтому мы обновляемся и видим следующую картину:
Делая перебазирование нашего коммита, мы меняем родителся с “Пятый коммит” на “Чей-то коммит”, тем самым убирая ветвление:
Следует заметить, что происходит не перемещение коммита в другое место, а удаление и создание нового, это видно по тому, что изменяется идентификатор узла нашего коммита. В связи с этим возникает проблема при работе с подрепозиториями, о которой поведаем в следующем разделе.
На что следует обратить внимание
При использовании подрепозиториев, нам нужно внимательнее делать Rebase в них. Допустим, репозиторий ссылается на состояние С подрепозитория:
Мы перебазируем С на D и получаем ссылку на несуществующее состояние:
Если пропушить такое состояние репозитория, то потом при обновлении на это состояние будут возникать критичные ошибки, мешающие дальнейшей работе. Поэтому Rebase следует проводить последовательно начиная от самых глубоковложенных подрепозиториев и заканчивая корневыми. Эта проблема пропадает при использовании тонких репозиториев (описано в статье про подрепы).
Rebase или Merge?
Мы можем действовать стандартным способом и при возникновении подобных ситуаций делать слияние:
Но при большой команде разработки вскоре дерево принимает подобный вид:
В таком дереве двоичным поиском сложней найти сбойную ревизию, да и вообще трудно разобраться в последовательности изменений.
Итак, какой же способ ведения дерева нам выбрать? Если для нас критична история и действительное время коммитов, то мы используем Merge, если же для нас важна простота изучения истории и красота дерева, то выбираем Rebase.
Нужно отметить, что при многопользовательской правки одних и тех же файлов было замечено, что Rebase хуже справляется со слиянием, требуется больше времени, чтобы завершить все изменения.
Насколько Rebase должен упростить нам жизнь?
Какие положительные моменты данного подхода?
- Дерево выглядит красиво и понятно
- Удобно следить за историей изменений
- При необходимости двоичного поиска сбойной ревизии нам надо будет обновиться на меньшее количество ревизий, чем при сильно разветвлённом дереве
Какие отрицательные моменты?
- Потеря истории слияний, что иногда может привести к невозможности определения источника и виновника ошибки
- По опыту работы существуют отзывы, говорящие, что трудней проводить громоздкие слияния с Rebase, чем при использовании обычных слияний
Как мы можем обойтись без Rebase?
В принципе, можно сохранить прямое дерево изменений, если перед каждым коммитом обновляться на последнюю ревизию, улаживать конфликты, коммитить и сразу проталкивать изменения. Я сам так всегда делал до того, как узнал про Rebase.
Конечно же, есть положительные и отрицательные стороны подхода:
Положительные:
- Мы-таки сохраняем дерево стройным и красивым
Отрицательные:
- При неудачном слиянии можно безвозвратно потерять свои незакоммиченные изменения
- Не получится разбить задачу на несколько коммитов, сохранив их рядом друг с другом
Хочу отметить, что если задача состоит из нескольких коммитов и имеет довольно большой срок разработки (больше недели), то следует создать отдельную ветку для реализации и потом слить её с рабочей веткой, чтобы обособить масштабные изменения от других правок.