Введение в Git Merge и Git Rebase: зачем и когда их использовать

Автор оригинала: Vali Shah
Часто у разработчиков возникает выбор между Merge (слияние) и Rebase (перемещение). В Гугле вы увидите разное мнение, многие советуют не использовать Rebase, так как это может вызвать серьезные проблемы. В статье я объясню, что такое слияние и перемещение, почему вы должны (или не должны) использовать их и как это сделать.

image

Git Merge и Git Rebase преследуют одну и ту же цель. Они предназначены для интеграции изменений из одной ветки в другую. Хотя конечная цель одинаковая, принципы работы разные.

Некоторые считают, что вы всегда должны использовать Rebase, другие предпочитают Merge. В этом есть свои плюсы и минусы.

Git Merge


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

  • простота;
  • сохраняет полную историю и хронологический порядок;
  • поддерживает контекст ветки.

Минусы:

  • история коммитов может быть заполнена (загрязнена) множеством коммитов;
  • отладка с использованием git bisect может стать сложнее.

Как это сделать

Слейте ветку master в ветку feature, используя команды checkout и merge.

$ git checkout feature
$ git merge master
(or)
$ git merge master feature

Это создаст новый «Merge commit» в ветке feature, который содержит историю обеих веток.

Git Rebase


Rebase — еще один способ перенести изменения из одной ветки в другую. Rebase сжимает все изменения в один «патч». Затем он интегрирует патч в целевую ветку.

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

image

Плюсы:

  • Упрощает потенциально сложную историю
  • Упрощение манипуляций с единственным коммитом
  • Избежание слияния коммитов в занятых репозиториях и ветках
  • Очищает промежуточные коммиты, делая их одним коммитом, что полезно для DevOps команд

Минусы:

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

Если вы сделаете перемещение неправильно, история изменится, а это может привести к серьезным проблемам, поэтому убедитесь в том, что делаете!

Как это сделать

Переместите ветку feature на главной ветке, используя следующие команды.

$ git checkout feature
$ git rebase master

Это перемещает всю ветку функции в главную ветку. История проекта изменяется, создаются новые коммиты для каждого коммита в основной ветке.

Интерактивное перемещение


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

$ git checkout feature
$ git rebase -i master

Это откроет редактор, перечислив все коммиты, которые будут перемещены.

pick 22d6d7c Commit message#1
pick 44e8a9b Commit message#2
pick 79f1d2h Commit message#3

Это точно определяет, как будет выглядеть ветка после выполнения перемещения. Упорядочивая объекты, вы можете сделать историю такой, как захотите. Вы можете использовать команды fixup, squash, edit, и так далее.

image

Какой из них использовать?


Так что же лучше? Что рекомендуют эксперты?

Трудно принять единственно правильное решение о том, что лучше использовать, поскольку все команды разные. Всё зависит от потребностей и традиций внутри команды.

Принимайте решения на основании компетенции команды в Git. Для вас важна простота или перезаписывание истории, а может быть что-то другое?

Что рекомендую я?

По мере роста команды становится сложно управлять или отслеживать изменения в разработке, применяя слияние. Чтобы иметь чистую и понятную историю коммитов, разумно использовать Rebase.

Преимущества Rebase:

  • Вы разрабатываете локально: если вы не делились своей работой с кем-либо еще. На данный момент вы должны предпочесть перемещение слиянию, чтобы сохранить свою историю в порядке. Если у вас есть личная вилка репозитория, которая не используется совместно с другими разработчиками, вы можете делать rebase даже после того, как переместились в свою ветку.
  • Ваш код готов к ревью: вы создали пулл реквест. Другие анализируют вашу работу и потенциально стягивают ее к своей вилке для локального ревью. На данный момент вы не должны перемещать свою работу. Вы должны создать коммит «переделать» и обновить ветку. Это помогает отслеживать запросы на пулл реквест и предотвращает случайную поломку истории.
  • Ревью сделано и готово к интеграции в целевую ветку. Поздравляем! Вы собираетесь удалить свою ветку feature. Учитывая, что с этого момента другие разработчики не будут fetch-merging эти изменения, это ваш шанс изменить вашу историю. На этом этапе вы можете переписать историю и сбросить оригинальные коммиты, и эти надоедливые «переделки» и «слияние» сливаются в небольшой набор целенаправленных коммитов. Создание явного слияния для этих коммитов является необязательным, но имеет значение. Он записывает, когда функция достигла master.

Теперь вы знаете хоть и незначительную, но разницу между Merge и Rebase. Уверен, вы примете правильное решение и будете использовать то, что подходит именно вам.

Не забывайте:

