Статьи

Линейные деревья с Git rebase

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

Тяга против ветвления

Давайте начнем с простого наблюдения. Когда вы клонируете репо и работаете над собственной копией кода, вы ее разветвляете. Даже если на github нет форка с вашим именем: это естественно, и это было сделано с помощью Subversion или CVS.

Pull и push — это действительно замаскированные слияния : ваш мастер отличается от мастера по происхождению: на самом деле это две разные ветви. Вы можете попробовать выполнить git checkout origin / master, чтобы увидеть, как Git концептуально различает удаленные и локальные ветви с одинаковыми именами.

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

Как Git работает за минуту

Вы можете думать о GIT фиксаций , как фотографии , сделанные при выполнении команды; у них также есть один или несколько родительских коммитов , которые в линейном случае являются последним коммитом, сделанным с рабочей копией перед выполнением нового git commit .

Ветви — это просто метки , наложенные на определенные коммиты; метка изменяется при создании новых коммитов в соответствии с последним коммитом. Когда вы переходите, в большинстве случаев вы поддерживаете общего предка с исходной веткой:

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

Так в чем же разница?

Во время слияния создается новый одиночный коммит с двумя родителями: ветвь, с которой вы объединяете, и текущая ветвь.

Во время перебазирования коммиты в вашей текущей ветке применяются последовательно к ветке, в которую вы перебазируете; родитель вашей ветви становится текущим заголовком цели. Это объясняет название: вместо того, чтобы основывать свою ветвь на том, когда вы ее разветвляете, вы основываете ее на ГОЛОВЕ мастера (если вы отошли от мастера).

В обоих случаях обновляется только метка для текущей ветви.

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

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

Возможный рабочий процесс, который использует rebase, следующий:

git checkout -b mybranch  # fork from master
...do some work and some commits...
...meanwhile master goes on with his life and several new commits are made...
git rebase master # your branch is cut out and applied to the more recent version of master
...resolve possible conflicts created by master... # run unit tests for example)
git checkout master && git merge mybranch # immedita, should be a fast-forward)

В происхождении против местной версии, вы заменяете GIT перебазироваться мастер с мерзавца тяговой —rebase .

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

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

При слиянии вы увидите только один автоматически сгенерированный коммит в git log; с rebase плюс merge вы увидите все различные коммиты, так как вторая операция, merge, становится быстрой перемоткой вперед (поднимая метку HEAD master без каких-либо дальнейших коммитов):

 

Конечным результатом является то, что история вашего мастера (или любой другой ветви, в которую вы переходите и объединяетесь) всегда линейна. Вы сможете использовать git-bisect, как умно предложено здесь , и продолжать использовать git log вместо визуализации сложного дерева кода.