Независимо от используемых в проекте стратегий ветвления, приходится регулярно интегрировать изменения из одной ветки в другую. В git
это можно сделать двумя основными способами: merge
(слияние) и rebase
(перебазирование).
В данной статье мы рассмотрим обе операции и отличия между ними, а также обозначим моменты, требующего особого внимания.
Сначала с помощью анимационных средств разберем каждую операцию по отдельности, а на заключительном этапе проведем параллельное сравнение. Если вам уже знакомы принципы работы этих действий, то сразу переходите к сравнительным характеристикам.
Согласно официальному руководству Git rebase
“повторно применяет коммиты поверх другой базовой ветки”, тогда как merge
“объединяет две или более историй разработки”. Иначе говоря,основное отличие между ними в том, что слияние сохраняет историю в первозданном виде, а перебазирование ее перезаписывает. Прежде чем переходить к более подробному осмыслению принципов их внутренней работы, обратимся к примеру:
Как видно из примера, разработчики Ada и Satoshi изначально создали 2 тематические ветки (feature-1
и feature-2
), происходящие из одного и того же коммита (C1
) на ветке master
. Затем Ada завершила работу с feature-1
, осуществив ее слияние с master
(создав коммит слияния C4
). Теперь у Satoshi есть два способа интегрировать изменения Ada в свою ветку feature-2
— слияние или перебазирование.
Слияние
Начнем с самого распространенного рабочего процесса интеграции изменений: слияния. Перед объединением изменений Ada с feature-2
Satoshi должен сначала обновить свой локальный указатель на master
ветку, поскольку в данный момент она устарела. Как только master
и o/master
синхронизируются, Satoshi сможет включить все изменения в свою тематическую ветку.
Процесс слияния:
После всех изменений в feature-2
Satoshi может продолжить разработку ветки и на заключительном этапе объединить ее с master
.
Ниже представлен окончательный результат слияния. Как видно, история разработки сохраняет все свои этапы — добавляется только коммит слияния C7
.
Перебазирование
Имея в виду процесс слияния, рассмотрим тот же пример, но уже с точки зрения перебазирования. Так же как и в предыдущем случае, перед интеграцией изменений Satoshi должен убедиться, что его локальная и удаленная ветки master
синхронизированы. Но затем вместо обычного слияния, сохраняющего историю в ее поэтапном виде, он может интегрировать все изменения с помощью операции перебазирования, таким образом перезаписывая историю.
Выполняя перебазирование feature-2
относительно master
, Git вернется назад и повторно выполнит коммиты C5
и C6
один за другим прямо поверх C4
, создавая впечатление, что feature-2
изначально была ответвлением конечных изменений Ada.
Процесс перебазирования:
После повторной интеграции всех изменений Satoshi может продолжить работу над своей тематической веткой.
Ниже представлен конечный результат перебазирования. Обратите внимание на повторное выполнение коммитов C5
и C6
поверх C4
, повлекшее за собой перезаписывание истории разработки и полное удаление старых коммитов!
Понимая главное отличие между слиянием и перебазированием, проанализируем конечные результаты этих операций.
Сравнение слияния и перебазирования
Как видим, после слияния две ветки объединились в новом коммите (C7
), придавая нелинейной истории ромбовидную форму и сохраняя ее в неизменном виде. В отличие от этой операции перебазирование привело не к созданию коммита слияния, а к возврату и повторному применению коммитов C5
и C6
поверх C4
, обеспечивая линейность истории. Более детальное изучение этих коммитов позволяет выявить изменения их хешей, подтверждающее факт перезаписи истории в результате перебазирования.
Примечание: каждый раз перебазирование ветки будет сопровождаться созданием новых коммитов, даже если их содержимое останется одним и тем же. Таким образом, прежние коммиты будут в итоге полностью удалены из истории.
С большой силой приходит большая ответственность
Итак, теперь мы знаем, что перебазирование перезаписывает историю, а слияние ее сохраняет. Но что это значит в более широком смысле? Какие возможности и потенциальные недочеты таят в себе две эти операции?
Конфликты при интеграции изменений
Допустим, попытка интегрировать изменения обернулась рядом неприятных конфликтов. Прибегнув к слиянию, вы бы решили их все за раз прямо в коммите C7
. А вот в случае с перебазированием вам бы пришлось решать одни и те же конфликты в каждом коммите (C5
и C6
) по мере их повторного применения.
Трудноразрешимые конфликты говорят о недостатке общения с коллегами ввиду очень длительной работы над одними и теми же файлами.
Опубликованные ветки
Еще одна потенциальная проблема связана с ситуацией, в которой ветка, подлежащая перебазированию, уже удаленно опубликована и положена в основу чьей-либо работы. Тогда такая перебазированная ветка может запутать и усложнить процесс для всех участников, поскольку Git укажет, что она одновременно и отстает, и опережает. В этом случае проблема решается путем извлечения изменений из удаленного репозитория с последующим внедрением в текущий, для чего служит флаг --rebase
(git pull --rebase
).
Кроме того, всякий раз при перебазировании уже опубликованной ветки, независимо от того, основывается ли на ней чья-либо работа, вам по прежнему необходимо принудительно опубликовать ее для внесения обновлений в удаленный сервер, тем самым полностью переписывая текущий указатель.
Потеря данных (как преимущество)
Поскольку слияние сохраняет историю, а перебазирование ее переписывает, то последняя операция может привести к потере данных. При повторном выполнении новых коммитов старые удаляются (после сборки мусора). Именно эта особенность повышает эффективность команды rebase
, позволяющей очистить историю разработки, прежде чем сделать ее общедоступной. А с помощью интерактивного перебазирования можно удалять ненужные коммиты, сжимать изменения или просто обновлять сообщения коммитов.
Главные правила перебазирования
Во избежание связанных с перебазированием проблем рекомендуется придерживаться следующих правил:
- Не перебазируйте ветку, опубликованную удаленно…
- …если только вы не уверены, что кроме вас с ней никто не работает (и что ее принудительная публикация не вызовет проблем).
- Создайте резервную ветку, исходящую из конечной точки ветки, подлежащей перебазированию. Это позволит легко сравнить результат (по завершении) и при необходимости вернуться к состоянию, предшествующему перебазированию.
Усложненные случаи перебазирования
Существует множество усложненных операций перебазирования. К числу наиболее эффективных из них относится ранее упомянутый его интерактивный вариант, позволяющий определить способ повторного выполнения каждого коммита.
Данный режим применяется для разделения, сжатия, перегруппировки и даже полного удаления коммитов, и этим его возможности не ограничиваются.
Заключение
Многие разработчики предпочитают вместо rebase
выполнять merge
, поскольку они уверены, что так не потеряют результаты своей работы. В некотором смысле такой веский аргумент оправдывает отказ от неудобных в работе инструментов. А вот нежелание постичь все преимущества эффективных возможностей, будучи о них осведомленным, оправдать нельзя!
Такой подход равносилен высказыванию: “Хоть у меня и отличная машина, но лучше я ограничусь первой передачей, ведь скоростная езда смертельно опасна”. А почему бы не научиться переключать передачи и безопасно передвигаться на высоких скоростях?!
Мой собственный опыт показал, что знание принципов перебазирования углубляет понимание Git, а также развивает вас как разработчика, особенно если речь идет об управлении исходным кодом.
Как-то в самом начале моей карьеры разработчика я получил один из лучших советов от более опытного коллеги. Звучит он так: “Хватит стучать по клавишам в Source Tree, лучше научись использовать команды Git из терминала! Иначе ты не познаешь все возможности Git, и в перспективе не сможешь программировать автоматические конвейеры.”
С тех пор в качестве визуального средства для просмотра дерева истории я предпочитаю только GitK, а все команды набираю в терминале. И вам рекомендую!
Теперь, понимая разницу между слиянием и перебазированием, вы с большей уверенностью начнете применять обе операции.
Благодарю за внимание и желаю удачи в развитии навыков управления исходным кодом.
Читайте также:
- Продвинутый функционал Git: хитрые приемы и команды
- Поддержание документации в актуальном состоянии с помощью Bit и GitHub
- Как на самом деле работает Git
Читайте нас в Telegram, VK и Дзен
Перевод статьи Alexis Määttä Vinkler: Differences Between Git Merge and Rebase — and Why You Should Care