code = coffee + developer
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 17

    +4
    поэтому убедитесь в том, что делаете!

    Ммм, что это означает?
      –20
      Rebase — это то что нельзя делать.
        +13
        Статья ни о чём — rebase (интерактивный) можно и нужно использовать для наведения порядка (собрать коммиты в осмысленные и законченные коммиты) в своей ветке перед мерджем как бы он ни выполнялся, также rebase разумно использовать для синхронизации своего форка/ветки с главной веткой чтобы не иметь мусора про мерджи в истории.
        А вот мердж в мастер уже скорее стоить делать именно merge'ем, во всяком случае если вы не гуру гита.
          –1
          Из-за стремительного уменьшения относительной доли гуру гита среди пользователей гита уже давно набирает популярность squash merge, когда в master ваша ветка всегда попадает в виде одного коммита.
            0
            А чем адепты squash merge аргументируют свой подход? Типа раз никто не следит за своей историей коммитов, то вместо наведения порядка тупо «округлим» её до коммита на фичу?
              +2
              некоторые contribution считают под количеству коммитов, поэтому 1 фича — 1 коммит. что в целом не так-то уж и плохо
                +2

                Я не то, чтобы адепт, но плюсы есть:


                • Стимулирует делать в одной ветке одну задачу.
                • При следовании спеке Conventional Commits получаем чистые и полезные описания всех коммитов в master, при этом над описаниями коммитов в фиче-бранчах можно не париться (ибо зачастую их в принципе невозможно контролировать, напр. когда получаешь сторонний пул-реквест на гитхабе).
                • Упрощает revert при проблемах.
                • Упрощает bisect.

                А вот явных минусов особо не видно. Да, теряется пошаговая история как кто-то пилил фичу и лажал в процессе — ценность этой истории после мержа фичи обычно нулевая. Если будет очень надо — в течении месяца её можно будет ручками восстановить из reflog.

                  +2

                  Да, типа того.


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


                  Это может бесить людей, которые заморачиваются с разбиением на логические куски, с нормальными описаниями, возможностью сделать bisect и revert… — когда вся эта красота выбрасывается squash. Но когда твой средний пулл-реквест выглядит так — и люди искренне не понимают, что в этом плохого, так как единицей ревью и работы является пулл-реквест, а не коммит — уж лучше squash, чем эти сообщения сохранять в истории.


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

                  +1
                  Это отличный способ если мерджатся изменения которые имеет смысл иметь в виде одного коммита.
                +7
                Rebase — еще один способ перенести изменения из одной ветки в другую. Rebase сжимает все изменения в один «патч». Затем он интегрирует патч в целевую ветку.

                Rebase не изменяет целевую ветку, он «переигрывает» изменения из текущей ветки на вершине целевой ветки, оставаясь в текущей ветке. Для интеграции изменений вам все равно прийдется сделать merge. Однако поскольку в целевой ветке более не будет изменений, сделанных после точки отбранчевания, мердж будет проведен как fast forward, что означает перенесение маркера вершины целевой ветки на конец текущей ветки без merge-комита.

                Я понимаю, что возможно, я придираюсь к словам, и в результате происходит ровно то, что вы и описали. Но эти неточности в понимании тонкостей работы git только вредят. И лишний раз приводят к спорам, что лучше, merge или rebase, хотя это вообще в принципе разные функции!
                  +1
                  Да, это описание гораздо лучше, чем то, что в статье.
                    0

                    На мой взгляд rebase очень удобен только при работе в своей feature ветке для выравнивания с общей (develop) веткой. С shared ветками довольно проблематично, учитывая, что в среднем многие разработчики не очень сильно разбираются в таких тонкостях, проще просто не создавать проблем коллегам и просто использовать merge. Вливание в основную ветку у нас в целом заведено делать через megre с опцией —no-ff.

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

                      Что было бы полезно — сделать какую-то основательную статью с анализом всех популярных подходов к git flow и их подводных камней. В частности, в реалиях наличия ci/cd (когда мы хотим недоделанный код катить и сразу видеть результат его выполнения, кстати, ребейз в этом случае чреват ещё дополнительными рассинхронами с теми же средствами сборки и хранения артефактов)

                      За перевод спасибо, каких-то сильных ляпов в нем не нашел, но особо и не вчитывался.
                        +3
                        Rebase и merge — не одно и то же, и после rebase вам все равно придётся делать merge. Так что сама постановка вопроса является некорректной.
                          0
                          Добавлю, что в случае rebase, конфликтов приходится устранять больше, так как это по сути последовательность cherry-pick-ов, где конфликт может быть на каждом шаге. Тогда как в случае merge — мы устраняем только реальные конфликты на единственном коммите. Несколько дней назад я опубликовал статью, где описал метод, как можно упростить конфликты при rebase.
                            0
                            В чём делались картинки для этой статьи? Мне стиль нравится, хотел бы в подобном стиле сделать свои графики

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

                            Самое читаемое