Как сделать merge
Перейти к содержимому

Как сделать merge

Git Merge How to Use Git Merge [the Correct Way]

Isolating features into different branches is a crucial practice for any serious developer. By separating each feature, bugfix or working experiment you will avoid a lot of problems and keep your development branches clean.

At some point, a piece of code will reach a state where you’ll want to integrate it with the rest of the project. This is where the git merge command comes in.

Preparing to Merge

Let’s assume that you want to merge branch hotfix into your master branch.

Before you start, how to make sure that you are ready to merge your changes?

  1. Check if your local repository is up to date with the latest changes from your remote server with a git fetch .
  2. Once the fetch is completed git checkout master .
  3. Ensure the master branch has the latest updates by executing git pull .
  4. Checkout to the branch that should receive the changes, in our case that is master.

Merging

Once the preparations are completed, you can start the merge with git merge hotfix command.

Fast Forward Merge

A fast-forward merge can occur when there is a linear path between branches that you want to merge. If a master has not diverged, instead of creating a new commit, it will just point master to the latest commit of the hotfix branch. All commits from hotfix branch are now available in master.

git-merge-fast-forward

However, a fast-forward merge is not possible if the branches have diverged. In this case, you want to use a Three-way merge.

Three-Way Merge

When there is not a linear path to the target branch, Git has no choice but to combine them via a three-way merge. This merge uses an extra commit to tie together the two branches.

git-merge-three-way-merge-1

Test this out! Create your own project with an RSpec test branch and at the same time edit the Controller tests in master. Now, try to merge.

How to Deal With Merge Conflicts

A merge conflict occurs when two branches you’re trying to merge both changed the same part of the same file, Git won’t be able to figure out which version to use.

For example, if the file example.rb was edited on the same lines in different branches of the same Git repository or if the file was deleted, you will get a merge conflict error when you try to merge these branches. Before you can continue, the merge conflict has to be resolved with a new commit.

Merge conflicts will only occur in the event of a 3-way merge.

  1. Generate a list of the files which need to be resolved: git status
  1. When the conflicted line is encountered, Git will edit the content of the affected files with visual indicators that mark both sides of the conflicting content. These visual markers are:
    • <<<<<<< — Conflict marker, the conflict starts after this line.
    • ======= — Divides your changes from the changes in the other branch.
    • >>>>>>> — End of the conflicted lines.
  1. Decide if you want to keep only your hotfix or master changes, or write a completely new code. Delete the conflict markers before merging your changes.
  2. When you’re ready to merge, all you have to do is run git add command on the conflicted files to tell Git they’re resolved.
  3. Commit your changes with git commit to generate the merge commit.

Hope this helped you get a better understanding how to merge your branches and deal with conflicts.

Владеешь merge — освой и rebase

Независимо от используемых в проекте стратегий ветвления, приходится регулярно интегрировать изменения из одной ветки в другую. В 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: пример merge develop в master

Пример того, как смерджить бранч из девелоп-ветки в мастер, с сохранением всех коммитов и истории.

Переключаемся на мастер, потягиваем последние изменения:

Переключаемся на бранч, который будем мерджить в master, в данном примере это LTHS-380_Update_build_deploy_to_compose:

M после чекаута указывает на то, что файл был modified:

  • M = modified
  • A = added
  • D = deleted
  • R = renamed
  • C = copied
  • U = updated but unmerged

Но тут эти изменения не нужны, коммитить их не надо, продолжаем.

Подтягиваем последние изменения в девелоп-бранче:

Тут изменений нет.

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

Тут изменений в мастере не было, потому up to date, идём дальше.

Переключаемся на мастер:

Мерджим в него изменения из девелоп-ветки:

Теперь осталось запушить изменения в удалённый репозиторий:

Теперь соберём всё вместе:

  1. git checkout master // переключаемся на мастер, в который будем делать мердж
  2. git pull // подягиваем последние изменения
  3. git checkout develop // переключаемся на бранч, который будем мерджить в мастер
  4. git pull // подтягиваем последние изменения
  5. git merge master // мерджим мастер в девелоп-бранч, решаем конфиликты, если есть, в девелоп бранче
  6. git checkout master // переключаемся на мастер
  7. git merge -m «merge message» develop // мерджим изменения из девелопа в мастер, можно добавить —no-ff
  8. git push // пушим мастер в репозиторий

Если работа над задачей, для которой создавался бранч, закончена – то можно добавить git тег и удалить бранч.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *